Skip to content

Commit 0f683ac

Browse files
committed
Add missing file unit tests
1. Test `Program.getMissingFilePaths` 2. Test program structure reuse (i.e. that the appearance of a missing file prevents complete reuse)
1 parent 6d200bf commit 0f683ac

File tree

5 files changed

+138
-2
lines changed

5 files changed

+138
-2
lines changed

Jakefile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ var harnessSources = harnessCoreSources.concat([
138138
"telemetry.ts",
139139
"transform.ts",
140140
"customTransforms.ts",
141+
"programMissingFiles.ts",
141142
].map(function (f) {
142143
return path.join(unittestsDirectory, f);
143144
})).concat([

src/harness/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
"./unittests/transform.ts",
130130
"./unittests/customTransforms.ts",
131131
"./unittests/textChanges.ts",
132-
"./unittests/telemetry.ts"
132+
"./unittests/telemetry.ts",
133+
"./unittests/programMissingFiles.ts"
133134
]
134135
}

src/harness/unittests/cachingInServerLSHost.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ namespace ts {
7575
const rootScriptInfo = projectService.getOrCreateScriptInfo(rootFile, /* openedByClient */ true, /*containingProject*/ undefined);
7676

7777
const project = projectService.createInferredProjectWithRootFileIfNecessary(rootScriptInfo);
78-
project.setCompilerOptions({ module: ts.ModuleKind.AMD } );
78+
project.setCompilerOptions({ module: ts.ModuleKind.AMD, noLib: true } );
7979
return {
8080
project,
8181
rootScriptInfo
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/// <reference path="..\harness.ts" />
2+
3+
namespace ts {
4+
describe("Program.getMissingFilePaths", () => {
5+
6+
const options: CompilerOptions = {
7+
noLib: true,
8+
};
9+
10+
const emptyFileName = "empty.ts";
11+
const emptyFileRelativePath = "./" + emptyFileName;
12+
13+
const emptyFile: Harness.Compiler.TestFile = {
14+
unitName: emptyFileName,
15+
content: ""
16+
};
17+
18+
const referenceFileName = "reference.ts";
19+
const referenceFileRelativePath = "./" + referenceFileName;
20+
21+
const referenceFile: Harness.Compiler.TestFile = {
22+
unitName: referenceFileName,
23+
content:
24+
"/// <reference path=\"d:/imaginary/nonexistent1.ts\"/>\n" + // Absolute
25+
"/// <reference path=\"./nonexistent2.ts\"/>\n" + // Relative
26+
"/// <reference path=\"nonexistent3.ts\"/>\n" + // Unqualified
27+
"/// <reference path=\"nonexistent4\"/>\n" // No extension
28+
};
29+
30+
const testCompilerHost = Harness.Compiler.createCompilerHost(
31+
/*inputFiles*/ [emptyFile, referenceFile],
32+
/*writeFile*/ undefined,
33+
/*scriptTarget*/ undefined,
34+
/*useCaseSensitiveFileNames*/ false,
35+
/*currentDirectory*/ "d:\\pretend\\",
36+
/*newLineKind*/ NewLineKind.LineFeed,
37+
/*libFiles*/ undefined
38+
);
39+
40+
it("handles no missing root files", () => {
41+
const program = createProgram([emptyFileRelativePath], options, testCompilerHost);
42+
const missing = program.getMissingFilePaths();
43+
assert.isDefined(missing);
44+
assert.equal(missing.length, 0);
45+
});
46+
47+
it("handles missing root file", () => {
48+
const program = createProgram(["./nonexistent.ts"], options, testCompilerHost);
49+
const missing = program.getMissingFilePaths();
50+
assert.isDefined(missing);
51+
assert.equal(missing.length, 1);
52+
assert.equal(missing[0].toString(), "d:/pretend/nonexistent.ts"); // Absolute path
53+
});
54+
55+
it("handles multiple missing root files", () => {
56+
const program = createProgram(["./nonexistent0.ts", "./nonexistent1.ts"], options, testCompilerHost);
57+
const missing = program.getMissingFilePaths().sort();
58+
assert.equal(missing.length, 2);
59+
assert.equal(missing[0].toString(), "d:/pretend/nonexistent0.ts");
60+
assert.equal(missing[1].toString(), "d:/pretend/nonexistent1.ts");
61+
});
62+
63+
it("handles a mix of present and missing root files", () => {
64+
const program = createProgram(["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], options, testCompilerHost);
65+
const missing = program.getMissingFilePaths().sort();
66+
assert.equal(missing.length, 2);
67+
assert.equal(missing[0].toString(), "d:/pretend/nonexistent0.ts");
68+
assert.equal(missing[1].toString(), "d:/pretend/nonexistent1.ts");
69+
});
70+
71+
it("handles repeatedly specified root files", () => {
72+
const program = createProgram(["./nonexistent.ts", "./nonexistent.ts"], options, testCompilerHost);
73+
const missing = program.getMissingFilePaths();
74+
assert.isDefined(missing);
75+
assert.equal(missing.length, 1);
76+
assert.equal(missing[0].toString(), "d:/pretend/nonexistent.ts");
77+
});
78+
79+
it("normalizes file paths", () => {
80+
const program0 = createProgram(["./nonexistent.ts", "./NONEXISTENT.ts"], options, testCompilerHost);
81+
const program1 = createProgram(["./NONEXISTENT.ts", "./nonexistent.ts"], options, testCompilerHost);
82+
const missing0 = program0.getMissingFilePaths();
83+
const missing1 = program1.getMissingFilePaths();
84+
assert.equal(missing0.length, 1);
85+
assert.deepEqual(missing0, missing1);
86+
});
87+
88+
it("handles missing triple slash references", () => {
89+
const program = createProgram([referenceFileRelativePath], options, testCompilerHost);
90+
const missing = program.getMissingFilePaths().sort();
91+
assert.isDefined(missing);
92+
assert.equal(missing.length, 6);
93+
94+
// From absolute reference
95+
assert.equal(missing[0].toString(), "d:/imaginary/nonexistent1.ts");
96+
97+
// From relative reference
98+
assert.equal(missing[1].toString(), "d:/pretend/nonexistent2.ts");
99+
100+
// From unqualified reference
101+
assert.equal(missing[2].toString(), "d:/pretend/nonexistent3.ts");
102+
103+
// From no-extension reference
104+
assert.equal(missing[3].toString(), "d:/pretend/nonexistent4.d.ts");
105+
assert.equal(missing[4].toString(), "d:/pretend/nonexistent4.ts");
106+
assert.equal(missing[5].toString(), "d:/pretend/nonexistent4.tsx");
107+
});
108+
});
109+
}

src/harness/unittests/reuseProgramStructure.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,31 @@ namespace ts {
316316
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
317317
});
318318

319+
it("succeeds if missing files remain missing", () => {
320+
const options: CompilerOptions = { target, noLib: true };
321+
322+
const program_1 = newProgram(files, ["a.ts"], options);
323+
assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths());
324+
325+
const program_2 = updateProgram(program_1, ["a.ts"], options, noop);
326+
assert.deepEqual(program_1.getMissingFilePaths(), program_2.getMissingFilePaths());
327+
328+
assert.equal(StructureIsReused.Completely, program_1.structureIsReused);
329+
});
330+
331+
it("fails if missing file is created", () => {
332+
const options: CompilerOptions = { target, noLib: true };
333+
334+
const program_1 = newProgram(files, ["a.ts"], options);
335+
assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths());
336+
337+
const newTexts: NamedSourceText[] = files.concat([{ name: "non-existing-file.ts", text: SourceText.New("", "", `var x = 1`) }]);
338+
const program_2 = updateProgram(program_1, ["a.ts"], options, noop, newTexts);
339+
assert.deepEqual(emptyArray, program_2.getMissingFilePaths());
340+
341+
assert.equal(StructureIsReused.SafeModules, program_1.structureIsReused);
342+
});
343+
319344
it("resolution cache follows imports", () => {
320345
(<any>Error).stackTraceLimit = Infinity;
321346

0 commit comments

Comments
 (0)