diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts
index 88e81ffcf348d..a64435b7ddcbe 100644
--- a/src/harness/compilerRunner.ts
+++ b/src/harness/compilerRunner.ts
@@ -1,8 +1,6 @@
///
///
///
-// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`.
-/* tslint:disable:no-null-keyword */
const enum CompilerTestType {
Conformance,
@@ -136,21 +134,10 @@ class CompilerBaselineRunner extends RunnerBase {
otherFiles = undefined;
});
- function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string {
- return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : "";
- }
-
- function getErrorBaseline(toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], result: Harness.Compiler.CompilerResult) {
- return Harness.Compiler.getErrorBaseline(toBeCompiled.concat(otherFiles), result.errors);
- }
-
// check errors
it("Correct errors for " + fileName, () => {
if (this.errors) {
- Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), (): string => {
- if (result.errors.length === 0) return null;
- return getErrorBaseline(toBeCompiled, otherFiles, result);
- });
+ Harness.Compiler.doErrorBaseline(justName, toBeCompiled.concat(otherFiles), result.errors);
}
});
@@ -168,8 +155,10 @@ class CompilerBaselineRunner extends RunnerBase {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => {
const record = result.getSourceMapRecord();
if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) {
- // Because of the noEmitOnError option no files are created. We need to return null because baselining isn"t required.
+ // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
+ /* tslint:disable:no-null-keyword */
return null;
+ /* tslint:enable:no-null-keyword */
}
return record;
});
@@ -178,87 +167,12 @@ class CompilerBaselineRunner extends RunnerBase {
it("Correct JS output for " + fileName, () => {
if (hasNonDtsFiles && this.emit) {
- if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) {
- throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
- }
-
- // check js output
- Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, ".js"), () => {
- let tsCode = "";
- const tsSources = otherFiles.concat(toBeCompiled);
- if (tsSources.length > 1) {
- tsCode += "//// [" + fileName + "] ////\r\n\r\n";
- }
- for (let i = 0; i < tsSources.length; i++) {
- tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n";
- tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : "");
- }
-
- let jsCode = "";
- for (let i = 0; i < result.files.length; i++) {
- jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n";
- jsCode += getByteOrderMarkText(result.files[i]);
- jsCode += result.files[i].code;
- }
-
- if (result.declFilesCode.length > 0) {
- jsCode += "\r\n\r\n";
- for (let i = 0; i < result.declFilesCode.length; i++) {
- jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n";
- jsCode += getByteOrderMarkText(result.declFilesCode[i]);
- jsCode += result.declFilesCode[i].code;
- }
- }
-
- const declFileCompilationResult =
- Harness.Compiler.compileDeclarationFiles(
- toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
-
- if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
- jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
- jsCode += "\r\n\r\n";
- jsCode += getErrorBaseline(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles, declFileCompilationResult.declResult);
- }
-
- if (jsCode.length > 0) {
- return tsCode + "\r\n\r\n" + jsCode;
- }
- else {
- return null;
- }
- });
+ Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, toBeCompiled, otherFiles, harnessSettings);
}
});
it("Correct Sourcemap output for " + fileName, () => {
- if (options.inlineSourceMap) {
- if (result.sourceMaps.length > 0) {
- throw new Error("No sourcemap files should be generated if inlineSourceMaps was set.");
- }
- return null;
- }
- else if (options.sourceMap) {
- if (result.sourceMaps.length !== result.files.length) {
- throw new Error("Number of sourcemap files should be same as js files.");
- }
-
- Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, ".js.map"), () => {
- if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) {
- // We need to return null here or the runBaseLine will actually create a empty file.
- // Baselining isn't required here because there is no output.
- return null;
- }
-
- let sourceMapCode = "";
- for (let i = 0; i < result.sourceMaps.length; i++) {
- sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n";
- sourceMapCode += getByteOrderMarkText(result.sourceMaps[i]);
- sourceMapCode += result.sourceMaps[i].code;
- }
-
- return sourceMapCode;
- });
- }
+ Harness.Compiler.doSourcemapBaseline(justName, options, result);
});
it("Correct type/symbol baselines for " + fileName, () => {
@@ -266,129 +180,7 @@ class CompilerBaselineRunner extends RunnerBase {
return;
}
- // NEWTODO: Type baselines
- if (result.errors.length !== 0) {
- return;
- }
-
- // The full walker simulates the types that you would get from doing a full
- // compile. The pull walker simulates the types you get when you just do
- // a type query for a random node (like how the LS would do it). Most of the
- // time, these will be the same. However, occasionally, they can be different.
- // Specifically, when the compiler internally depends on symbol IDs to order
- // things, then we may see different results because symbols can be created in a
- // different order with 'pull' operations, and thus can produce slightly differing
- // output.
- //
- // For example, with a full type check, we may see a type displayed as: number | string
- // But with a pull type check, we may see it as: string | number
- //
- // These types are equivalent, but depend on what order the compiler observed
- // certain parts of the program.
-
- const program = result.program;
- const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
-
- const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
-
- const fullResults = ts.createMap();
- const pullResults = ts.createMap();
-
- for (const sourceFile of allFiles) {
- fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
- pullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
- }
-
- // Produce baselines. The first gives the types for all expressions.
- // The second gives symbols for all identifiers.
- let e1: Error, e2: Error;
- try {
- checkBaseLines(/*isSymbolBaseLine*/ false);
- }
- catch (e) {
- e1 = e;
- }
-
- try {
- checkBaseLines(/*isSymbolBaseLine*/ true);
- }
- catch (e) {
- e2 = e;
- }
-
- if (e1 || e2) {
- throw e1 || e2;
- }
-
- return;
-
- function checkBaseLines(isSymbolBaseLine: boolean) {
- const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
- const pullBaseLine = generateBaseLine(pullResults, isSymbolBaseLine);
-
- const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
- const pullExtension = isSymbolBaseLine ? ".symbols.pull" : ".types.pull";
-
- if (fullBaseLine !== pullBaseLine) {
- Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
- Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine);
- }
- else {
- Harness.Baseline.runBaseline(justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
- }
- }
-
- function generateBaseLine(typeWriterResults: ts.Map, isSymbolBaseline: boolean): string {
- const typeLines: string[] = [];
- const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
-
- allFiles.forEach(file => {
- const codeLines = file.content.split("\n");
- typeWriterResults[file.unitName].forEach(result => {
- if (isSymbolBaseline && !result.symbol) {
- return;
- }
-
- const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
- const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
- if (!typeMap[file.unitName]) {
- typeMap[file.unitName] = {};
- }
-
- let typeInfo = [formattedLine];
- const existingTypeInfo = typeMap[file.unitName][result.line];
- if (existingTypeInfo) {
- typeInfo = existingTypeInfo.concat(typeInfo);
- }
- typeMap[file.unitName][result.line] = typeInfo;
- });
-
- typeLines.push("=== " + file.unitName + " ===\r\n");
- for (let i = 0; i < codeLines.length; i++) {
- const currentCodeLine = codeLines[i];
- typeLines.push(currentCodeLine + "\r\n");
- if (typeMap[file.unitName]) {
- const typeInfo = typeMap[file.unitName][i];
- if (typeInfo) {
- typeInfo.forEach(ty => {
- typeLines.push(">" + ty + "\r\n");
- });
- if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
- }
- else {
- typeLines.push("\r\n");
- }
- }
- }
- else {
- typeLines.push("No type information for this code.");
- }
- }
- });
-
- return typeLines.join("");
- }
-
+ Harness.Compiler.doTypeAndSymbolBaseline(justName, result, toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)));
});
});
}
diff --git a/src/harness/harness.ts b/src/harness/harness.ts
index 3375b8e47e7dc..14cb3147c323d 100644
--- a/src/harness/harness.ts
+++ b/src/harness/harness.ts
@@ -1328,6 +1328,220 @@ namespace Harness {
Harness.IO.newLine() + Harness.IO.newLine() + outputLines.join("\r\n");
}
+ export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) {
+ Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string => {
+ if (errors.length === 0) {
+ /* tslint:disable:no-null-keyword */
+ return null;
+ /* tslint:enable:no-null-keyword */
+ }
+ return getErrorBaseline(inputFiles, errors);
+ });
+ }
+
+ export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[]) {
+ if (result.errors.length !== 0) {
+ return;
+ }
+ // The full walker simulates the types that you would get from doing a full
+ // compile. The pull walker simulates the types you get when you just do
+ // a type query for a random node (like how the LS would do it). Most of the
+ // time, these will be the same. However, occasionally, they can be different.
+ // Specifically, when the compiler internally depends on symbol IDs to order
+ // things, then we may see different results because symbols can be created in a
+ // different order with 'pull' operations, and thus can produce slightly differing
+ // output.
+ //
+ // For example, with a full type check, we may see a type displayed as: number | string
+ // But with a pull type check, we may see it as: string | number
+ //
+ // These types are equivalent, but depend on what order the compiler observed
+ // certain parts of the program.
+
+ const program = result.program;
+
+ const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
+
+ const fullResults = ts.createMap();
+
+ for (const sourceFile of allFiles) {
+ fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
+ }
+
+ // Produce baselines. The first gives the types for all expressions.
+ // The second gives symbols for all identifiers.
+ let e1: Error, e2: Error;
+ try {
+ checkBaseLines(/*isSymbolBaseLine*/ false);
+ }
+ catch (e) {
+ e1 = e;
+ }
+
+ try {
+ checkBaseLines(/*isSymbolBaseLine*/ true);
+ }
+ catch (e) {
+ e2 = e;
+ }
+
+ if (e1 || e2) {
+ throw e1 || e2;
+ }
+
+ return;
+
+ function checkBaseLines(isSymbolBaseLine: boolean) {
+ const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
+
+ const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
+
+ Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
+ }
+
+ function generateBaseLine(typeWriterResults: ts.Map, isSymbolBaseline: boolean): string {
+ const typeLines: string[] = [];
+ const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
+
+ allFiles.forEach(file => {
+ const codeLines = file.content.split("\n");
+ typeWriterResults[file.unitName].forEach(result => {
+ if (isSymbolBaseline && !result.symbol) {
+ return;
+ }
+
+ const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
+ const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
+ if (!typeMap[file.unitName]) {
+ typeMap[file.unitName] = {};
+ }
+
+ let typeInfo = [formattedLine];
+ const existingTypeInfo = typeMap[file.unitName][result.line];
+ if (existingTypeInfo) {
+ typeInfo = existingTypeInfo.concat(typeInfo);
+ }
+ typeMap[file.unitName][result.line] = typeInfo;
+ });
+
+ typeLines.push("=== " + file.unitName + " ===\r\n");
+ for (let i = 0; i < codeLines.length; i++) {
+ const currentCodeLine = codeLines[i];
+ typeLines.push(currentCodeLine + "\r\n");
+ if (typeMap[file.unitName]) {
+ const typeInfo = typeMap[file.unitName][i];
+ if (typeInfo) {
+ typeInfo.forEach(ty => {
+ typeLines.push(">" + ty + "\r\n");
+ });
+ if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
+ }
+ else {
+ typeLines.push("\r\n");
+ }
+ }
+ }
+ else {
+ typeLines.push("No type information for this code.");
+ }
+ }
+ });
+
+ return typeLines.join("");
+ }
+ }
+
+ function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string {
+ return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : "";
+ }
+
+ export function doSourcemapBaseline(baselinePath: string, options: ts.CompilerOptions, result: CompilerResult) {
+ if (options.inlineSourceMap) {
+ if (result.sourceMaps.length > 0) {
+ throw new Error("No sourcemap files should be generated if inlineSourceMaps was set.");
+ }
+ return;
+ }
+ else if (options.sourceMap) {
+ if (result.sourceMaps.length !== result.files.length) {
+ throw new Error("Number of sourcemap files should be same as js files.");
+ }
+
+ Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js.map"), () => {
+ if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) {
+ // We need to return null here or the runBaseLine will actually create a empty file.
+ // Baselining isn't required here because there is no output.
+ /* tslint:disable:no-null-keyword */
+ return null;
+ /* tslint:enable:no-null-keyword */
+ }
+
+ let sourceMapCode = "";
+ for (let i = 0; i < result.sourceMaps.length; i++) {
+ sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n";
+ sourceMapCode += getByteOrderMarkText(result.sourceMaps[i]);
+ sourceMapCode += result.sourceMaps[i].code;
+ }
+
+ return sourceMapCode;
+ });
+ }
+ }
+
+ export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
+ if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) {
+ throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
+ }
+
+ // check js output
+ Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js"), () => {
+ let tsCode = "";
+ const tsSources = otherFiles.concat(toBeCompiled);
+ if (tsSources.length > 1) {
+ tsCode += "//// [" + header + "] ////\r\n\r\n";
+ }
+ for (let i = 0; i < tsSources.length; i++) {
+ tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n";
+ tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : "");
+ }
+
+ let jsCode = "";
+ for (let i = 0; i < result.files.length; i++) {
+ jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n";
+ jsCode += getByteOrderMarkText(result.files[i]);
+ jsCode += result.files[i].code;
+ }
+
+ if (result.declFilesCode.length > 0) {
+ jsCode += "\r\n\r\n";
+ for (let i = 0; i < result.declFilesCode.length; i++) {
+ jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n";
+ jsCode += getByteOrderMarkText(result.declFilesCode[i]);
+ jsCode += result.declFilesCode[i].code;
+ }
+ }
+
+ const declFileCompilationResult =
+ Harness.Compiler.compileDeclarationFiles(
+ toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
+
+ if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
+ jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
+ jsCode += "\r\n\r\n";
+ jsCode += Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
+ }
+
+ if (jsCode.length > 0) {
+ return tsCode + "\r\n\r\n" + jsCode;
+ }
+ else {
+ /* tslint:disable:no-null-keyword */
+ return null;
+ /* tslint:enable:no-null-keyword */
+ }
+ });
+ }
+
export function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): string {
// Collect, test, and sort the fileNames
outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName)));
diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts
index 17346016fbbd0..5720f9b541c46 100644
--- a/src/harness/rwcRunner.ts
+++ b/src/harness/rwcRunner.ts
@@ -222,7 +222,12 @@ namespace RWC {
}
});
- // TODO: Type baselines (need to refactor out from compilerRunner)
+ it("has the expected types", () => {
+ Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
+ .concat(otherFiles)
+ .filter(file => !!compilerResult.program.getSourceFile(file.unitName))
+ .filter(e => !Harness.isDefaultLibraryFile(e.unitName)));
+ });
});
}
}