cubx-dependency-resolver
Version:
Npm package to resolve the dependencies of a list of artifacts
1,051 lines (1,018 loc) • 63 kB
JavaScript
/* globals describe, beforeEach, expect, it, __dirname, sinon */
/* eslint no-unused-expressions: "off" */
(function () {
'use strict';
var DependencyTree = require('../../lib/DependencyTree');
var DepReference = require('../../lib/DepReference');
describe('DependencyTree', function () {
var depTree;
var rootNode1;
var rootNode2;
var childA;
var childB;
var childC;
beforeEach(function () {
/**
* init tree and put some nodes in it. Following tree will be created:
*
* rootNode1 rootNode2
* | / \
* | / \
* childC childA childB
*/
depTree = new DependencyTree();
rootNode1 = new DependencyTree.Node();
rootNode1.data = {prop1: 'test', prop2: 1234};
childC = new DependencyTree.Node();
childC.parent = rootNode1;
rootNode1.children = [childC];
rootNode2 = new DependencyTree.Node();
rootNode2.data = {prop1: 'test2', prop2: 4321};
childA = new DependencyTree.Node();
childA.parent = rootNode2;
childB = new DependencyTree.Node();
childB.parent = rootNode2;
rootNode2.children = [childA, childB];
depTree._rootNodes = [rootNode1, rootNode2];
});
describe('#insertNode()', function () {
it('should return the inserted DependencyTree.Node instance', function () {
var node = new DependencyTree.Node();
node.data = {testData: 'testData'};
expect(depTree.insertNode(node)).to.equal(node);
});
it('should append given node to rootNodes array if neither parent nor before parameter is given.', function () {
var node = new DependencyTree.Node();
node.data = {testData: 'testData'};
depTree.insertNode(node);
depTree._rootNodes.should.have.lengthOf(3);
depTree._rootNodes[2].should.be.equal(node);
});
it('should insert given node to parents children array if parent and before parameter are given.', function () {
var node = new DependencyTree.Node();
node.data = {testData: 'testData'};
depTree.insertNode(node, rootNode2, childB);
rootNode2.children.should.have.lengthOf(3);
rootNode2.children[1].should.equal(node);
node.parent.should.be.equal(rootNode2);
});
it('should insert given node to rootNodes array as left neighbour of given before node if no parent is given.', function () {
var node = new DependencyTree.Node();
node.data = {testData: 'testData'};
depTree.insertNode(node, null, rootNode2);
expect(node.parent).to.be.null;
depTree._rootNodes.should.have.lengthOf(3);
depTree._rootNodes[0].should.be.equal(rootNode1);
depTree._rootNodes[1].should.be.equal(node);
depTree._rootNodes[2].should.be.equal(rootNode2);
});
});
describe('#removeNode()', function () {
it('should remove given node and all of it\'s descendants from tree', function () {
depTree.removeNode(rootNode2);
depTree._rootNodes.should.have.length(1);
depTree._rootNodes[0].should.equal(rootNode1);
});
it('should return null if node to be removed could not be found in tree', function () {
var node = depTree.removeNode(new DependencyTree.Node());
expect(node).to.be.null;
});
it('should return the removed node', function () {
var node = depTree.removeNode(childA);
expect(node).to.eql(childA);
});
it('should remove given node from usesExisting array of all nodes inside given nodes usedBy array', function () {
childA.usesExisting = [childC];
childC.usedBy = [childA];
depTree.removeNode(childC);
childA.usesExisting.should.have.lengthOf(0);
});
it('should log an error if given parameter is not a DependencyTree.Node instance', function () {
var spy = sinon.spy(console, 'error');
depTree.removeNode({});
expect(spy.calledOnce);
spy.restore();
});
});
describe('#traverseDF()', function () {
it('should traverse the tree in depth first pre-order and call the given callback with each visited node', function () {
var callbackStub = sinon.stub();
callbackStub.returns(true);
depTree.traverseDF(callbackStub);
expect(callbackStub.getCall(0).calledWith(rootNode1)).to.be.true;
expect(callbackStub.getCall(1).calledWith(childC)).to.be.true;
expect(callbackStub.getCall(2).calledWith(rootNode2)).to.be.true;
expect(callbackStub.getCall(3).calledWith(childA)).to.be.true;
expect(callbackStub.getCall(4).calledWith(childB)).to.be.true;
});
it('should break traversal if callback returns false', function () {
var callbackStub = sinon.stub();
callbackStub.onThirdCall().returns(false);
callbackStub.returns(true);
depTree.traverseDF(callbackStub);
expect(callbackStub.getCall(0).calledWith(rootNode1)).to.be.true;
expect(callbackStub.getCall(1).calledWith(childC)).to.be.true;
expect(callbackStub.getCall(2).calledWith(rootNode2)).to.be.true;
expect(callbackStub.callCount).to.equal(3);
});
it('should log an error if parameter is not of type function', function () {
var consoleStub = sinon.stub(console, 'error');
depTree.traverseDF('foo');
expect(consoleStub.called).to.be.true;
consoleStub.restore();
});
});
describe('#traverseBF()', function () {
it('should traverse the tree in breadth first order and call the given callback with each visited node', function () {
var callbackStub = sinon.stub();
callbackStub.returns(true);
depTree.traverseBF(callbackStub);
expect(callbackStub.getCall(0).calledWith(rootNode1)).to.be.true;
expect(callbackStub.getCall(1).calledWith(rootNode2)).to.be.true;
expect(callbackStub.getCall(2).calledWith(childC)).to.be.true;
expect(callbackStub.getCall(3).calledWith(childA)).to.be.true;
expect(callbackStub.getCall(4).calledWith(childB)).to.be.true;
expect(callbackStub.callCount).to.equal(5);
});
it('should break traversal if callback returns false', function () {
var callbackStub = sinon.stub();
callbackStub.onThirdCall().returns(false);
callbackStub.returns(true);
depTree.traverseBF(callbackStub);
expect(callbackStub.getCall(0).calledWith(rootNode1)).to.be.true;
expect(callbackStub.getCall(1).calledWith(rootNode2)).to.be.true;
expect(callbackStub.getCall(2).calledWith(childC)).to.be.true;
expect(callbackStub.callCount).to.equal(3);
});
it('should log an error if parameter is not of type function', function () {
var consoleStub = sinon.stub(console, 'error');
depTree.traverseBF('foo');
expect(consoleStub.called).to.be.true;
consoleStub.restore();
});
});
describe('#traverseSubtreeBF()', function () {
it('should traverse subtree starting from given node in breadth first order and call callback for each visited node', function () {
var callbackStub = sinon.stub();
callbackStub.returns(true);
depTree.traverseSubtreeBF(rootNode2, callbackStub);
expect(callbackStub.getCall(0).calledWith(rootNode2)).to.be.true;
expect(callbackStub.getCall(1).calledWith(childA)).to.be.true;
expect(callbackStub.getCall(2).calledWith(childB)).to.be.true;
expect(callbackStub.callCount).to.equal(3);
});
it('should log an error if first parameter is not of type DependencyTree.Node', function () {
var consoleStub = sinon.stub(console, 'error');
depTree.traverseSubtreeBF('foo', function () {});
expect(consoleStub.called).to.be.true;
consoleStub.restore();
});
it('should log an error if second paramter is not of type function', function () {
var consoleStub = sinon.stub(console, 'error');
depTree.traverseSubtreeBF(rootNode2, 'foo');
expect(consoleStub.called).to.be.true;
consoleStub.restore();
});
});
describe('#contains()', function () {
it('should return true if given node is member of the DependencyTree', function () {
expect(depTree.contains(childA)).to.be.true;
});
it('should return false if given node is not member of the DependencyTree', function () {
var node = new DependencyTree.Node();
expect(depTree.contains(node)).to.be.false;
});
});
describe('#toJSON()', function () {
it('should return an object describing the dependency tree as JSON object', function () {
rootNode1.data = new DepReference({webpackageId: 'com.example.package1@1.0', artifactId: 'comp-1', referrer: null});
childC.data = new DepReference({webpackageId: 'com.example.packageC@1.0', artifactId: 'comp-c', referrer: null});
rootNode2.data = new DepReference({webpackageId: 'com.example.package2@1.0', artifactId: 'comp-2', referrer: null});
childA.data = new DepReference({webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a', referrer: null});
childB.data = new DepReference({webpackageId: 'com.example.packageB@1.0', artifactId: 'comp-b', referrer: null});
expect(depTree.toJSON()).to.deep.equal({
rootNodes: [
{
webpackageId: 'com.example.package1@1.0',
artifactId: 'comp-1',
children: [
{
webpackageId: 'com.example.packageC@1.0',
artifactId: 'comp-c',
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.package2@1.0',
artifactId: 'comp-2',
children: [
{
webpackageId: 'com.example.packageA@1.0',
artifactId: 'comp-a',
children: [],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageB@1.0',
artifactId: 'comp-b',
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
]
});
});
it('should include the \'resources\' property on nodes of the JSON object', function () {
rootNode1.data = new DepReference({webpackageId: 'com.example.package1@1.0', artifactId: 'comp-1', referrer: null});
childC.data = new DepReference({webpackageId: 'com.example.packageC@1.0', artifactId: 'comp-c', referrer: null});
childC.data.resources = ['index.html'];
rootNode2.data = new DepReference({webpackageId: 'com.example.package2@1.0', artifactId: 'comp-2', referrer: null});
childA.data = new DepReference({webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a', referrer: null});
childA.data.resources = ['js/main.js', 'css/style.css'];
childB.data = new DepReference({webpackageId: 'com.example.packageB@1.0', artifactId: 'comp-b', referrer: null});
expect(depTree.toJSON(true)).to.deep.equal({
rootNodes: [
{
webpackageId: 'com.example.package1@1.0',
artifactId: 'comp-1',
resources: [],
children: [
{
webpackageId: 'com.example.packageC@1.0',
artifactId: 'comp-c',
resources: ['index.html'],
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.package2@1.0',
artifactId: 'comp-2',
resources: [],
children: [
{
webpackageId: 'com.example.packageA@1.0',
artifactId: 'comp-a',
resources: ['js/main.js', 'css/style.css'],
children: [],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageB@1.0',
artifactId: 'comp-b',
resources: [],
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
]
});
});
it('should assign correct values to \'usesExisting\' and \'usedBy\' properties', function () {
rootNode1.data = new DepReference({webpackageId: 'com.example.package1@1.0', artifactId: 'comp-1', referrer: null});
childC.data = new DepReference({webpackageId: 'com.example.packageC@1.0', artifactId: 'comp-c', referrer: null});
rootNode2.data = new DepReference({webpackageId: 'com.example.package2@1.0', artifactId: 'comp-2', referrer: null});
childA.data = new DepReference({webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a', referrer: null});
childB.data = new DepReference({webpackageId: 'com.example.packageB@1.0', artifactId: 'comp-b', referrer: null});
var childD = new DependencyTree.Node();
childD.data = new DepReference({webpackageId: 'com.example.packageD@1.0', artifactId: 'comp-d', referrer: {webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a'}});
var childD2 = new DependencyTree.Node();
childD2.data = new DepReference({webpackageId: 'com.example.packageD@1.0', artifactId: 'comp-d', referrer: {webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a'}});
depTree.insertNode(childD, childC);
depTree.insertNode(childD2, childB);
depTree.removeDuplicates();
expect(depTree.toJSON()).to.deep.equal({
rootNodes: [
{
webpackageId: 'com.example.package1@1.0',
artifactId: 'comp-1',
children: [
{
webpackageId: 'com.example.packageC@1.0',
artifactId: 'comp-c',
children: [
{
webpackageId: 'com.example.packageD@1.0',
artifactId: 'comp-d',
children: [],
usesExisting: [],
usedBy: [
{
webpackageId: 'com.example.packageB@1.0',
artifactId: 'comp-b'
}
],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.package2@1.0',
artifactId: 'comp-2',
children: [
{
webpackageId: 'com.example.packageA@1.0',
artifactId: 'comp-a',
children: [],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageB@1.0',
artifactId: 'comp-b',
children: [],
usesExisting: [
{
webpackageId: 'com.example.packageD@1.0',
artifactId: 'comp-d'
}
],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
]
});
});
});
describe('#clone()', function () {
var clonedTree;
beforeEach(function () {
rootNode1.data = new DepReference({webpackageId: 'com.example.package1@1.0', artifactId: 'comp-1', referrer: null});
childC.data = new DepReference({webpackageId: 'com.example.packageC@1.0', artifactId: 'comp-c', referrer: null});
rootNode2.data = new DepReference({webpackageId: 'com.example.package2@1.0', artifactId: 'comp-2', referrer: null});
childA.data = new DepReference({webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a', referrer: null});
childB.data = new DepReference({webpackageId: 'com.example.packageB@1.0', artifactId: 'comp-b', referrer: null});
var childD = new DependencyTree.Node();
childD.data = new DepReference({webpackageId: 'com.example.packageD@1.0', artifactId: 'comp-d', referrer: {webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a'}});
var childD2 = new DependencyTree.Node();
childD2.data = new DepReference({webpackageId: 'com.example.packageD@1.0', artifactId: 'comp-d', referrer: {webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a'}});
depTree.insertNode(childD, childC);
depTree.insertNode(childD2, childB);
clonedTree = depTree.clone();
console.log(clonedTree);
});
it('cloned tree should be an instance of \'DependencyTree\'', function () {
expect(clonedTree instanceof DependencyTree).to.be.true;
});
it('cloned and original tree should be deep equal', function () {
expect(clonedTree).to.deep.equal(depTree);
});
});
});
describe('DependencyTree.Node', function () {
var depTree;
var rootNode1;
var rootNode2;
var childA;
var childB;
var childC;
var childD;
var childE;
var childF;
var childG;
var childH;
beforeEach(function () {
/**
* init tree and put some nodes in it. Following tree will be created:
*
* rootNode1 rootNode2
* | / \
* | / \
* childC childA childB
* / \ | / \
* / \ | / \
* childD childE childF childG childH
*/
depTree = new DependencyTree();
rootNode1 = new DependencyTree.Node();
rootNode1.data = {prop1: 'test', prop2: 1234};
childC = new DependencyTree.Node();
childC.parent = rootNode1;
rootNode1.children = [childC];
rootNode2 = new DependencyTree.Node();
rootNode2.data = {prop1: 'test2', prop2: 4321};
childA = new DependencyTree.Node();
childA.parent = rootNode2;
childB = new DependencyTree.Node();
childB.parent = rootNode2;
rootNode2.children = [childA, childB];
depTree._rootNodes = [rootNode1, rootNode2];
childD = new DependencyTree.Node();
childD.parent = childC;
childE = new DependencyTree.Node();
childE.parent = childC;
childC.children = [childD, childE];
childF = new DependencyTree.Node();
childF.parent = childA;
childA.children = [childF];
childG = new DependencyTree.Node();
childG.parent = childB;
childH = new DependencyTree.Node();
childH.parent = childB;
childB.children = [childG, childH];
});
describe('#equalsArtifcat()', function () {
it('should return true if given node references same artifact (based on artifactId and webpackageId)', function () {
childA.data = new DepReference({webpackageId: 'pkgA', artifactId: 'artifactA', referrer: null});
childB.data = new DepReference({webpackageId: 'pkgA', artifactId: 'artifactA', referrer: null});
expect(childA.equalsArtifact(childB)).to.be.true;
});
it('should return false if given node references a different artifact', function () {
childA.data = new DepReference({webpackageId: 'pkgA', artifactId: 'artifactA', referrer: null});
childB.data = new DepReference({webpackageId: 'pkgB', artifactId: 'artifactB', referrer: null});
expect(childA.equalsArtifact(childB)).to.be.false;
});
});
describe('#getPathAsString()', function () {
it('should return a string containing the path from root down to node using [webpackageId]/[artifactId] as node names', function () {
rootNode1.data = new DepReference({webpackageId: 'pkgA', artifactId: 'artifactA', referrer: null});
childC.data = new DepReference({webpackageId: 'pkgC', artifactId: 'artifactC', referrer: null});
childD.data = new DepReference({webpackageId: 'pkgD', artifactId: 'artifactD', referrer: null});
var path = childD.getPathAsString();
path.should.equal('pkgA/artifactA > pkgC/artifactC > pkgD/artifactD');
});
});
describe('#isDescendantOf()', function () {
beforeEach(function () {
childA.usesExisting = [childC];
childC.usedBy = [childA];
});
it('should return true if node is a descendant of given node checking also paths for nodes in usedBy array', function () {
expect(childD.isDescendantOf(rootNode1)).to.be.true;
expect(childD.isDescendantOf(rootNode2)).to.be.true;
expect(childC.isDescendantOf(childA)).to.be.true;
expect(childC.isDescendantOf(rootNode2)).to.be.true;
expect(childF.isDescendantOf(rootNode1)).to.be.false;
});
});
describe('#isAncestorOf()', function () {
beforeEach(function () {
childF.usesExisting = [childC];
childC.usedBy = [childF];
});
it('should return true if node is an ancestor of given node checking also paths defined by usesExisting array', function () {
expect(childF.isAncestorOf(childD)).to.be.true;
expect(rootNode1.isAncestorOf(childD)).to.be.true;
expect(rootNode1.isAncestorOf(childF)).to.be.false;
expect(rootNode2.isAncestorOf(childF)).to.be.true;
expect(rootNode2.isAncestorOf(childE)).to.be.true;
});
});
describe('#toJSON()', function () {
it('should return an object describing the node as JSON object', function () {
rootNode2.data = new DepReference({webpackageId: 'com.example.package2@1.0', artifactId: 'comp-2', referrer: null});
childA.data = new DepReference({webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a', referrer: null});
childB.data = new DepReference({webpackageId: 'com.example.packageB@1.0', artifactId: 'comp-b', referrer: null});
childF.data = new DepReference({webpackageId: 'com.example.packageF@1.0', artifactId: 'comp-f', referrer: null});
childG.data = new DepReference({webpackageId: 'com.example.packageG@1.0', artifactId: 'comp-g', referrer: null});
childH.data = new DepReference({webpackageId: 'com.example.packageH@1.0', artifactId: 'comp-h', referrer: null});
expect(rootNode2.toJSON()).to.deep.equal(
{
webpackageId: 'com.example.package2@1.0',
artifactId: 'comp-2',
children: [
{
webpackageId: 'com.example.packageA@1.0',
artifactId: 'comp-a',
children: [
{
webpackageId: 'com.example.packageF@1.0',
artifactId: 'comp-f',
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageB@1.0',
artifactId: 'comp-b',
children: [
{
webpackageId: 'com.example.packageG@1.0',
artifactId: 'comp-g',
children: [],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageH@1.0',
artifactId: 'comp-h',
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
);
});
it('should include resources property in the JSON object', function () {
rootNode2.data = new DepReference({webpackageId: 'com.example.package2@1.0', artifactId: 'comp-2', referrer: null});
childA.data = new DepReference({webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a', referrer: null});
childA.data.resources = ['js/main.js', 'css/style.css'];
childB.data = new DepReference({webpackageId: 'com.example.packageB@1.0', artifactId: 'comp-b', referrer: null});
childB.data.resources = ['index.html'];
childF.data = new DepReference({webpackageId: 'com.example.packageF@1.0', artifactId: 'comp-f', referrer: null});
childF.data.resources = ['index.html'];
childG.data = new DepReference({webpackageId: 'com.example.packageG@1.0', artifactId: 'comp-g', referrer: null});
childH.data = new DepReference({webpackageId: 'com.example.packageH@1.0', artifactId: 'comp-h', referrer: null});
expect(rootNode2.toJSON(true)).to.deep.equal(
{
webpackageId: 'com.example.package2@1.0',
artifactId: 'comp-2',
resources: [],
children: [
{
webpackageId: 'com.example.packageA@1.0',
artifactId: 'comp-a',
resources: ['js/main.js', 'css/style.css'],
children: [
{
webpackageId: 'com.example.packageF@1.0',
artifactId: 'comp-f',
resources: ['index.html'],
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageB@1.0',
artifactId: 'comp-b',
resources: ['index.html'],
children: [
{
webpackageId: 'com.example.packageG@1.0',
artifactId: 'comp-g',
resources: [],
children: [],
usesExisting: [],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageH@1.0',
artifactId: 'comp-h',
resources: [],
children: [],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
);
});
it('should assign correct values to \'usesExisting\' and \'usedBy\' properties', function () {
rootNode2.data = new DepReference({webpackageId: 'com.example.package2@1.0', artifactId: 'comp-2', referrer: null});
childA.data = new DepReference({webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a', referrer: null});
childA.usesExisting = [childH];
childB.data = new DepReference({webpackageId: 'com.example.packageB@1.0', artifactId: 'comp-b', referrer: null});
childF.data = new DepReference({webpackageId: 'com.example.packageF@1.0', artifactId: 'comp-f', referrer: null});
childF.usesExisting = [childG];
childG.data = new DepReference({webpackageId: 'com.example.packageG@1.0', artifactId: 'comp-g', referrer: null});
childG.usedBy = [childF];
childH.data = new DepReference({webpackageId: 'com.example.packageH@1.0', artifactId: 'comp-h', referrer: null});
childH.usedBy = [childA];
expect(rootNode2.toJSON()).to.deep.equal(
{
webpackageId: 'com.example.package2@1.0',
artifactId: 'comp-2',
children: [
{
webpackageId: 'com.example.packageA@1.0',
artifactId: 'comp-a',
children: [
{
webpackageId: 'com.example.packageF@1.0',
artifactId: 'comp-f',
children: [],
usesExisting: [{webpackageId: 'com.example.packageG@1.0', artifactId: 'comp-g'}],
usedBy: [],
excluded: false
}
],
usesExisting: [{webpackageId: 'com.example.packageH@1.0', artifactId: 'comp-h'}],
usedBy: [],
excluded: false
},
{
webpackageId: 'com.example.packageB@1.0',
artifactId: 'comp-b',
children: [
{
webpackageId: 'com.example.packageG@1.0',
artifactId: 'comp-g',
children: [],
usesExisting: [],
usedBy: [{webpackageId: 'com.example.packageF@1.0', artifactId: 'comp-f'}],
excluded: false
},
{
webpackageId: 'com.example.packageH@1.0',
artifactId: 'comp-h',
children: [],
usesExisting: [],
usedBy: [{webpackageId: 'com.example.packageA@1.0', artifactId: 'comp-a'}],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
],
usesExisting: [],
usedBy: [],
excluded: false
}
);
});
});
});
describe('DependencyTree Modification', function () {
var depTree;
var nodeA;
var nodeB;
var childA1;
var childA2;
var childB1;
var childB2;
var childA11;
var childB11;
var childB21;
var childA111;
var childB111;
var packages = {};
beforeEach(function () {
packages = {
pkg1: {webpackageId: 'package1@1.0.0', artifactId: 'util1'},
pkg2: {webpackageId: 'package2@1.0.0', artifactId: 'util2'},
pkg3: {webpackageId: 'package3@1.0.0', artifactId: 'util3'},
pkg4: {webpackageId: 'package4@1.0.0', artifactId: 'util4'},
pkg5: {webpackageId: 'package5@1.0.0', artifactId: 'util5'},
pkg6: {webpackageId: 'package6@1.0.0', artifactId: 'util6'}
};
/**
* build dependency tree that has the following structure:
*
* package1@1.0.0/util1 package2@1.0.0/util2
* / \ / \
* / \ / \
* package3@1.0.0/util3 package4@1.0.0/util4 package3@1.0.0/util3 package5@1.0.0/util5
* | | |
* | | |
* package5@1.0.0/util5 package5@1.0.0/util5 package6@1.0.0/util6
* | |
* | |
* package6@1.0.0/util6 package6@1.0.0/util6
*/
depTree = new DependencyTree();
nodeA = new DependencyTree.Node();
nodeA.data = new DepReference({webpackageId: packages.pkg1.webpackageId, artifactId: packages.pkg1.artifactId, referrer: null});
nodeB = new DependencyTree.Node();
nodeB.data = new DepReference({webpackageId: packages.pkg2.webpackageId, artifactId: packages.pkg2.artifactId, referrer: null});
childA1 = new DependencyTree.Node();
childA1.data = new DepReference({webpackageId: packages.pkg3.webpackageId, artifactId: packages.pkg3.artifactId, referrer: packages.pkg1});
childA2 = new DependencyTree.Node();
childA2.data = new DepReference({webpackageId: packages.pkg4.webpackageId, artifactId: packages.pkg4.artifactId, referrer: packages.pkg1});
childB1 = new DependencyTree.Node();
childB1.data = new DepReference({webpackageId: packages.pkg3.webpackageId, artifactId: packages.pkg3.artifactId, referrer: packages.pkg2});
childB2 = new DependencyTree.Node();
childB2.data = new DepReference({webpackageId: packages.pkg5.webpackageId, artifactId: packages.pkg5.artifactId, referrer: packages.pkg2});
childA11 = new DependencyTree.Node();
childA11.data = new DepReference({webpackageId: packages.pkg5.webpackageId, artifactId: packages.pkg5.artifactId, referrer: packages.pkg3});
childB11 = new DependencyTree.Node();
childB11.data = new DepReference({webpackageId: packages.pkg5.webpackageId, artifactId: packages.pkg5.artifactId, referrer: packages.pkg3});
childB21 = new DependencyTree.Node();
childB21.data = new DepReference({webpackageId: packages.pkg6.webpackageId, artifactId: packages.pkg6.artifactId, referrer: packages.pkg5});
childA111 = new DependencyTree.Node();
childA111.data = new DepReference({webpackageId: packages.pkg6.webpackageId, artifactId: packages.pkg6.artifactId, referrer: packages.pkg5});
childB111 = new DependencyTree.Node();
childB111.data = new DepReference({webpackageId: packages.pkg6.webpackageId, artifactId: packages.pkg6.artifactId, referrer: packages.pkg5});
depTree.insertNode(nodeA);
depTree.insertNode(nodeB);
depTree.insertNode(childA1, nodeA);
depTree.insertNode(childA2, nodeA);
depTree.insertNode(childB1, nodeB);
depTree.insertNode(childB2, nodeB);
depTree.insertNode(childA11, childA1);
depTree.insertNode(childB11, childB1);
depTree.insertNode(childB21, childB2);
depTree.insertNode(childA111, childA11);
depTree.insertNode(childB111, childB11);
});
describe('#_removeDuplicate()', function () {
it('should set excluded value of duplicated node to false if duplicate node has excluded value of false', function () {
// set excluded flag for several nodes
childA1.excluded = true;
childA11.excluded = true;
childA111.excluded = true;
childB1.excluded = false;
depTree._removeDuplicate(childA1, childB1);
childA1.excluded.should.be.false;
});
it('should keep excluded value true of duplicated node if duplicate node has excluded value of true as well', function () {
// set excluded flag for several nodes
childA1.excluded = true;
childA11.excluded = true;
childA111.excluded = true;
childB1.excluded = true;
childB11.excluded = true;
childB111.excluded = true;
depTree._removeDuplicate(childA1, childB1);
childA1.excluded.should.be.true;
});
it('should keep excluded value false of duplicated node if duplicate node has excluded value of false as well', function () {
// set excluded flag for several nodes
childA1.excluded = false;
childB1.excluded = false;
depTree._removeDuplicate(childA1, childB1);
childA1.excluded.should.be.false;
});
it('should keep excluded value false of duplicated node if duplicate node has excluded value of true', function () {
// set excluded flag for several nodes
childA1.excluded = false;
childB1.excluded = true;
childB11.excluded = true;
childB111.excluded = true;
depTree._removeDuplicate(childA1, childB1);
childA1.excluded.should.be.false;
});
it('should only mark nodes as excluded if they are excluded in subtree of duplicated node as well as in ' +
'subtree of duplicate node', function () {
childA11.excluded = true;
childA111.excluded = true;
childB11.excluded = false;
childB111.excluded = true;
depTree._removeDuplicate(childA1, childB1);
childA11.excluded.should.be.false;
childA111.excluded.should.be.true;
});
it('should only mark nodes as excluded if they are excluded in subtree of duplicated node as well as in ' +
'subtree of duplicate node, even if children are in a different order', function () {
// Add subtree, to achieve the following subtree, so that other tests are not broken
/**
* build dependency tree that has the following structure:
*
* package1@1.0.0/util1 package2@1.0.0/util2
* / | \ / \
* / | \ / \
* package3@1.0.0/util3 package4@1.0.0/util4 package3@1.0.0/util3 package3@1.0.0/util3 package5@1.0.0/util5
* | | | |
* | | | |
* package5@1.0.0/util5 package6@1.0.0/util6 package5@1.0.0/util5 package6@1.0.0/util6
* | | |
* | | |
* package6@1.0.0/util6 package5@1.0.0/util5 package6@1.0.0/util6
*/
var childA3;
var childA31;
var childA311;
childA3 = new DependencyTree.Node();
childA3.data = new DepReference({webpackageId: packages.pkg3.webpackageId, artifactId: packages.pkg3.artifactId, referrer: packages.pkg1});
childA31 = new DependencyTree.Node();
childA31.data = new DepReference({webpackageId: packages.pkg6.webpackageId, artifactId: packages.pkg6.artifactId, referrer: packages.pkg3});
childA311 = new DependencyTree.Node();
childA311.data = new DepReference({webpackageId: packages.pkg5.webpackageId, artifactId: packages.pkg5.artifactId, referrer: packages.pkg6});
depTree.insertNode(childA3, nodeA);
depTree.insertNode(childA31, childA3);
depTree.insertNode(childA311, childA31);
// Actual test
childA31.excluded = true;
childA311.excluded = true;
childB11.excluded = false;
childB111.excluded = true;
depTree._removeDuplicate(childA3, childB1);
childA31.excluded.should.be.true;
childA311.excluded.should.be.false;
});
it('should append referrer of removed duplicate node to referrer of duplicated nodes', function () {
depTree._removeDuplicate(childA1, childB1);
childA1.data.referrer.should.eql([ packages.pkg1, packages.pkg2 ]);
});
});
describe('#applyExcludes()', function () {
var childB3;
beforeEach(function () {
/**
* apply some excludes to given tree like follows (excludes in []). Add a child node package4 to invalidate exclude [package4]
*
* package1@1.0.0/util1 [package4] package2@1.0.0/util2 [package5]
* / \ / \ \_______________
* / \ / \ \
* package3@1.0.0/util3 package4@1.0.0/util4 package3@1.0.0/util3 package5@1.0.0/util5 package4@1.0.0/util4
* | [package6] | [package6] |
* | | |
* package5@1.0.0/util5 package5@1.0.0/util5 package6@1.0.0/util6
* | |
* | |
* package6@1.0.0/util6 package6@1.0.0/util6
*/
nodeA.data.dependencyExcludes = [{ webpackageId: 'package4@1.0.0', artifactId: 'util4' }];
childA1.data.dependencyExcludes = [{ webpackageId: 'package6@1.0.0', artifactId: 'util6' }];
nodeB.data.dependencyExcludes = [{ webpackageId: 'package5@1.0.0', artifactId: 'util5' }];
childB1.data.dependenyExcludes = [{ webpackageId: 'package6@1.0.0', artifactId: 'util6' }];
childB3 = new DependencyTree.Node();
childB3.data = new DepReference({webpackageId: packages.pkg4.webpackageId, artifactId: packages.pkg4.artifactId, referrer: packages.pkg2});
depTree.insertNode(childB3, nodeB);
});
it('should mark all excluded Nodes', function () {
depTree.applyExcludes();
nodeA.excluded.should.be.false;
nodeB.excluded.should.be.false;
childA1.excluded.should.be.false;
childA2.excluded.should.be.true;
childB1.excluded.should.be.false;
childB2.excluded.should.be.true;
childB3.excluded.should.be.false;
childA11.excluded.should.be.false;
childA111.excluded.should.be.true;
childB11.excluded.should.be.true;
childB21.excluded.should.be.true;
childB111.excluded.should.be.true;
});
});
describe('#applyGlobalExclude()', function () {
it('should return the DependencyTree itself', function () {
// depTree.applyGlobalExclude('')
});
it('should set exclude value to true for all appearances of given artifact', function () {
depTree.applyGlobalExclude(packages.pkg3.webpackageId, packages.pkg3.artifactId);
childA1.excluded.should.be.true;
childA11.excluded.should.be.true;
childA111.excluded.should.be.true;
childB1.excluded.should.be.true;
childB11.excluded.should.be.true;
childB111.excluded.should.be.true;
// for each other node excluded should be set to false
nodeA.excluded.should.be.false;
nodeB.excluded.should.be.false;
childA2.excluded.should.be.false;
childB2.excluded.should.be.false;
childB21.excluded.should.be.false;
});
});
describe('#removeDuplicates() without conflicts', function () {
it('should return the DependencyTree itself', function () {
expect(depTree.removeDuplicates()).to.be.an.instanceOf(DependencyTree);
});
it('should remove all duplicated nodes from DependencyTree. Only the first one that is found using breadth-first traversal is kept.', function () {
depTree.removeDuplicates();
/**
* Check if cleaned dependency tree has the following structure:
*
* package1@1.0.0/util1 package2@1.0.0/util2
* / \ /
* / \ /
* package3@1.0.0/util3 package4@1.0.0/util4 package5@1.0.0/util5
* |
* |
* package6@1.0.0/util6
*/
depTree._rootNodes.should.be.eql([nodeA, nodeB]);
depTree._rootNodes[0].children.should.be.eql([childA1, childA2]);
depTree._rootNodes[0].children[0].children.should.be.eql([]);
depTree._rootNodes[0].children[1].children.should.be.eql([]);
depTree._rootNodes[1].children.should.be.eql([childB2]);
depTree._rootNodes[1].children[0].children.should.be.eql([childB21]);
});
it('should return DependencyTree which contains each webpackage exactly once', function () {
// packageIds in breadth first order
var packageIds = [
'package1@1.0.0/util1',
'package2@1.0.0/util2',
'package3@1.0.0/util3',
'package4@1.0.0/util4',
'package5@1.0.0/util5',
'package6@1.0.0/util6'
];
depTree.removeDuplicates();
var count = 0;
depTree.traverseBF(function (node) {
expect(packageIds[count]).to.eql(node.data.getId());
count++;
});
count.should.be.eql(6);
});
it('should create correct \'usedBy\' and \'usesExisting\' relations', function () {
depTree.removeDuplicates();
nodeB.usesExisting.should.be.eql([childA1]);
childA1.usedBy.should.be.eql([nodeB]);
childA1.usesExisting.should.be.eql([childB2]);
childB2.usedBy.should.be.eql([childA1]);
});
it('should set excluded value on each remaining node correctly', function () {
/**
* apply some excludes to given tree like follows (excludes in []). Add a child node package4 to invalidate exclude [package4]
*
* package1@1.0.0/util1 [package4] package2@1.0.0/util2 [package5]
* / \ / \ \_______________
* / \ / \ \
* package3@1.0.0/util3 package4@1.0.0/util4 package3@1.0.0/util3 package5@1.0.0/util5 package4@1.0.0/util4
* | [package6] | [package6] |
* | | |
* package5@1.0.0/util5 package5@1.0.0/util5 package6@1.0.0/util6
* | |
* | |
* package6@1.0.0/util6 package6@1.0.0/util6
*/
nodeA.data.dependencyExcludes = [{ webpackageId: 'package4@1.0.0', artifactId: 'util4' }];
childA1.data.dependencyExcludes = [{ webpackageId: 'package6@1.0.0', artifactId: 'util6' }];
nodeB.data.dependencyExcludes = [{ webpackageId: 'package5@1.0.0', artifactId: 'util5' }];
childB1.data.dependenyExcludes = [{ webpackageId: 'package6@1.0.0', artifactId: 'util6' }];
var childB3 = new DependencyTree.Node();
childB3.data = new DepReference({webpackageId: packages.pkg4.webpackageId, artifactId: packages.pkg4.artifactId, referrer: packages.pkg2});
depTree.insertNode(childB3, nodeB);
depTree.applyExcludes();
depTree.removeDuplicates();
nodeA.excluded.should.be.false;
nodeB.excluded.should.be.false;
childA1.excluded.should.be.false;
childA2.excluded.should.be.false;
childB2.excluded.should.be.false;
childB21.excluded.should.be.true;
});
});
describe('#removeExcludes()', function () {
beforeEach(function () {
/**
* mark some nodes as [excluded] in original dependency tree
*
* package1@1.0.0/util1 package2@1.0.0/util2
* / \ / \
* / \ / \
* package3@1.0.0/util3 package4@1.0.0/util4 package3@1.0.0/util3 [package5@1.0.0/util5]
* | | |
* | | |
* [package5@1.0.0/util5]