Skip to content

Commit e269e70

Browse files
committed
Add test that fails because file is written multiple times
Reported from #33061
1 parent b4417da commit e269e70

File tree

1 file changed

+150
-17
lines changed

1 file changed

+150
-17
lines changed

src/testRunner/unittests/tscWatch/incremental.ts

Lines changed: 150 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ namespace ts.tscWatch {
1616
expectedIncrementalEmit?: ReadonlyArray<File>;
1717
expectedIncrementalErrors?: ReadonlyArray<string>;
1818
}
19-
function verifyIncrementalWatchEmit(input: VerifyIncrementalWatchEmitInput) {
19+
function verifyIncrementalWatchEmit(input: () => VerifyIncrementalWatchEmitInput) {
2020
it("with tsc --w", () => {
2121
verifyIncrementalWatchEmitWorker({
22-
input,
22+
input: input(),
2323
emitAndReportErrors: createWatchOfConfigFile,
2424
verifyErrors: checkOutputErrorsInitial
2525
});
2626
});
2727
it("with tsc", () => {
2828
verifyIncrementalWatchEmitWorker({
29-
input,
29+
input: input(),
3030
emitAndReportErrors: incrementalBuild,
3131
verifyErrors: checkNormalBuildErrors
3232
});
@@ -122,15 +122,15 @@ namespace ts.tscWatch {
122122

123123
function checkFileEmit(actual: Map<string>, expected: ReadonlyArray<File>) {
124124
assert.equal(actual.size, expected.length, `Actual: ${JSON.stringify(arrayFrom(actual.entries()), /*replacer*/ undefined, " ")}\nExpected: ${JSON.stringify(expected, /*replacer*/ undefined, " ")}`);
125-
expected.forEach(file => {
125+
for (const file of expected) {
126126
let expectedContent = file.content;
127127
let actualContent = actual.get(file.path);
128128
if (isBuildInfoFile(file.path)) {
129129
actualContent = actualContent && sanitizeBuildInfo(actualContent);
130130
expectedContent = sanitizeBuildInfo(expectedContent);
131131
}
132132
assert.equal(actualContent, expectedContent, `Emit for ${file.path}`);
133-
});
133+
}
134134
}
135135

136136
const libFileInfo: BuilderState.FileInfo = {
@@ -170,7 +170,7 @@ namespace ts.tscWatch {
170170
describe("own file emit without errors", () => {
171171
function verify(optionsToExtend?: CompilerOptions, expectedBuildinfoOptions?: CompilerOptions) {
172172
const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10");
173-
verifyIncrementalWatchEmit({
173+
verifyIncrementalWatchEmit(() => ({
174174
files: [libFile, file1, file2, configFile],
175175
optionsToExtend,
176176
expectedInitialEmit: [
@@ -226,7 +226,7 @@ namespace ts.tscWatch {
226226
}
227227
],
228228
expectedIncrementalErrors: emptyArray,
229-
});
229+
}));
230230
}
231231
verify();
232232
describe("with commandline parameters that are not relative", () => {
@@ -259,7 +259,7 @@ namespace ts.tscWatch {
259259
"file2.ts(1,7): error TS2322: Type '20' is not assignable to type 'string'.\n"
260260
];
261261
const modifiedFile1Content = file1.content.replace("x", "z");
262-
verifyIncrementalWatchEmit({
262+
verifyIncrementalWatchEmit(() => ({
263263
files: [libFile, file1, fileModified, configFile],
264264
expectedInitialEmit: [
265265
file1Js,
@@ -320,7 +320,7 @@ namespace ts.tscWatch {
320320
}
321321
],
322322
expectedIncrementalErrors: file2Errors,
323-
});
323+
}));
324324
});
325325

326326
describe("with --out", () => {
@@ -332,7 +332,7 @@ namespace ts.tscWatch {
332332
path: `${project}/out.js`,
333333
content: "var x = 10;\nvar y = 20;\n"
334334
};
335-
verifyIncrementalWatchEmit({
335+
verifyIncrementalWatchEmit(() => ({
336336
files: [libFile, file1, file2, config],
337337
expectedInitialEmit: [
338338
outFile,
@@ -353,7 +353,7 @@ namespace ts.tscWatch {
353353
}
354354
],
355355
expectedInitialErrors: emptyArray
356-
});
356+
}));
357357
});
358358

359359
});
@@ -397,7 +397,7 @@ namespace ts.tscWatch {
397397

398398
describe("own file emit without errors", () => {
399399
const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10");
400-
verifyIncrementalWatchEmit({
400+
verifyIncrementalWatchEmit(() => ({
401401
files: [libFile, file1, file2, config],
402402
expectedInitialEmit: [
403403
file1Js,
@@ -451,7 +451,7 @@ namespace ts.tscWatch {
451451
}
452452
],
453453
expectedIncrementalErrors: emptyArray,
454-
});
454+
}));
455455
});
456456

457457
describe("own file emit with errors", () => {
@@ -479,7 +479,7 @@ namespace ts.tscWatch {
479479
"file2.ts(1,14): error TS2322: Type '20' is not assignable to type 'string'.\n"
480480
];
481481
const modifiedFile1Content = file1.content.replace("x = 10", "z = 10");
482-
verifyIncrementalWatchEmit({
482+
verifyIncrementalWatchEmit(() => ({
483483
files: [libFile, file1, fileModified, config],
484484
expectedInitialEmit: [
485485
file1Js,
@@ -541,7 +541,7 @@ namespace ts.tscWatch {
541541
}
542542
],
543543
expectedIncrementalErrors: file2Errors,
544-
});
544+
}));
545545
});
546546

547547
describe("with --out", () => {
@@ -561,7 +561,7 @@ namespace ts.tscWatch {
561561
});
562562
`;
563563
}
564-
verifyIncrementalWatchEmit({
564+
verifyIncrementalWatchEmit(() => ({
565565
files: [libFile, file1, file2, config],
566566
expectedInitialEmit: [
567567
outFile,
@@ -582,7 +582,140 @@ namespace ts.tscWatch {
582582
}
583583
],
584584
expectedInitialErrors: emptyArray
585-
});
585+
}));
586+
});
587+
});
588+
589+
describe("incremental with circular references", () => {
590+
function getFileInfo(content: string): BuilderState.FileInfo {
591+
const signature = Harness.mockHash(content);
592+
return { version: signature, signature };
593+
}
594+
const config: File = {
595+
path: configFile.path,
596+
content: JSON.stringify({
597+
compilerOptions: {
598+
incremental: true,
599+
target: "es5",
600+
module: "commonjs",
601+
declaration: true,
602+
emitDeclarationOnly: true
603+
}
604+
})
605+
};
606+
const aTs: File = {
607+
path: `${project}/a.ts`,
608+
content: `import { B } from "./b";
609+
export interface A {
610+
b: B;
611+
}
612+
`
613+
};
614+
const bTs: File = {
615+
path: `${project}/b.ts`,
616+
content: `import { C } from "./c";
617+
export interface B {
618+
b: C;
619+
}
620+
`
621+
};
622+
const cTs: File = {
623+
path: `${project}/c.ts`,
624+
content: `import { A } from "./a";
625+
export interface C {
626+
a: A;
627+
}
628+
`
629+
};
630+
const indexTs: File = {
631+
path: `${project}/index.ts`,
632+
content: `export { A } from "./a";
633+
export { B } from "./b";
634+
export { C } from "./c";
635+
`
636+
};
637+
638+
verifyIncrementalWatchEmit(() => {
639+
const referencedMap: MapLike<string[]> = {
640+
"./a.ts": ["./b.ts"],
641+
"./b.ts": ["./c.ts"],
642+
"./c.ts": ["./a.ts"],
643+
"./index.ts": ["./a.ts", "./b.ts", "./c.ts"],
644+
};
645+
const initialProgram: ProgramBuildInfo = {
646+
fileInfos: {
647+
[libFilePath]: libFileInfo,
648+
"./c.ts": getFileInfo(cTs.content),
649+
"./b.ts": getFileInfo(bTs.content),
650+
"./a.ts": getFileInfo(aTs.content),
651+
"./index.ts": getFileInfo(indexTs.content)
652+
},
653+
options: {
654+
incremental: true,
655+
target: ScriptTarget.ES5,
656+
module: ModuleKind.CommonJS,
657+
declaration: true,
658+
emitDeclarationOnly: true,
659+
configFilePath: "./tsconfig.json"
660+
},
661+
referencedMap,
662+
exportedModulesMap: referencedMap,
663+
semanticDiagnosticsPerFile: [
664+
libFilePath,
665+
"./a.ts",
666+
"./b.ts",
667+
"./c.ts",
668+
"./index.ts",
669+
]
670+
};
671+
const { fileInfos, ...rest } = initialProgram;
672+
const expectedADts: File = { path: `${project}/a.d.ts`, content: aTs.content };
673+
const expectedBDts: File = { path: `${project}/b.d.ts`, content: bTs.content };
674+
const expectedCDts: File = { path: `${project}/c.d.ts`, content: cTs.content };
675+
const expectedIndexDts: File = { path: `${project}/index.d.ts`, content: indexTs.content };
676+
const modifiedATsContent = aTs.content.replace("b: B;", `b: B;
677+
foo: any;`);
678+
return {
679+
files: [libFile, aTs, bTs, cTs, indexTs, config],
680+
expectedInitialEmit: [
681+
expectedADts,
682+
expectedBDts,
683+
expectedCDts,
684+
expectedIndexDts,
685+
{
686+
path: `${project}/tsconfig.tsbuildinfo`,
687+
content: getBuildInfoText({
688+
program: initialProgram,
689+
version
690+
})
691+
}
692+
],
693+
expectedInitialErrors: emptyArray,
694+
modifyFs: host => host.writeFile(aTs.path, modifiedATsContent),
695+
expectedIncrementalEmit: [
696+
{ path: expectedADts.path, content: modifiedATsContent },
697+
expectedBDts,
698+
expectedCDts,
699+
expectedIndexDts,
700+
{
701+
path: `${project}/tsconfig.tsbuildinfo`,
702+
content: getBuildInfoText({
703+
program: {
704+
fileInfos: {
705+
[libFilePath]: libFileInfo,
706+
"./c.ts": getFileInfo(cTs.content),
707+
"./b.ts": getFileInfo(bTs.content),
708+
"./a.ts": getFileInfo(modifiedATsContent),
709+
"./index.ts": getFileInfo(indexTs.content)
710+
},
711+
...rest
712+
},
713+
version
714+
})
715+
}
716+
],
717+
expectedIncrementalErrors: emptyArray
718+
};
586719
});
587720
});
588721
});

0 commit comments

Comments
 (0)