From c8e2b9c7c0f5705916578a1b1dc367ea69dd06d1 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 14 Dec 2017 13:27:04 -0800 Subject: [PATCH] Simplify check output errors --- src/harness/unittests/tscWatchMode.ts | 181 +++++++++++++------------- 1 file changed, 88 insertions(+), 93 deletions(-) diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index 9e01021155c..8abc23f1ac7 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -81,64 +81,60 @@ namespace ts.tscWatch { checkOutputDoesNotContain(host, expectedNonAffectedFiles); } - enum ExpectedOutputErrorsPosition { - BeforeCompilationStarts, - AfterCompilationStarting, - AfterFileChangeDetected - } - function checkOutputErrors( host: WatchedSystem, + preErrorsWatchDiagnostic: DiagnosticMessage | undefined, errors: ReadonlyArray, - errorsPosition: ExpectedOutputErrorsPosition, - skipWaiting?: true + ...postErrorsWatchDiagnostics: DiagnosticMessage[] ) { const outputs = host.getOutput(); - const expectedOutputCount = errors.length + (skipWaiting ? 0 : 1) + 1; - assert.equal(outputs.length, expectedOutputCount, "Outputs = " + outputs.toString()); - let index: number; - - switch (errorsPosition) { - case ExpectedOutputErrorsPosition.AfterCompilationStarting: - assertWatchDiagnosticAt(host, 0, Diagnostics.Starting_compilation_in_watch_mode); - index = 1; - break; - case ExpectedOutputErrorsPosition.AfterFileChangeDetected: - assertWatchDiagnosticAt(host, 0, Diagnostics.File_change_detected_Starting_incremental_compilation); - index = 1; - break; - case ExpectedOutputErrorsPosition.BeforeCompilationStarts: - assertWatchDiagnosticAt(host, errors.length, Diagnostics.Starting_compilation_in_watch_mode); - index = 0; - break; - } - - forEach(errors, error => { - assertDiagnosticAt(host, index, error); - index++; - }); - if (!skipWaiting) { - if (errorsPosition === ExpectedOutputErrorsPosition.BeforeCompilationStarts) { - assertWatchDiagnosticAt(host, index, ts.Diagnostics.Starting_compilation_in_watch_mode); - index += 1; - } - assertWatchDiagnosticAt(host, index, Diagnostics.Compilation_complete_Watching_for_file_changes); + const expectedOutputCount = (preErrorsWatchDiagnostic ? 1 : 0) + errors.length + postErrorsWatchDiagnostics.length; + assert.equal(outputs.length, expectedOutputCount); + let index = 0; + if (preErrorsWatchDiagnostic) { + assertWatchDiagnostic(preErrorsWatchDiagnostic); } + // Verify errors + forEach(errors, assertDiagnostic); + forEach(postErrorsWatchDiagnostics, assertWatchDiagnostic); host.clearOutput(); + + function assertDiagnostic(diagnostic: Diagnostic) { + const expected = formatDiagnostic(diagnostic, host); + assert.equal(outputs[index], expected, getOutputAtFailedMessage("Diagnostic", expected)); + index++; + } + + function assertWatchDiagnostic(diagnosticMessage: DiagnosticMessage) { + const expected = getWatchDiagnosticWithoutDate(diagnosticMessage); + assert.isTrue(endsWith(outputs[index], expected), getOutputAtFailedMessage("Watch diagnostic", expected)); + index++; + } + + function getOutputAtFailedMessage(caption: string, expectedOutput: string) { + return `Expected ${caption}: ${expectedOutput} at ${index} in ${JSON.stringify(outputs)}`; + } + + function getWatchDiagnosticWithoutDate(diagnosticMessage: DiagnosticMessage) { + return ` - ${flattenDiagnosticMessageText(getLocaleSpecificMessage(diagnosticMessage), host.newLine)}${host.newLine + host.newLine + host.newLine}`; + } } - function assertDiagnosticAt(host: WatchedSystem, outputAt: number, diagnostic: Diagnostic) { - const output = host.getOutput()[outputAt]; - assert.equal(output, formatDiagnostic(diagnostic, host), "outputs[" + outputAt + "] is " + output); + function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray) { + checkOutputErrors(host, Diagnostics.Starting_compilation_in_watch_mode, errors, Diagnostics.Compilation_complete_Watching_for_file_changes); } - function assertWatchDiagnosticAt(host: WatchedSystem, outputAt: number, diagnosticMessage: DiagnosticMessage) { - const output = host.getOutput()[outputAt]; - assert.isTrue(endsWith(output, getWatchDiagnosticWithoutDate(host, diagnosticMessage)), "outputs[" + outputAt + "] is " + output); + function checkOutputErrorsInitialWithConfigErrors(host: WatchedSystem, errors: ReadonlyArray) { + checkOutputErrors(host, /*preErrorsWatchDiagnostic*/ undefined, errors, Diagnostics.Starting_compilation_in_watch_mode, Diagnostics.Compilation_complete_Watching_for_file_changes); } - function getWatchDiagnosticWithoutDate(host: WatchedSystem, diagnosticMessage: DiagnosticMessage) { - return ` - ${flattenDiagnosticMessageText(getLocaleSpecificMessage(diagnosticMessage), host.newLine)}${host.newLine + host.newLine + host.newLine}`; + function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray) { + checkOutputErrors(host, Diagnostics.File_change_detected_Starting_incremental_compilation, errors, Diagnostics.Compilation_complete_Watching_for_file_changes); + } + + function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray, expectedExitCode: ExitStatus) { + checkOutputErrors(host, Diagnostics.File_change_detected_Starting_incremental_compilation, errors); + assert.equal(host.exitCode, expectedExitCode); } function getDiagnosticOfFileFrom(file: SourceFile, text: string, start: number, length: number, message: DiagnosticMessage): Diagnostic { @@ -358,16 +354,16 @@ namespace ts.tscWatch { checkProgramRootFiles(watch(), [file1.path]); checkProgramActualFiles(watch(), [file1.path, libFile.path]); - checkOutputErrors(host, [ + checkOutputErrorsInitial(host, [ getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf(commonFile2Name), commonFile2Name.length, Diagnostics.File_0_not_found, commonFile2.path), getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf("y"), 1, Diagnostics.Cannot_find_name_0, "y") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + ]); host.reloadFS([file1, commonFile2, libFile]); host.runQueuedTimeoutCallbacks(); checkProgramRootFiles(watch(), [file1.path]); checkProgramActualFiles(watch(), [file1.path, libFile.path, commonFile2.path]); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); }); it("should reflect change in config file", () => { @@ -695,15 +691,14 @@ namespace ts.tscWatch { const watch = createWatchModeWithConfigFile(config.path, host); checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, emptyArray); host.reloadFS([file1, file2, libFile]); host.checkTimeoutQueueLengthAndRun(1); - assert.equal(host.exitCode, ExitStatus.DiagnosticsPresent_OutputsSkipped); - checkOutputErrors(host, [ + checkOutputErrorsIncrementalWithExit(host, [ getDiagnosticWithoutFile(Diagnostics.File_0_not_found, config.path) - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected, /*skipWaiting*/ true); + ], ExitStatus.DiagnosticsPresent_OutputsSkipped); }); it("Proper errors: document is not contained in project", () => { @@ -806,21 +801,21 @@ namespace ts.tscWatch { }; const host = createWatchedSystem([moduleFile, file1, libFile]); const watch = createWatchModeWithoutConfigFile([file1.path], host); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, emptyArray); const moduleFileOldPath = moduleFile.path; const moduleFileNewPath = "/a/b/moduleFile1.ts"; moduleFile.path = moduleFileNewPath; host.reloadFS([moduleFile, file1, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, [ + checkOutputErrorsIncremental(host, [ getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + ]); moduleFile.path = moduleFileOldPath; host.reloadFS([moduleFile, file1, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); }); it("rename a module file and rename back should restore the states for configured projects", () => { @@ -838,21 +833,21 @@ namespace ts.tscWatch { }; const host = createWatchedSystem([moduleFile, file1, configFile, libFile]); const watch = createWatchModeWithConfigFile(configFile.path, host); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, emptyArray); const moduleFileOldPath = moduleFile.path; const moduleFileNewPath = "/a/b/moduleFile1.ts"; moduleFile.path = moduleFileNewPath; host.reloadFS([moduleFile, file1, configFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, [ + checkOutputErrorsIncremental(host, [ getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + ]); moduleFile.path = moduleFileOldPath; host.reloadFS([moduleFile, file1, configFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); }); it("types should load from config file path if config exists", () => { @@ -889,13 +884,13 @@ namespace ts.tscWatch { const host = createWatchedSystem([file1, libFile]); const watch = createWatchModeWithoutConfigFile([file1.path], host); - checkOutputErrors(host, [ + checkOutputErrorsInitial(host, [ getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + ]); host.reloadFS([file1, moduleFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); }); it("Configure file diagnostics events are generated when the config file has errors", () => { @@ -915,10 +910,10 @@ namespace ts.tscWatch { const host = createWatchedSystem([file, configFile, libFile]); const watch = createWatchModeWithConfigFile(configFile.path, host); - checkOutputErrors(host, [ + checkOutputErrorsInitialWithConfigErrors(host, [ getUnknownCompilerOption(watch(), configFile, "foo"), getUnknownCompilerOption(watch(), configFile, "allowJS") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.BeforeCompilationStarts); + ]); }); it("If config file doesnt have errors, they are not reported", () => { @@ -935,7 +930,7 @@ namespace ts.tscWatch { const host = createWatchedSystem([file, configFile, libFile]); createWatchModeWithConfigFile(configFile.path, host); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, emptyArray); }); it("Reports errors when the config file changes", () => { @@ -952,7 +947,7 @@ namespace ts.tscWatch { const host = createWatchedSystem([file, configFile, libFile]); const watch = createWatchModeWithConfigFile(configFile.path, host); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, emptyArray); configFile.content = `{ "compilerOptions": { @@ -961,16 +956,16 @@ namespace ts.tscWatch { }`; host.reloadFS([file, configFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, [ + checkOutputErrorsIncremental(host, [ getUnknownCompilerOption(watch(), configFile, "haha") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + ]); configFile.content = `{ "compilerOptions": {} }`; host.reloadFS([file, configFile, libFile]); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); }); it("non-existing directories listed in config file input array should be tolerated without crashing the server", () => { @@ -1058,13 +1053,13 @@ namespace ts.tscWatch { getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration") ]; const intialErrors = errors(); - checkOutputErrors(host, intialErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, intialErrors); configFile.content = configFileContentWithoutCommentLine; host.reloadFS(files); host.runQueuedTimeoutCallbacks(); const nowErrors = errors(); - checkOutputErrors(host, nowErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, nowErrors); assert.equal(nowErrors[0].start, intialErrors[0].start - configFileContentComment.length); assert.equal(nowErrors[1].start, intialErrors[1].start - configFileContentComment.length); }); @@ -1725,7 +1720,7 @@ namespace ts.tscWatch { const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo"); // ensure that imported file was found - checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, [f1IsNotModule, cannotFindFoo]); const originalFileExists = host.fileExists; { @@ -1741,11 +1736,11 @@ namespace ts.tscWatch { host.runQueuedTimeoutCallbacks(); // ensure file has correct number of errors after edit - checkOutputErrors(host, [ + checkOutputErrorsIncremental(host, [ f1IsNotModule, getDiagnosticOfFileFromProgram(watch(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"), cannotFindFoo - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + ]); } { let fileExistsIsCalled = false; @@ -1765,9 +1760,9 @@ namespace ts.tscWatch { host.runQueuedTimeoutCallbacks(); // ensure file has correct number of errors after edit - checkOutputErrors(host, [ + checkOutputErrorsIncremental(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "f2") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + ]); assert.isTrue(fileExistsIsCalled); } @@ -1788,7 +1783,7 @@ namespace ts.tscWatch { host.reloadFS(files); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, [f1IsNotModule, cannotFindFoo]); assert.isTrue(fileExistsCalled); } }); @@ -1823,16 +1818,16 @@ namespace ts.tscWatch { const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD }); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called"); - checkOutputErrors(host, [ + checkOutputErrorsInitial(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "bar") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + ]); fileExistsCalledForBar = false; root.content = `import {y} from "bar"`; host.reloadFS(files.concat(imported)); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); }); @@ -1865,20 +1860,20 @@ namespace ts.tscWatch { const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD }); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called"); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, emptyArray); fileExistsCalledForBar = false; host.reloadFS(files); host.runQueuedTimeoutCallbacks(); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); - checkOutputErrors(host, [ + checkOutputErrorsIncremental(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "bar") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + ]); fileExistsCalledForBar = false; host.reloadFS(filesWithImported); host.checkTimeoutQueueLengthAndRun(1); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); }); @@ -1913,13 +1908,13 @@ declare module "fs" { const watch = createWatchModeWithoutConfigFile([root.path], host, { }); - checkOutputErrors(host, [ + checkOutputErrorsInitial(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "fs") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + ]); host.reloadFS(filesWithNodeType); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); }); it("works when included file with ambient module changes", () => { @@ -1955,14 +1950,14 @@ declare module "fs" { const watch = createWatchModeWithoutConfigFile([root.path, file.path], host, {}); - checkOutputErrors(host, [ + checkOutputErrorsInitial(host, [ getDiagnosticModuleNotFoundOfFile(watch(), root, "fs") - ], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + ]); file.content += fileContentWithFS; host.reloadFS(files); host.runQueuedTimeoutCallbacks(); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); }); it("works when reusing program with files from external library", () => { @@ -1997,7 +1992,7 @@ declare module "fs" { const host = createWatchedSystem(programFiles.concat(configFile), { currentDirectory: "/a/b/projects/myProject/" }); const watch = createWatchModeWithConfigFile(configFile.path, host); checkProgramActualFiles(watch(), programFiles.map(f => f.path)); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting); + checkOutputErrorsInitial(host, emptyArray); const expectedFiles: ExpectedFile[] = [ createExpectedEmittedFile(file1), createExpectedEmittedFile(file2), @@ -2016,7 +2011,7 @@ declare module "fs" { host.reloadFS(programFiles.concat(configFile)); host.runQueuedTimeoutCallbacks(); checkProgramActualFiles(watch(), programFiles.map(f => f.path)); - checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected); + checkOutputErrorsIncremental(host, emptyArray); verifyExpectedFiles(expectedFiles);