Skip to content

Commit fd515b5

Browse files
committed
Handle status and error messages for better checking
1 parent 9e8fbcd commit fd515b5

File tree

9 files changed

+191
-30
lines changed

9 files changed

+191
-30
lines changed

src/harness/fakes.ts

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -375,15 +375,118 @@ namespace fakes {
375375
}
376376
}
377377

378-
export type ExpectedDiagnostic = [ts.DiagnosticMessage, ...(string | number)[]];
379-
function expectedDiagnosticToText([message, ...args]: ExpectedDiagnostic) {
378+
export type ExpectedDiagnosticMessage = [ts.DiagnosticMessage, ...(string | number)[]];
379+
export interface ExpectedDiagnosticMessageChain {
380+
message: ExpectedDiagnosticMessage;
381+
next?: ExpectedDiagnosticMessageChain[];
382+
}
383+
384+
export interface ExpectedDiagnosticLocation {
385+
file: string;
386+
start: number;
387+
length: number;
388+
}
389+
export interface ExpectedDiagnosticRelatedInformation extends ExpectedDiagnosticMessageChain {
390+
location?: ExpectedDiagnosticLocation;
391+
}
392+
393+
export enum DiagnosticKind {
394+
Error = "Error",
395+
Status = "Status"
396+
}
397+
export interface ExpectedErrorDiagnostic extends ExpectedDiagnosticRelatedInformation {
398+
relatedInformation?: ExpectedDiagnosticRelatedInformation[];
399+
}
400+
401+
export type ExpectedDiagnostic = ExpectedDiagnosticMessage | ExpectedErrorDiagnostic;
402+
403+
interface SolutionBuilderDiagnostic {
404+
kind: DiagnosticKind;
405+
diagnostic: ts.Diagnostic;
406+
}
407+
408+
function indentedText(indent: number, text: string) {
409+
if (!indent) return text;
410+
let indentText = "";
411+
for (let i = 0; i < indent; i++) {
412+
indentText += " ";
413+
}
414+
return `
415+
${indentText}${text}`;
416+
}
417+
418+
function expectedDiagnosticMessageToText([message, ...args]: ExpectedDiagnosticMessage) {
380419
let text = ts.getLocaleSpecificMessage(message);
381420
if (args.length) {
382421
text = ts.formatStringFromArgs(text, args);
383422
}
384423
return text;
385424
}
386425

426+
function expectedDiagnosticMessageChainToText({ message, next }: ExpectedDiagnosticMessageChain, indent = 0) {
427+
let text = indentedText(indent, expectedDiagnosticMessageToText(message));
428+
if (next) {
429+
indent++;
430+
next.forEach(kid => text += expectedDiagnosticMessageChainToText(kid, indent));
431+
}
432+
return text;
433+
}
434+
435+
function expectedDiagnosticRelatedInformationToText({ location, ...diagnosticMessage }: ExpectedDiagnosticRelatedInformation) {
436+
const text = expectedDiagnosticMessageChainToText(diagnosticMessage);
437+
if (location) {
438+
const { file, start, length } = location;
439+
return `${file}(${start}:${length}):: ${text}`;
440+
}
441+
return text;
442+
}
443+
444+
function expectedErrorDiagnosticToText({ relatedInformation, ...diagnosticRelatedInformation }: ExpectedErrorDiagnostic) {
445+
let text = `${DiagnosticKind.Error}!: ${expectedDiagnosticRelatedInformationToText(diagnosticRelatedInformation)}`;
446+
if (relatedInformation) {
447+
for (const kid of relatedInformation) {
448+
text += `
449+
related:: ${expectedDiagnosticRelatedInformationToText(kid)}`;
450+
}
451+
}
452+
return text;
453+
}
454+
455+
function expectedDiagnosticToText(errorOrStatus: ExpectedDiagnostic) {
456+
return ts.isArray(errorOrStatus) ?
457+
`${DiagnosticKind.Status}!: ${expectedDiagnosticMessageToText(errorOrStatus)}` :
458+
expectedErrorDiagnosticToText(errorOrStatus);
459+
}
460+
461+
function diagnosticMessageChainToText({ messageText, next}: ts.DiagnosticMessageChain, indent = 0) {
462+
let text = indentedText(indent, messageText);
463+
if (next) {
464+
indent++;
465+
next.forEach(kid => text += diagnosticMessageChainToText(kid, indent));
466+
}
467+
return text;
468+
}
469+
470+
function diagnosticRelatedInformationToText({ file, start, length, messageText }: ts.DiagnosticRelatedInformation) {
471+
const text = typeof messageText === "string" ?
472+
messageText :
473+
diagnosticMessageChainToText(messageText);
474+
return file ?
475+
`${file.fileName}(${start}:${length}):: ${text}` :
476+
text;
477+
}
478+
479+
function diagnosticToText({ kind, diagnostic: { relatedInformation, ...diagnosticRelatedInformation } }: SolutionBuilderDiagnostic) {
480+
let text = `${kind}!: ${diagnosticRelatedInformationToText(diagnosticRelatedInformation)}`;
481+
if (relatedInformation) {
482+
for (const kid of relatedInformation) {
483+
text += `
484+
related:: ${diagnosticRelatedInformationToText(kid)}`;
485+
}
486+
}
487+
return text;
488+
}
489+
387490
function compareProgramBuildInfoDiagnostic(a: ts.ProgramBuildInfoDiagnostic, b: ts.ProgramBuildInfoDiagnostic) {
388491
return ts.compareStringsCaseSensitive(ts.isString(a) ? a : a[0], ts.isString(b) ? b : b[0]);
389492
}
@@ -446,22 +549,22 @@ namespace fakes {
446549
return new Date(this.sys.vfs.time());
447550
}
448551

449-
diagnostics: ts.Diagnostic[] = [];
552+
diagnostics: SolutionBuilderDiagnostic[] = [];
450553

451554
reportDiagnostic(diagnostic: ts.Diagnostic) {
452-
this.diagnostics.push(diagnostic);
555+
this.diagnostics.push({ kind: DiagnosticKind.Error, diagnostic });
453556
}
454557

455558
reportSolutionBuilderStatus(diagnostic: ts.Diagnostic) {
456-
this.diagnostics.push(diagnostic);
559+
this.diagnostics.push({ kind: DiagnosticKind.Status, diagnostic });
457560
}
458561

459562
clearDiagnostics() {
460563
this.diagnostics.length = 0;
461564
}
462565

463566
assertDiagnosticMessages(...expectedDiagnostics: ExpectedDiagnostic[]) {
464-
const actual = this.diagnostics.slice().map(d => d.messageText as string);
567+
const actual = this.diagnostics.slice().map(diagnosticToText);
465568
const expected = expectedDiagnostics.map(expectedDiagnosticToText);
466569
assert.deepEqual(actual, expected, `Diagnostic arrays did not match:
467570
Actual: ${JSON.stringify(actual, /*replacer*/ undefined, " ")}
@@ -471,8 +574,8 @@ Expected: ${JSON.stringify(expected, /*replacer*/ undefined, " ")}`);
471574
printDiagnostics(header = "== Diagnostics ==") {
472575
const out = ts.createDiagnosticReporter(ts.sys);
473576
ts.sys.write(header + "\r\n");
474-
for (const d of this.diagnostics) {
475-
out(d);
577+
for (const { diagnostic } of this.diagnostics) {
578+
out(diagnostic);
476579
}
477580
}
478581
}

src/testRunner/unittests/tsbuild/demo.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,15 @@ namespace ts {
9393
expectedExitStatus: ExitStatus.ProjectReferenceCycle_OutputsSkupped,
9494
expectedDiagnostics: [
9595
getExpectedDiagnosticForProjectsInBuild("src/animals/tsconfig.json", "src/zoo/tsconfig.json", "src/core/tsconfig.json", "src/tsconfig.json"),
96-
[
96+
errorDiagnostic([
9797
Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0,
9898
[
9999
"/src/tsconfig.json",
100100
"/src/core/tsconfig.json",
101101
"/src/zoo/tsconfig.json",
102102
"/src/animals/tsconfig.json"
103103
].join("\r\n")
104-
]
104+
])
105105
],
106106
expectedOutputs: emptyArray,
107107
notExpectedOutputs: [...coreOutputs(), ...animalOutputs(), ...zooOutputs()]
@@ -121,12 +121,12 @@ namespace ts {
121121
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/animals/tsconfig.json", "src/zoo/tsconfig.json", "src/tsconfig.json"),
122122
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/lib/core/utilities.js"],
123123
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
124-
[Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/animal.ts", "/src/core"],
125-
[Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/dog.ts", "/src/core"],
126-
[Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/index.ts", "/src/core"],
127-
[Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/animal.ts", "/src/core/tsconfig.json"],
128-
[Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/dog.ts", "/src/core/tsconfig.json"],
129-
[Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/index.ts", "/src/core/tsconfig.json"],
124+
errorDiagnostic([Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/animal.ts", "/src/core"]),
125+
errorDiagnostic([Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/dog.ts", "/src/core"]),
126+
errorDiagnostic([Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/index.ts", "/src/core"]),
127+
errorDiagnostic([Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/animal.ts", "/src/core/tsconfig.json"]),
128+
errorDiagnostic([Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/dog.ts", "/src/core/tsconfig.json"]),
129+
errorDiagnostic([Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/index.ts", "/src/core/tsconfig.json"]),
130130
[Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, "src/animals/tsconfig.json", "src/core"],
131131
[Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, "/src/animals/tsconfig.json", "/src/core"],
132132
[Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_was_not_built, "src/zoo/tsconfig.json", "src/animals"],

src/testRunner/unittests/tsbuild/emptyFiles.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ namespace ts {
1515

1616
host.clearDiagnostics();
1717
builder.build();
18-
host.assertDiagnosticMessages([Diagnostics.The_files_list_in_config_file_0_is_empty, "/src/no-references/tsconfig.json"]);
18+
host.assertDiagnosticMessages({
19+
message: [Diagnostics.The_files_list_in_config_file_0_is_empty, "/src/no-references/tsconfig.json"],
20+
location: {
21+
file: "/src/no-references/tsconfig.json",
22+
start: lastIndexOf(fs, "/src/no-references/tsconfig.json", "[]"),
23+
length: 2
24+
}
25+
});
1926

2027
// Check for outputs to not be written.
2128
verifyOutputsAbsent(fs, allExpectedOutputs);

src/testRunner/unittests/tsbuild/helpers.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
namespace ts {
2+
export function errorDiagnostic(message: fakes.ExpectedDiagnosticMessage): fakes.ExpectedErrorDiagnostic {
3+
return { message };
4+
}
5+
26
export function getExpectedDiagnosticForProjectsInBuild(...projects: string[]): fakes.ExpectedDiagnostic {
37
return [Diagnostics.Projects_in_this_build_Colon_0, projects.map(p => "\r\n * " + p).join("")];
48
}
@@ -42,6 +46,22 @@ namespace ts {
4246
fs.writeFileSync(path, `${old}${additionalContent}`);
4347
}
4448

49+
export function indexOf(fs: vfs.FileSystem, path: string, searchStr: string) {
50+
if (!fs.statSync(path).isFile()) {
51+
throw new Error(`File ${path} does not exist`);
52+
}
53+
const content = fs.readFileSync(path, "utf-8");
54+
return content.indexOf(searchStr);
55+
}
56+
57+
export function lastIndexOf(fs: vfs.FileSystem, path: string, searchStr: string) {
58+
if (!fs.statSync(path).isFile()) {
59+
throw new Error(`File ${path} does not exist`);
60+
}
61+
const content = fs.readFileSync(path, "utf-8");
62+
return content.lastIndexOf(searchStr);
63+
}
64+
4565
export function getTime() {
4666
let currentTime = 100;
4767
return { tick, time, touch };

src/testRunner/unittests/tsbuild/missingExtendedFile.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ namespace ts {
77
const builder = createSolutionBuilder(host, ["/src/tsconfig.json"], {});
88
builder.build();
99
host.assertDiagnosticMessages(
10-
[Diagnostics.The_specified_path_does_not_exist_Colon_0, "/src/foobar.json"],
11-
[Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, "/src/tsconfig.first.json", "[\"**/*\"]", "[]"],
12-
[Diagnostics.The_specified_path_does_not_exist_Colon_0, "/src/foobar.json"],
13-
[Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, "/src/tsconfig.second.json", "[\"**/*\"]", "[]"]
10+
errorDiagnostic([Diagnostics.The_specified_path_does_not_exist_Colon_0, "/src/foobar.json"]),
11+
errorDiagnostic([Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, "/src/tsconfig.first.json", "[\"**/*\"]", "[]"]),
12+
errorDiagnostic([Diagnostics.The_specified_path_does_not_exist_Colon_0, "/src/foobar.json"]),
13+
errorDiagnostic([Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, "/src/tsconfig.second.json", "[\"**/*\"]", "[]"])
1414
);
1515
});
1616
});

src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,14 @@ namespace ts {
4343
[Diagnostics.Building_project_0, "/src/src/other/tsconfig.json"],
4444
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/src/main/tsconfig.json", "src/dist/a.js"],
4545
[Diagnostics.Building_project_0, "/src/src/main/tsconfig.json"],
46-
[Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"]
46+
{
47+
message: [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"],
48+
location: {
49+
file: "/src/src/main/tsconfig.json",
50+
start: indexOf(fs, "/src/src/main/tsconfig.json", `{ "path": "../other" }`),
51+
length: `{ "path": "../other" }`.length
52+
}
53+
}
4754
);
4855
verifyOutputsPresent(fs, allExpectedOutputs);
4956
verifyOutputsAbsent(fs, missingOutputs);
@@ -75,7 +82,14 @@ namespace ts {
7582
[Diagnostics.Building_project_0, "/src/src/other/tsconfig.json"],
7683
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/src/main/tsconfig.json", "src/dist/a.js"],
7784
[Diagnostics.Building_project_0, "/src/src/main/tsconfig.json"],
78-
[Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"]
85+
{
86+
message: [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"],
87+
location: {
88+
file: "/src/src/main/tsconfig.json",
89+
start: indexOf(fs, "/src/src/main/tsconfig.json", `{"path":"../other"}`),
90+
length: `{"path":"../other"}`.length
91+
}
92+
}
7993
);
8094
verifyOutputsPresent(fs, allExpectedOutputs);
8195
verifyOutputsAbsent(fs, missingOutputs);

src/testRunner/unittests/tsbuild/resolveJsonModule.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ namespace ts {
2828
}
2929

3030
it("with resolveJsonModule and include only", () => {
31-
verifyProjectWithResolveJsonModule("/src/tsconfig_withInclude.json", [
32-
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
33-
"/src/src/hello.json",
34-
"/src/tsconfig_withInclude.json"
35-
]);
31+
verifyProjectWithResolveJsonModule(
32+
"/src/tsconfig_withInclude.json",
33+
errorDiagnostic([
34+
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
35+
"/src/src/hello.json",
36+
"/src/tsconfig_withInclude.json"
37+
])
38+
);
3639
});
3740

3841
it("with resolveJsonModule and include of *.json along with other include", () => {

src/testRunner/unittests/tsbuild/sample.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,14 @@ namespace ts {
450450
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
451451
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/logic/tsconfig.json", "src/logic/index.js"],
452452
[Diagnostics.Building_project_0, "/src/logic/tsconfig.json"],
453-
[Diagnostics.Property_0_does_not_exist_on_type_1, "muitply", `typeof import("/src/core/index")`],
453+
{
454+
message: [Diagnostics.Property_0_does_not_exist_on_type_1, "muitply", `typeof import("/src/core/index")`],
455+
location: {
456+
file: "/src/logic/index.ts",
457+
start: indexOf(fs, "/src/logic/index.ts", "muitply"),
458+
length: "muitply".length
459+
}
460+
},
454461
[Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, "src/tests/tsconfig.json", "src/logic"],
455462
[Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, "/src/tests/tsconfig.json", "/src/logic"]
456463
);

src/testRunner/unittests/tsbuild/transitiveReferences.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,14 @@ export const b = new A();`);
6969
verifyBuild(fs => modifyFsBTsToNonRelativeImport(fs, "node"),
7070
allExpectedOutputs,
7171
expectedFileTraces,
72-
[Diagnostics.Cannot_find_module_0, "a"],
72+
{
73+
message: [Diagnostics.Cannot_find_module_0, "a"],
74+
location: {
75+
file: "/src/b.ts",
76+
start: `import {A} from 'a';`.indexOf(`'a'`),
77+
length: `'a'`.length
78+
}
79+
},
7380
);
7481
});
7582
});

0 commit comments

Comments
 (0)