diff --git a/Jakefile b/Jakefile index 060690589b6..e754f5baad9 100644 --- a/Jakefile +++ b/Jakefile @@ -71,6 +71,7 @@ var harnessSources = [ "fourslashRunner.ts", "projectsRunner.ts", "unittestrunner.ts", + "loggedIO.ts", "rwcRunner.ts", "runner.ts" ].map(function (f) { diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 0fa27f0d1fa..a8b8bb6cc5c 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1898,9 +1898,9 @@ module FourSlash { fourslashSourceFile = fourslashSourceFile || ts.createSourceFile(tsFn, Harness.IO.readFile(tsFn), ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false); var files: { [filename: string]: ts.SourceFile; } = {}; - files[fourslashFilename] = fourslashSourceFile; - files[fileName] = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false); - files[Harness.Compiler.defaultLibFileName] = Harness.Compiler.defaultLibSourceFile; + files[ts.getCanonicalFileName(fourslashFilename)] = fourslashSourceFile; + files[ts.getCanonicalFileName(fileName)] = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false); + files[ts.getCanonicalFileName(Harness.Compiler.defaultLibFileName)] = Harness.Compiler.defaultLibSourceFile; var host = Harness.Compiler.createCompilerHost(files, (fn, contents) => result = contents); var program = ts.createProgram([fourslashFilename, fileName], { out: "fourslashTestOutput.js" }, host); diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 87036db292b..b273a87e418 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -539,8 +539,8 @@ module Harness { getCurrentDirectory: sys.getCurrentDirectory, getCancellationToken: (): any => undefined, getSourceFile: (fn, languageVersion) => { - if (fn in filemap) { - return filemap[fn]; + if (ts.getCanonicalFileName(fn) in filemap) { + return filemap[ts.getCanonicalFileName(fn)]; } else { var lib = defaultLibFileName; if (fn === defaultLibFileName) { @@ -726,7 +726,7 @@ module Harness { var filemap: { [name: string]: ts.SourceFile; } = {}; var register = (file: { unitName: string; content: string; }) => { var filename = Path.switchToForwardSlashes(file.unitName); - filemap[filename] = ts.createSourceFile(filename, file.content, options.target); + filemap[ts.getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, options.target); }; inputFiles.forEach(register); otherFiles.forEach(register); @@ -770,6 +770,21 @@ module Harness { return { filename: err.file && err.file.filename, start: err.start, end: err.start + err.length, line: errorLineInfo.line, character: errorLineInfo.character, message: err.messageText }; } + export function minimalDiagnosticsToString(diagnostics: MinimalDiagnostic[]) { + // This is copied from tsc.ts's reportError to replicate what tsc does + var errors = ""; + ts.forEach(diagnostics, diagnotic => { + if (diagnotic.filename) { + errors += diagnotic.filename + "(" + diagnotic.line + "," + diagnotic.character + "): " + diagnotic.message + sys.newLine; + } + else { + errors += diagnotic.message + sys.newLine; + } + }); + + return errors; + } + export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: MinimalDiagnostic[] ) { diff --git a/src/harness/loggedIO.ts b/src/harness/loggedIO.ts index 5dfd10dfa02..dbc3cdbec2c 100644 --- a/src/harness/loggedIO.ts +++ b/src/harness/loggedIO.ts @@ -173,8 +173,6 @@ module Playback { var results = logArray.filter(e => pathsAreEquivalent(e.path, expectedPath, wrapper)); if (results.length === 0) { if (defaultValue === undefined) { - console.log('Resolved path: ' + wrapper.resolvePath(expectedPath)); - console.log('Filenames were: ' + logArray.map(x => x.path).join(', ')); throw new Error('No matching result in log array for path: ' + expectedPath); } else { return defaultValue; @@ -191,7 +189,7 @@ module Playback { } function noOpReplay(name: string) { - console.log("Swallowed write operation during replay: " + name); + //console.log("Swallowed write operation during replay: " + name); } export function wrapSystem(underlying: System): PlaybackSystem { @@ -257,7 +255,7 @@ module Playback { wrapper.resolvePath = recordReplay(wrapper.resolvePath, underlying)( (path) => callAndRecord(underlying.resolvePath(path), recordLog.pathsResolved, { path: path }), - memoize((path) => findResultByFields(replayLog.pathsResolved, { path: path }, replayLog.currentDirectory ? replayLog.currentDirectory + '/' + path : path))); + memoize((path) => findResultByFields(replayLog.pathsResolved, { path: path }, !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog.currentDirectory ? replayLog.currentDirectory + '/' + path : ts.normalizeSlashes(path)))); wrapper.readFile = recordReplay(wrapper.readFile, underlying)( (path) => callAndRecord(underlying.readFile(path), recordLog.filesRead, { path: path, codepage: 0 }), diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index c192c3acecf..aa88dbee6a2 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -293,27 +293,13 @@ class ProjectRunner extends RunnerBase { } function getErrorsBaseline(compilerResult: CompileProjectFilesResult) { - // This is copied from tc.ts's reportError to replicate what tc does - var errors = ""; - for (var i = 0; i < compilerResult.errors.length; i++) { - var error = compilerResult.errors[i]; - // TODO(jfreeman): Remove assert - ts.Debug.assert(error.messageText.indexOf("{NL}") < 0); - if (error.file) { - var loc = error.file.getLineAndCharacterFromPosition(error.start); - errors += error.file.filename + "(" + loc.line + "," + loc.character + "): " + error.messageText + sys.newLine; - } - else { - errors += error.messageText + sys.newLine; - } - } - var inputFiles = ts.map(ts.filter(compilerResult.program.getSourceFiles(), sourceFile => sourceFile.filename !== "lib.d.ts"), sourceFile => { return { unitName: sourceFile.filename, content: sourceFile.text }; }); var diagnostics = ts.map(compilerResult.errors, error => Harness.Compiler.getMinimalDiagnostic(error)); + var errors = Harness.Compiler.minimalDiagnosticsToString(diagnostics); errors += sys.newLine + sys.newLine + Harness.Compiler.getErrorBaseline(inputFiles, diagnostics); return errors; diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index b8d25b890e6..be6787ae0d6 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -5,27 +5,6 @@ /// module RWC { - class RWCEmitter implements Harness.Compiler.IEmitterIOHost { - public outputs: { [filename: string]: string; } = {}; - - constructor() { } - - writeFile(path: string, contents: string, writeByteOrderMark: boolean) { - if (path in this.outputs) throw new Error('Emitter attempted to write to "' + path + '" twice'); - this.outputs[path] = contents; - } - - directoryExists(s: string) { - return false; - } - fileExists(s: string) { - return true; - } - resolvePath(s: string) { - return s; - } - } - function runWithIOLog(ioLog: IOLog, fn: () => void) { var oldSys = sys; @@ -41,32 +20,26 @@ module RWC { } } - function collateOutputs(emitterIOHost: RWCEmitter, fnTest: (s: string) => {}, clean?: (s: string) => string) { + function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[], clean?: (s: string) => string) { // Collect, test, and sort the filenames - var files: string[] = []; - for (var fn in emitterIOHost.outputs) { - if (emitterIOHost.outputs.hasOwnProperty(fn) && fnTest(fn)) { - files.push(fn); - } - } function cleanName(fn: string) { var lastSlash = Harness.Path.switchToForwardSlashes(fn).lastIndexOf('/'); return fn.substr(lastSlash + 1).toLowerCase(); } - files.sort((a, b) => cleanName(a).localeCompare(cleanName(b))); + outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName))); // Emit them var result = ''; - files.forEach(fn => { + ts.forEach(outputFiles, outputFile => { // Some extra spacing if this isn't the first file if (result.length) result = result + '\r\n\r\n'; // Filename header + content - result = result + '/*====== ' + fn + ' ======*/\r\n'; + result = result + '/*====== ' + outputFile.fileName + ' ======*/\r\n'; if (clean) { - result = result + clean(emitterIOHost.outputs[fn]); + result = result + clean(outputFile.code); } else { - result = result + emitterIOHost.outputs[fn]; + result = result + outputFile.code; } }); return result; @@ -86,90 +59,54 @@ module RWC { }); }); - var emitterIOHost = new RWCEmitter(); + var compilerResult: Harness.Compiler.CompilerResult; it('can compile', () => { runWithIOLog(ioLog, () => { harnessCompiler.reset(); - var inputList: string[] = opts.filenames; - var noDefaultLib = false; - var libPath = Harness.IO.directoryName(sys.getExecutingFilePath()) + '/lib.d.ts'; - - if (!opts.options.noResolve) { - var filemap: any = {}; - var host: ts.CompilerHost = { - getCurrentDirectory: () => sys.getCurrentDirectory(), - getCancellationToken: (): any => undefined, - getSourceFile: (fileName, languageVersion) => { - var fileContents: string; - try { - if (libPath === fileName) { - fileContents = Harness.IO.readFile(Harness.libFolder + "lib.d.ts"); - } - else { - fileContents = sys.readFile(fileName); - } - } - catch (e) { - // Leave fileContents undefined; - } - return ts.createSourceFile(fileName, fileContents, languageVersion); - }, - getDefaultLibFilename: () => libPath, - writeFile: (fn, contents) => emitterIOHost.writeFile(fn, contents, false), - getCanonicalFileName: ts.getCanonicalFileName, - useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames, - getNewLine: () => sys.newLine - }; - - var resolvedProgram = ts.createProgram(opts.filenames, opts.options, host); - resolvedProgram.getSourceFiles().forEach(sourceFile => { - noDefaultLib = noDefaultLib || sourceFile.hasNoDefaultLib; - if (inputList.indexOf(sourceFile.filename) === -1) { - inputList.push(sourceFile.filename); - } - }); - } - - if (!opts.options.noLib && !noDefaultLib) { - inputList.push(libPath); - } - - harnessCompiler.reset(); - harnessCompiler.setCompilerSettingsFromOptions(opts.options); // Load the files - inputList.forEach((item: string) => { - var resolvedPath = libPath === item ? item : Harness.Path.switchToForwardSlashes(sys.resolvePath(item)); - try { - if (libPath === item) { - var content = Harness.IO.readFile(Harness.libFolder + "lib.d.ts"); - } - else { - var content = sys.readFile(resolvedPath); - } - } - catch (e) { - // Leave content undefined. - } - harnessCompiler.addInputFile({ unitName: resolvedPath, content: content }); + var inputFiles: { unitName: string; content: string; }[] = []; + ts.forEach(opts.filenames, fileName => { + inputFiles.push(getHarnessCompilerInputUnit(fileName)); }); - harnessCompiler.setCompilerOptions(); + if (!opts.options.noLib) { + // Find the lib.d.ts file in the input file and add it to the input files list + var libFile = ts.forEach(ioLog.filesRead, fileRead=> Harness.isLibraryFile(fileRead.path) ? fileRead.path : undefined); + if (libFile) { + inputFiles.push(getHarnessCompilerInputUnit(libFile)); + } + } + + var otherFiles: { unitName: string; content: string; }[] = []; + ts.forEach(ioLog.filesRead, fileRead => { + var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileRead.path)); + var inInputList = ts.forEach(inputFiles, inputFile=> inputFile.unitName === resolvedPath); + if (!inInputList) { + // Add the file to other files + otherFiles.push(getHarnessCompilerInputUnit(fileRead.path)); + } + }); + + // do not use lib since we shouldnt be reading any files that arent in the ioLog + opts.options.noLib = true; // Emit the results - harnessCompiler.emitAll(emitterIOHost); - var compilationErrors = harnessCompiler.reportCompilationErrors(); - - // Create an error baseline - compilationErrors.forEach(err => { - if (err.filename) { - errors += err.filename + ' (' + err.line + "," + err.character + "): " + err.message + '\r\n'; - } - else { - errors += err.message + '\r\n'; - } - }); + harnessCompiler.compileFiles(inputFiles, otherFiles, compileResult => { + compilerResult = compileResult; + }, /*settingsCallback*/ undefined, opts.options); }); + + function getHarnessCompilerInputUnit(fileName: string) { + var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileName)); + try { + var content = sys.readFile(resolvedPath); + } + catch (e) { + // Leave content undefined. + } + return { unitName: resolvedPath, content: content }; + } }); // Baselines @@ -178,27 +115,36 @@ module RWC { it('has the expected emitted code', () => { Harness.Baseline.runBaseline('has the expected emitted code', baseName + '.output.js', () => { - return collateOutputs(emitterIOHost, fn => Harness.Compiler.isJS(fn), s => SyntacticCleaner.clean(s)); + return collateOutputs(compilerResult.files, s => SyntacticCleaner.clean(s)); }, false, baselineOpts); }); it('has the expected declaration file content', () => { Harness.Baseline.runBaseline('has the expected declaration file content', baseName + '.d.ts', () => { - var result = collateOutputs(emitterIOHost, fn => Harness.Compiler.isDTS(fn)); - return result.length > 0 ? result : null; + if (compilerResult.errors.length || !compilerResult.declFilesCode.length) { + return null; + } + return collateOutputs(compilerResult.declFilesCode); }, false, baselineOpts); }); it('has the expected source maps', () => { Harness.Baseline.runBaseline('has the expected source maps', baseName + '.map', () => { - var result = collateOutputs(emitterIOHost, fn => fn.substr(fn.length - '.map'.length) === '.map'); - return result.length > 0 ? result : null; + if (!compilerResult.sourceMaps.length) { + return null; + } + + return collateOutputs(compilerResult.sourceMaps); }, false, baselineOpts); }); it('has the expected errors', () => { Harness.Baseline.runBaseline('has the expected errors', baseName + '.errors.txt', () => { - return errors.length > 0 ? errors : null; + if (compilerResult.errors.length === 0) { + return null; + } + + return Harness.Compiler.minimalDiagnosticsToString(compilerResult.errors); }, false, baselineOpts); });