npm/workspaces/arborist/test/tree-check.js

218 lines
5.2 KiB
JavaScript

const t = require('tap')
// turn on debug mode, or this does nothing
const treeCheck = t.mock('../lib/tree-check.js', {
'../lib/debug.js': fn => fn(),
})
const { resolve } = require('path')
const Node = require('../lib/node.js')
const Link = require('../lib/link.js')
const Edge = require('../lib/edge.js')
t.test('basic tree that is a-ok', t => {
const tree = new Node({
path: '/some/path',
pkg: {},
children: [
{ pkg: { name: 'foo', version: '1.2.3' } },
],
})
const link = new Link({
parent: tree,
name: 'glorb',
target: new Node({
fsParent: tree,
path: '/some/path/glorb',
pkg: { name: 'glorb', version: '1.2.3' },
}),
})
link.parent = tree
t.equal(treeCheck(tree), tree)
t.equal(treeCheck(link), link)
t.equal(treeCheck(link.target), link.target)
const nonTree = {}
t.equal(treeCheck(nonTree), nonTree)
nonTree.root = {}
t.equal(treeCheck(nonTree), nonTree)
t.end()
})
t.test('break some stuff', t => {
const tree = new Node({
path: '/some/path',
pkg: {},
children: [
{ pkg: { name: 'foo', version: '1.2.3' } },
{ pkg: { name: 'disowned', version: '1.2.3' } },
],
})
new Link({
parent: tree,
name: 'glorb',
target: new Node({
fsParent: tree,
path: '/some/path/glorb',
pkg: { name: 'glorb', version: '1.2.3' },
}),
})
const disowned = tree.children.get('disowned')
disowned.parent = null
// oops...
Map.prototype.set.call(tree.inventory, 'xyz', disowned)
t.equal(treeCheck(tree, false), tree, 'unreachable allowed')
t.throws(() => treeCheck(tree), {
message: 'unreachable in inventory',
node: resolve('/some/path/node_modules/disowned'),
realpath: resolve('/some/path/node_modules/disowned'),
location: '',
name: 'Error',
log: Array,
})
Map.prototype.delete.call(tree.inventory, 'xyz')
disowned.parent = tree
tree.inventory.delete(disowned)
t.throws(() => treeCheck(tree), {
message: 'not in inventory',
node: resolve('/some/path/node_modules/disowned'),
name: 'Error',
log: Array,
})
disowned.root = null
tree.children.set('wtf', disowned)
t.throws(() => treeCheck(tree), {
message: 'double root',
node: resolve('/some/path/node_modules/disowned'),
realpath: resolve('/some/path/node_modules/disowned'),
tree: tree.path,
name: 'Error',
log: Array,
})
const otherTree = new Node({
name: 'other',
parent: disowned,
})
tree.children.set('wtf', otherTree)
t.throws(() => treeCheck(tree), {
message: 'node from other root in tree',
node: resolve('/some/path/node_modules/disowned/node_modules/other'),
realpath: resolve('/some/path/node_modules/disowned/node_modules/other'),
tree: tree.path,
name: 'Error',
log: Array,
})
tree.children.delete('wtf')
Map.prototype.set.call(otherTree.inventory, 'othertree', disowned)
t.throws(() => treeCheck(otherTree), {
message: 'non-root has non-zero inventory',
node: disowned.path,
tree: otherTree.path,
inventory: [[disowned.path, disowned.location]],
name: 'Error',
log: Array,
})
Map.prototype.delete.call(tree.inventory, 'othertree')
t.end()
})
t.test('just return the tree if not in debug mode', t => {
const treeCheck = t.mock('../lib/tree-check.js', {
'../lib/debug.js': () => {},
})
const tree = new Node({
path: '/some/path',
pkg: {},
children: [
{ pkg: { name: 'foo', version: '1.2.3' } },
{ pkg: { name: 'disowned', version: '1.2.3' } },
],
})
const disowned = tree.children.get('disowned')
disowned.parent = null
// oops...
Map.prototype.set.call(tree.inventory, 'xyz', disowned)
t.equal(treeCheck(tree), tree, 'error suppressed outside of debug mode')
t.end()
})
t.test('tree with dev edges on a nested dep node', t => {
const tree = new Node({
path: '/some/path',
pkg: {},
children: [
{ pkg: { name: 'foo', version: '1.2.3', devDependencies: { x: '' } } },
],
})
// ensure it actually gets added
new Edge({
type: 'dev',
name: 'x',
spec: '',
from: tree.children.get('foo'),
})
t.throws(() => treeCheck(tree), {
message: 'dev edges on non-top node',
node: tree.children.get('foo').path,
tree: tree.path,
root: tree.root.path,
via: tree.path,
viaType: 'children',
devEdges: [['dev', 'x', '', 'MISSING']],
log: Array,
})
t.end()
})
t.test('node with same path as root', t => {
const root = new Node({
path: '/path/to/root',
pkg: {
dependencies: {
foo: '1',
},
},
})
const tree = new Node({
parent: root,
pkg: {
name: 'foo',
version: '1.2.3',
},
})
const child = new Node({
parent: tree,
pkg: {
name: 'not-root',
version: '1.2.3',
},
})
child.path = root.path
t.throws(() => treeCheck(tree), {
message: 'node with same path as root',
node: child.path,
tree: tree.path,
root: root.path,
via: tree.path,
viaType: 'children',
log: Array,
})
child.path = root.path + '/some/where/else'
t.throws(() => treeCheck(tree), {
message: 'non-link with mismatched path/realpath',
node: child.path,
tree: tree.path,
root: root.path,
via: tree.path,
viaType: 'children',
log: Array,
})
t.end()
})