Skip to content

Commit c197bae

Browse files
committed
Add tests for failing redirect reuse of program when host implements getSourceFileByPath
Test for #27207
1 parent 7c87546 commit c197bae

File tree

1 file changed

+64
-63
lines changed

1 file changed

+64
-63
lines changed

src/testRunner/unittests/reuseProgramStructure.ts

Lines changed: 64 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ namespace ts {
104104
return file;
105105
}
106106

107-
export function createTestCompilerHost(texts: ReadonlyArray<NamedSourceText>, target: ScriptTarget, oldProgram?: ProgramWithSourceTexts): TestCompilerHost {
107+
export function createTestCompilerHost(texts: ReadonlyArray<NamedSourceText>, target: ScriptTarget, oldProgram?: ProgramWithSourceTexts, useGetSourceFileByPath?: boolean) {
108108
const files = arrayToMap(texts, t => t.name, t => {
109109
if (oldProgram) {
110110
let oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
@@ -117,55 +117,47 @@ namespace ts {
117117
}
118118
return createSourceFileWithText(t.name, t.text, target);
119119
});
120+
const useCaseSensitiveFileNames = sys && sys.useCaseSensitiveFileNames;
121+
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
122+
const filesByPath = useGetSourceFileByPath ? mapEntries(files, (fileName, file) => [toPath(fileName, "", getCanonicalFileName), file]) : undefined;
120123
const trace: string[] = [];
121-
122-
return {
124+
const result: TestCompilerHost = {
123125
trace: s => trace.push(s),
124126
getTrace: () => trace,
125-
getSourceFile(fileName): SourceFile {
126-
return files.get(fileName)!;
127-
},
128-
getDefaultLibFileName(): string {
129-
return "lib.d.ts";
130-
},
127+
getSourceFile: fileName => files.get(fileName),
128+
getDefaultLibFileName: () => "lib.d.ts",
131129
writeFile: notImplemented,
132-
getCurrentDirectory(): string {
133-
return "";
134-
},
135-
getDirectories(): string[] {
136-
return [];
137-
},
138-
getCanonicalFileName(fileName): string {
139-
return sys && sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
140-
},
141-
useCaseSensitiveFileNames(): boolean {
142-
return sys && sys.useCaseSensitiveFileNames;
143-
},
144-
getNewLine(): string {
145-
return sys ? sys.newLine : newLine;
146-
},
130+
getCurrentDirectory: () => "",
131+
getDirectories: () => [],
132+
getCanonicalFileName,
133+
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
134+
getNewLine: () => sys ? sys.newLine : newLine,
147135
fileExists: fileName => files.has(fileName),
148136
readFile: fileName => {
149137
const file = files.get(fileName);
150138
return file && file.text;
151139
},
152140
};
141+
if (useGetSourceFileByPath) {
142+
result.getSourceFileByPath = (_fileName, path) => filesByPath!.get(path);
143+
}
144+
return result;
153145
}
154146

155-
export function newProgram(texts: NamedSourceText[], rootNames: string[], options: CompilerOptions): ProgramWithSourceTexts {
156-
const host = createTestCompilerHost(texts, options.target!);
147+
export function newProgram(texts: NamedSourceText[], rootNames: string[], options: CompilerOptions, useGetSourceFileByPath?: boolean): ProgramWithSourceTexts {
148+
const host = createTestCompilerHost(texts, options.target!, /*oldProgram*/ undefined, useGetSourceFileByPath);
157149
const program = <ProgramWithSourceTexts>createProgram(rootNames, options, host);
158150
program.sourceTexts = texts;
159151
program.host = host;
160152
return program;
161153
}
162154

163-
export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: ReadonlyArray<string>, options: CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[]) {
155+
export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: ReadonlyArray<string>, options: CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[], useGetSourceFileByPath?: boolean) {
164156
if (!newTexts) {
165157
newTexts = oldProgram.sourceTexts!.slice(0);
166158
}
167159
updater(newTexts);
168-
const host = createTestCompilerHost(newTexts, options.target!, oldProgram);
160+
const host = createTestCompilerHost(newTexts, options.target!, oldProgram, useGetSourceFileByPath);
169161
const program = <ProgramWithSourceTexts>createProgram(rootNames, options, host, oldProgram);
170162
program.sourceTexts = newTexts;
171163
program.host = host;
@@ -809,7 +801,7 @@ namespace ts {
809801
const root = "/a.ts";
810802
const compilerOptions = { target, moduleResolution: ModuleResolutionKind.NodeJs };
811803

812-
function createRedirectProgram(options?: { bText: string, bVersion: string }): ProgramWithSourceTexts {
804+
function createRedirectProgram(useGetSourceFileByPath: boolean, options?: { bText: string, bVersion: string }): ProgramWithSourceTexts {
813805
const files: NamedSourceText[] = [
814806
{
815807
name: "/node_modules/a/index.d.ts",
@@ -841,55 +833,64 @@ namespace ts {
841833
},
842834
];
843835

844-
return newProgram(files, [root], compilerOptions);
836+
return newProgram(files, [root], compilerOptions, useGetSourceFileByPath);
845837
}
846838

847-
function updateRedirectProgram(program: ProgramWithSourceTexts, updater: (files: NamedSourceText[]) => void): ProgramWithSourceTexts {
848-
return updateProgram(program, [root], compilerOptions, updater);
839+
function updateRedirectProgram(program: ProgramWithSourceTexts, updater: (files: NamedSourceText[]) => void, useGetSourceFileByPath: boolean): ProgramWithSourceTexts {
840+
return updateProgram(program, [root], compilerOptions, updater, /*newTexts*/ undefined, useGetSourceFileByPath);
849841
}
850842

851-
it("No changes -> redirect not broken", () => {
852-
const program1 = createRedirectProgram();
843+
function verifyRedirects(useGetSourceFileByPath: boolean) {
844+
it("No changes -> redirect not broken", () => {
845+
const program1 = createRedirectProgram(useGetSourceFileByPath);
853846

854-
const program2 = updateRedirectProgram(program1, files => {
855-
updateProgramText(files, root, "const x = 1;");
847+
const program2 = updateRedirectProgram(program1, files => {
848+
updateProgramText(files, root, "const x = 1;");
849+
}, useGetSourceFileByPath);
850+
assert.equal(program1.structureIsReused, StructureIsReused.Completely);
851+
assert.lengthOf(program2.getSemanticDiagnostics(), 0);
856852
});
857-
assert.equal(program1.structureIsReused, StructureIsReused.Completely);
858-
assert.lengthOf(program2.getSemanticDiagnostics(), 0);
859-
});
860853

861-
it("Target changes -> redirect broken", () => {
862-
const program1 = createRedirectProgram();
863-
assert.lengthOf(program1.getSemanticDiagnostics(), 0);
854+
it("Target changes -> redirect broken", () => {
855+
const program1 = createRedirectProgram(useGetSourceFileByPath);
856+
assert.lengthOf(program1.getSemanticDiagnostics(), 0);
864857

865-
const program2 = updateRedirectProgram(program1, files => {
866-
updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }");
867-
updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }'));
858+
const program2 = updateRedirectProgram(program1, files => {
859+
updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }");
860+
updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }'));
861+
}, useGetSourceFileByPath);
862+
assert.equal(program1.structureIsReused, StructureIsReused.Not);
863+
assert.lengthOf(program2.getSemanticDiagnostics(), 1);
868864
});
869-
assert.equal(program1.structureIsReused, StructureIsReused.Not);
870-
assert.lengthOf(program2.getSemanticDiagnostics(), 1);
871-
});
872865

873-
it("Underlying changes -> redirect broken", () => {
874-
const program1 = createRedirectProgram();
866+
it("Underlying changes -> redirect broken", () => {
867+
const program1 = createRedirectProgram(useGetSourceFileByPath);
875868

876-
const program2 = updateRedirectProgram(program1, files => {
877-
updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }");
878-
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" }));
869+
const program2 = updateRedirectProgram(program1, files => {
870+
updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }");
871+
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" }));
872+
}, useGetSourceFileByPath);
873+
assert.equal(program1.structureIsReused, StructureIsReused.Not);
874+
assert.lengthOf(program2.getSemanticDiagnostics(), 1);
879875
});
880-
assert.equal(program1.structureIsReused, StructureIsReused.Not);
881-
assert.lengthOf(program2.getSemanticDiagnostics(), 1);
882-
});
883876

884-
it("Previously duplicate packages -> program structure not reused", () => {
885-
const program1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" });
877+
it("Previously duplicate packages -> program structure not reused", () => {
878+
const program1 = createRedirectProgram(useGetSourceFileByPath, { bVersion: "1.2.4", bText: "export = class X { private x: number; }" });
886879

887-
const program2 = updateRedirectProgram(program1, files => {
888-
updateProgramText(files, bxIndex, "export default class X { private x: number; }");
889-
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" }));
880+
const program2 = updateRedirectProgram(program1, files => {
881+
updateProgramText(files, bxIndex, "export default class X { private x: number; }");
882+
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" }));
883+
}, useGetSourceFileByPath);
884+
assert.equal(program1.structureIsReused, StructureIsReused.Not);
885+
assert.deepEqual(program2.getSemanticDiagnostics(), []);
890886
});
891-
assert.equal(program1.structureIsReused, StructureIsReused.Not);
892-
assert.deepEqual(program2.getSemanticDiagnostics(), []);
887+
}
888+
889+
describe("when host implements getSourceFile", () => {
890+
verifyRedirects(/*useGetSourceFileByPath*/ false);
891+
});
892+
describe("when host implements getSourceFileByPath", () => {
893+
verifyRedirects(/*useGetSourceFileByPath*/ true);
893894
});
894895
});
895896
});

0 commit comments

Comments
 (0)