• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    describe("unittests:: tsbuild - graph-ordering", () => {
3        let host: fakes.SolutionBuilderHost | undefined;
4        const deps: [string, string][] = [
5            ["A", "B"],
6            ["B", "C"],
7            ["A", "C"],
8            ["B", "D"],
9            ["C", "D"],
10            ["C", "E"],
11            ["F", "E"],
12            ["H", "I"],
13            ["I", "J"],
14            ["J", "H"],
15            ["J", "E"]
16        ];
17
18        before(() => {
19            const fs = new vfs.FileSystem(false);
20            host = fakes.SolutionBuilderHost.create(fs);
21            writeProjects(fs, ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"], deps);
22        });
23
24        after(() => {
25            host = undefined;
26        });
27
28        it("orders the graph correctly - specify two roots", () => {
29            checkGraphOrdering(["A", "G"], ["D", "E", "C", "B", "A", "G"]);
30        });
31
32        it("orders the graph correctly - multiple parts of the same graph in various orders", () => {
33            checkGraphOrdering(["A"], ["D", "E", "C", "B", "A"]);
34            checkGraphOrdering(["A", "C", "D"], ["D", "E", "C", "B", "A"]);
35            checkGraphOrdering(["D", "C", "A"], ["D", "E", "C", "B", "A"]);
36        });
37
38        it("orders the graph correctly - other orderings", () => {
39            checkGraphOrdering(["F"], ["E", "F"]);
40            checkGraphOrdering(["E"], ["E"]);
41            checkGraphOrdering(["F", "C", "A"], ["E", "F", "D", "C", "B", "A"]);
42        });
43
44        it("returns circular order", () => {
45            checkGraphOrdering(["H"], ["E", "J", "I", "H"], /*circular*/ true);
46            checkGraphOrdering(["A", "H"], ["D", "E", "C", "B", "A", "J", "I", "H"], /*circular*/ true);
47        });
48
49        function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[], circular?: true) {
50            const builder = createSolutionBuilder(host!, rootNames.map(getProjectFileName), { dry: true, force: false, verbose: false });
51            const buildOrder = builder.getBuildOrder();
52            assert.equal(isCircularBuildOrder(buildOrder), !!circular);
53            const buildQueue = getBuildOrderFromAnyBuildOrder(buildOrder);
54            assert.deepEqual(buildQueue, expectedBuildSet.map(getProjectFileName));
55
56            if (!circular) {
57                for (const dep of deps) {
58                    const child = getProjectFileName(dep[0]);
59                    if (buildQueue.indexOf(child) < 0) continue;
60                    const parent = getProjectFileName(dep[1]);
61                    assert.isAbove(buildQueue.indexOf(child), buildQueue.indexOf(parent), `Expecting child ${child} to be built after parent ${parent}`);
62                }
63            }
64        }
65
66        function getProjectFileName(proj: string) {
67            return `/project/${proj}/tsconfig.json` as ResolvedConfigFileName;
68        }
69
70        function writeProjects(fileSystem: vfs.FileSystem, projectNames: string[], deps: [string, string][]): string[] {
71            const projFileNames: string[] = [];
72            for (const dep of deps) {
73                if (projectNames.indexOf(dep[0]) < 0) throw new Error(`Invalid dependency - project ${dep[0]} does not exist`);
74                if (projectNames.indexOf(dep[1]) < 0) throw new Error(`Invalid dependency - project ${dep[1]} does not exist`);
75            }
76            for (const proj of projectNames) {
77                fileSystem.mkdirpSync(`/project/${proj}`);
78                fileSystem.writeFileSync(`/project/${proj}/${proj}.ts`, "export {}");
79                const configFileName = getProjectFileName(proj);
80                const configContent = JSON.stringify({
81                    compilerOptions: { composite: true },
82                    files: [`./${proj}.ts`],
83                    references: deps.filter(d => d[0] === proj).map(d => ({ path: `../${d[1]}` }))
84                }, undefined, 2);
85                fileSystem.writeFileSync(configFileName, configContent);
86                projFileNames.push(configFileName);
87            }
88            return projFileNames;
89        }
90    });
91}
92