npm/workspaces/arborist/test/inventory.js

139 lines
5.0 KiB
JavaScript

// this test depends on debug stuff, so force it on, even if the test env
// does not enable it.
process.env.ARBORIST_DEBUG = '1'
const Inventory = require('../lib/inventory.js')
const t = require('tap')
t.test('basic operations', t => {
const i = new Inventory()
t.equal(i.primaryKey, 'location')
t.same(i.indexes, ['name', 'license', 'funding', 'realpath', 'packageName'])
// uk spelling
i.add({ location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } })
// old-style multi-license array
i.add({ location: 'y', name: 'x', package: { licenses: [{ type: 'ISC' }], funding: { url: 'foo' } } })
i.add({ location: 'z', name: 'z', package: { license: { type: 'MIT' }, funding: 'bar' } })
i.add({ location: 'a', name: 'a', package: {} })
t.same(i.filter(node => /[xy]/.test(node.name)), [
i.get('x'),
i.get('y'),
], 'filter returns an iterable of all matching nodes')
t.same([...i.query('license')].sort((a, b) => String(a).localeCompare(String(b, 'en'))),
['ISC', 'MIT', undefined])
t.same([...i.query('license', 'MIT')], [
{ location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } },
{ location: 'z', name: 'z', package: { license: { type: 'MIT' }, funding: 'bar' } },
], 'can query by license')
t.same(i.query('license', 'blerg'), new Set(),
'empty query returns empty set')
t.same([...i.query('name', 'x')], [
{ location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } },
{ location: 'y', name: 'x', package: { licenses: [{ type: 'ISC' }], funding: { url: 'foo' } } },
], 'can query by name')
t.same([...i.query('funding')].sort((a, b) => String(a).localeCompare(String(b, 'en'))),
['bar', 'foo', undefined])
t.same([...i.query('funding', 'foo')], [
{ location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } },
{ location: 'y', name: 'x', package: { licenses: [{ type: 'ISC' }], funding: { url: 'foo' } } },
], 'can query by funding url')
const x = i.get('x')
t.same(x, { location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } }, 'get by location')
i.add(x)
t.same(i.get('x'), x, 'adding a second time has no effect')
t.equal(i.has(x), true, 'has a node')
i.add({ location: 'x', name: 'a', package: { licences: [{ type: 'ABC' }] } })
t.same(i.get('x'), { location: 'x', name: 'a', package: { licences: [{ type: 'ABC' }] } },
'new node at same location overwrites')
t.equal(i.has(x), false, 'node has been overwritten')
const a = i.get('a')
t.same([...i.query('license', undefined)], [a], 'can query by missing license')
t.throws(() => i.set('a', 'b'), {
message: 'direct set() not supported, use inventory.add(node)',
})
const y = i.get('y')
i.delete({ location: 'y' })
t.equal(i.get('y'), y, 'deleting other node with same key has no effect')
i.delete(y)
t.equal(i.has(y), false, 'no longer has the y node')
t.equal(i.get('y'), undefined, 'get returns undefined')
// no name or license!
const z = { location: 'z' }
i.add(z)
t.equal(i.get('z'), z, 'can add and retrieve node without secondary keys')
// oops! mutated out of band, that's weird, but shouldn't throw anyway
// though, of course, this makes the secondary indexes incomplete.
// don't do this. but probably not worth making the package immutable.
z.package = { name: 'z' }
t.doesNotThrow(() => i.delete(z), 'doesnt try to delete from nonexistent sets')
t.equal(i.get('z'), undefined, 'node is not here')
t.equal(i.has(z), false, 'i does not have z any more')
t.doesNotThrow(() =>
i.add({
location: 'f',
name: 'f',
package: {
license: 'MIT',
funding: null,
},
}), 'doesnt throw on falsy funding info')
t.doesNotThrow(() =>
i.add({
location: 'l',
name: 'l',
package: {
license: null,
},
}), 'doesnt throw on falsy license info')
// inherited properties and getters are allowed
const n = Object.assign(Object.create({
location: 'n',
get packageName () {
return this.package.name
},
get package () {
return this._pkg
},
}), { _pkg: { name: 'n' } })
i.add(n)
t.equal(i.get('n'), n, 'found by inherited location')
t.same([...i.query('packageName', 'n')], [n], 'found by packageName query')
t.end()
})
t.test('dont allow external nodes to be added to inventory', t => {
const i = new Inventory()
const root = { location: '', path: 'rootpath' }
i.add(root)
t.throws(() => i.add({ root: { path: 'otherroot' }, location: 'adsf', path: 'nodepath' }), {
message: 'adding external node to inventory',
root: 'rootpath',
node: 'nodepath',
nodeRoot: 'otherroot',
})
t.end()
})
t.test('adding external nodes is no-op outside debug mode', t => {
const Inventory = t.mock('../lib/inventory.js', {
'../lib/debug.js': () => {},
})
const i = new Inventory()
const root = { location: '', path: 'rootpath' }
i.add(root)
const other = { root: { path: 'otherroot' }, location: 'adsf', path: 'nodepath' }
i.add(other)
t.equal(i.has(other), false, 'did not add external node to inventory')
t.end()
})