Skip to content

Commit 7533647

Browse files
committed
Merge pull request #495 from Microsoft/rwcRunner
Simplifies RWC Runner to use HarnessCompiler.compileFiles so it can be used to baseline errors and sourcemaps more like compiler runner
2 parents 5dc017b + 2ac377c commit 7533647

File tree

6 files changed

+92
-136
lines changed

6 files changed

+92
-136
lines changed

Jakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ var harnessSources = [
7171
"fourslashRunner.ts",
7272
"projectsRunner.ts",
7373
"unittestrunner.ts",
74+
"loggedIO.ts",
7475
"rwcRunner.ts",
7576
"runner.ts"
7677
].map(function (f) {

src/harness/fourslash.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,9 +1898,9 @@ module FourSlash {
18981898
fourslashSourceFile = fourslashSourceFile || ts.createSourceFile(tsFn, Harness.IO.readFile(tsFn), ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false);
18991899

19001900
var files: { [filename: string]: ts.SourceFile; } = {};
1901-
files[fourslashFilename] = fourslashSourceFile;
1902-
files[fileName] = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false);
1903-
files[Harness.Compiler.defaultLibFileName] = Harness.Compiler.defaultLibSourceFile;
1901+
files[ts.getCanonicalFileName(fourslashFilename)] = fourslashSourceFile;
1902+
files[ts.getCanonicalFileName(fileName)] = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false);
1903+
files[ts.getCanonicalFileName(Harness.Compiler.defaultLibFileName)] = Harness.Compiler.defaultLibSourceFile;
19041904

19051905
var host = Harness.Compiler.createCompilerHost(files, (fn, contents) => result = contents);
19061906
var program = ts.createProgram([fourslashFilename, fileName], { out: "fourslashTestOutput.js" }, host);

src/harness/harness.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -539,8 +539,8 @@ module Harness {
539539
getCurrentDirectory: sys.getCurrentDirectory,
540540
getCancellationToken: (): any => undefined,
541541
getSourceFile: (fn, languageVersion) => {
542-
if (fn in filemap) {
543-
return filemap[fn];
542+
if (Object.prototype.hasOwnProperty.call(filemap, ts.getCanonicalFileName(fn))) {
543+
return filemap[ts.getCanonicalFileName(fn)];
544544
} else {
545545
var lib = defaultLibFileName;
546546
if (fn === defaultLibFileName) {
@@ -729,7 +729,7 @@ module Harness {
729729
var filemap: { [name: string]: ts.SourceFile; } = {};
730730
var register = (file: { unitName: string; content: string; }) => {
731731
var filename = Path.switchToForwardSlashes(file.unitName);
732-
filemap[filename] = ts.createSourceFile(filename, file.content, options.target);
732+
filemap[ts.getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, options.target);
733733
};
734734
inputFiles.forEach(register);
735735
otherFiles.forEach(register);
@@ -773,6 +773,21 @@ module Harness {
773773
return { filename: err.file && err.file.filename, start: err.start, end: err.start + err.length, line: errorLineInfo.line, character: errorLineInfo.character, message: err.messageText };
774774
}
775775

776+
export function minimalDiagnosticsToString(diagnostics: MinimalDiagnostic[]) {
777+
// This is copied from tsc.ts's reportError to replicate what tsc does
778+
var errors = "";
779+
ts.forEach(diagnostics, diagnotic => {
780+
if (diagnotic.filename) {
781+
errors += diagnotic.filename + "(" + diagnotic.line + "," + diagnotic.character + "): " + diagnotic.message + sys.newLine;
782+
}
783+
else {
784+
errors += diagnotic.message + sys.newLine;
785+
}
786+
});
787+
788+
return errors;
789+
}
790+
776791
export function getErrorBaseline(inputFiles: { unitName: string; content: string }[],
777792
diagnostics: MinimalDiagnostic[]
778793
) {

src/harness/loggedIO.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,6 @@ module Playback {
173173
var results = logArray.filter(e => pathsAreEquivalent(e.path, expectedPath, wrapper));
174174
if (results.length === 0) {
175175
if (defaultValue === undefined) {
176-
console.log('Resolved path: ' + wrapper.resolvePath(expectedPath));
177-
console.log('Filenames were: ' + logArray.map(x => x.path).join(', '));
178176
throw new Error('No matching result in log array for path: ' + expectedPath);
179177
} else {
180178
return defaultValue;
@@ -191,7 +189,7 @@ module Playback {
191189
}
192190

193191
function noOpReplay(name: string) {
194-
console.log("Swallowed write operation during replay: " + name);
192+
//console.log("Swallowed write operation during replay: " + name);
195193
}
196194

197195
export function wrapSystem(underlying: System): PlaybackSystem {
@@ -257,7 +255,7 @@ module Playback {
257255

258256
wrapper.resolvePath = recordReplay(wrapper.resolvePath, underlying)(
259257
(path) => callAndRecord(underlying.resolvePath(path), recordLog.pathsResolved, { path: path }),
260-
memoize((path) => findResultByFields(replayLog.pathsResolved, { path: path }, replayLog.currentDirectory ? replayLog.currentDirectory + '/' + path : path)));
258+
memoize((path) => findResultByFields(replayLog.pathsResolved, { path: path }, !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog.currentDirectory ? replayLog.currentDirectory + '/' + path : ts.normalizeSlashes(path))));
261259

262260
wrapper.readFile = recordReplay(wrapper.readFile, underlying)(
263261
(path) => callAndRecord(underlying.readFile(path), recordLog.filesRead, { path: path, codepage: 0 }),

src/harness/projectsRunner.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -293,27 +293,13 @@ class ProjectRunner extends RunnerBase {
293293
}
294294

295295
function getErrorsBaseline(compilerResult: CompileProjectFilesResult) {
296-
// This is copied from tc.ts's reportError to replicate what tc does
297-
var errors = "";
298-
for (var i = 0; i < compilerResult.errors.length; i++) {
299-
var error = compilerResult.errors[i];
300-
// TODO(jfreeman): Remove assert
301-
ts.Debug.assert(error.messageText.indexOf("{NL}") < 0);
302-
if (error.file) {
303-
var loc = error.file.getLineAndCharacterFromPosition(error.start);
304-
errors += error.file.filename + "(" + loc.line + "," + loc.character + "): " + error.messageText + sys.newLine;
305-
}
306-
else {
307-
errors += error.messageText + sys.newLine;
308-
}
309-
}
310-
311296
var inputFiles = ts.map(ts.filter(compilerResult.program.getSourceFiles(),
312297
sourceFile => sourceFile.filename !== "lib.d.ts"),
313298
sourceFile => {
314299
return { unitName: sourceFile.filename, content: sourceFile.text };
315300
});
316301
var diagnostics = ts.map(compilerResult.errors, error => Harness.Compiler.getMinimalDiagnostic(error));
302+
var errors = Harness.Compiler.minimalDiagnosticsToString(diagnostics);
317303
errors += sys.newLine + sys.newLine + Harness.Compiler.getErrorBaseline(inputFiles, diagnostics);
318304

319305
return errors;

src/harness/rwcRunner.ts

Lines changed: 67 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,6 @@
55
/// <reference path='..\compiler\commandLineParser.ts'/>
66

77
module RWC {
8-
class RWCEmitter implements Harness.Compiler.IEmitterIOHost {
9-
public outputs: { [filename: string]: string; } = {};
10-
11-
constructor() { }
12-
13-
writeFile(path: string, contents: string, writeByteOrderMark: boolean) {
14-
if (path in this.outputs) throw new Error('Emitter attempted to write to "' + path + '" twice');
15-
this.outputs[path] = contents;
16-
}
17-
18-
directoryExists(s: string) {
19-
return false;
20-
}
21-
fileExists(s: string) {
22-
return true;
23-
}
24-
resolvePath(s: string) {
25-
return s;
26-
}
27-
}
28-
298
function runWithIOLog(ioLog: IOLog, fn: () => void) {
309
var oldSys = sys;
3110

@@ -41,32 +20,26 @@ module RWC {
4120
}
4221
}
4322

44-
function collateOutputs(emitterIOHost: RWCEmitter, fnTest: (s: string) => {}, clean?: (s: string) => string) {
23+
function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[], clean?: (s: string) => string) {
4524
// Collect, test, and sort the filenames
46-
var files: string[] = [];
47-
for (var fn in emitterIOHost.outputs) {
48-
if (emitterIOHost.outputs.hasOwnProperty(fn) && fnTest(fn)) {
49-
files.push(fn);
50-
}
51-
}
5225
function cleanName(fn: string) {
5326
var lastSlash = Harness.Path.switchToForwardSlashes(fn).lastIndexOf('/');
5427
return fn.substr(lastSlash + 1).toLowerCase();
5528
}
56-
files.sort((a, b) => cleanName(a).localeCompare(cleanName(b)));
29+
outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName)));
5730

5831
// Emit them
5932
var result = '';
60-
files.forEach(fn => {
33+
ts.forEach(outputFiles, outputFile => {
6134
// Some extra spacing if this isn't the first file
6235
if (result.length) result = result + '\r\n\r\n';
6336

6437
// Filename header + content
65-
result = result + '/*====== ' + fn + ' ======*/\r\n';
38+
result = result + '/*====== ' + outputFile.fileName + ' ======*/\r\n';
6639
if (clean) {
67-
result = result + clean(emitterIOHost.outputs[fn]);
40+
result = result + clean(outputFile.code);
6841
} else {
69-
result = result + emitterIOHost.outputs[fn];
42+
result = result + outputFile.code;
7043
}
7144
});
7245
return result;
@@ -86,90 +59,54 @@ module RWC {
8659
});
8760
});
8861

89-
var emitterIOHost = new RWCEmitter();
62+
var inputFiles: { unitName: string; content: string; }[] = [];
63+
var otherFiles: { unitName: string; content: string; }[] = [];
64+
var compilerResult: Harness.Compiler.CompilerResult;
9065
it('can compile', () => {
9166
runWithIOLog(ioLog, () => {
9267
harnessCompiler.reset();
93-
var inputList: string[] = opts.filenames;
94-
var noDefaultLib = false;
95-
var libPath = Harness.IO.directoryName(sys.getExecutingFilePath()) + '/lib.d.ts';
96-
97-
if (!opts.options.noResolve) {
98-
var filemap: any = {};
99-
var host: ts.CompilerHost = {
100-
getCurrentDirectory: () => sys.getCurrentDirectory(),
101-
getCancellationToken: (): any => undefined,
102-
getSourceFile: (fileName, languageVersion) => {
103-
var fileContents: string;
104-
try {
105-
if (libPath === fileName) {
106-
fileContents = Harness.IO.readFile(Harness.libFolder + "lib.d.ts");
107-
}
108-
else {
109-
fileContents = sys.readFile(fileName);
110-
}
111-
}
112-
catch (e) {
113-
// Leave fileContents undefined;
114-
}
115-
return ts.createSourceFile(fileName, fileContents, languageVersion);
116-
},
117-
getDefaultLibFilename: () => libPath,
118-
writeFile: (fn, contents) => emitterIOHost.writeFile(fn, contents, false),
119-
getCanonicalFileName: ts.getCanonicalFileName,
120-
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
121-
getNewLine: () => sys.newLine
122-
};
123-
124-
var resolvedProgram = ts.createProgram(opts.filenames, opts.options, host);
125-
resolvedProgram.getSourceFiles().forEach(sourceFile => {
126-
noDefaultLib = noDefaultLib || sourceFile.hasNoDefaultLib;
127-
if (inputList.indexOf(sourceFile.filename) === -1) {
128-
inputList.push(sourceFile.filename);
129-
}
130-
});
131-
}
132-
133-
if (!opts.options.noLib && !noDefaultLib) {
134-
inputList.push(libPath);
135-
}
136-
137-
harnessCompiler.reset();
138-
harnessCompiler.setCompilerSettingsFromOptions(opts.options);
13968

14069
// Load the files
141-
inputList.forEach((item: string) => {
142-
var resolvedPath = libPath === item ? item : Harness.Path.switchToForwardSlashes(sys.resolvePath(item));
143-
try {
144-
if (libPath === item) {
145-
var content = Harness.IO.readFile(Harness.libFolder + "lib.d.ts");
146-
}
147-
else {
148-
var content = sys.readFile(resolvedPath);
149-
}
70+
ts.forEach(opts.filenames, fileName => {
71+
inputFiles.push(getHarnessCompilerInputUnit(fileName));
72+
});
73+
74+
if (!opts.options.noLib) {
75+
// Find the lib.d.ts file in the input file and add it to the input files list
76+
var libFile = ts.forEach(ioLog.filesRead, fileRead=> Harness.isLibraryFile(fileRead.path) ? fileRead.path : undefined);
77+
if (libFile) {
78+
inputFiles.push(getHarnessCompilerInputUnit(libFile));
15079
}
151-
catch (e) {
152-
// Leave content undefined.
80+
}
81+
82+
ts.forEach(ioLog.filesRead, fileRead => {
83+
var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileRead.path));
84+
var inInputList = ts.forEach(inputFiles, inputFile=> inputFile.unitName === resolvedPath);
85+
if (!inInputList) {
86+
// Add the file to other files
87+
otherFiles.push(getHarnessCompilerInputUnit(fileRead.path));
15388
}
154-
harnessCompiler.addInputFile({ unitName: resolvedPath, content: content });
15589
});
15690

157-
harnessCompiler.setCompilerOptions();
91+
// do not use lib since we shouldnt be reading any files that arent in the ioLog
92+
opts.options.noLib = true;
15893

15994
// Emit the results
160-
harnessCompiler.emitAll(emitterIOHost);
161-
var compilationErrors = harnessCompiler.reportCompilationErrors();
162-
163-
// Create an error baseline
164-
compilationErrors.forEach(err => {
165-
if (err.filename) {
166-
errors += err.filename + ' (' + err.line + "," + err.character + "): " + err.message + '\r\n';
167-
}
168-
else {
169-
errors += err.message + '\r\n';
170-
}
171-
});
95+
harnessCompiler.compileFiles(inputFiles, otherFiles, compileResult => {
96+
compilerResult = compileResult;
97+
}, /*settingsCallback*/ undefined, opts.options);
17298
});
99+
100+
function getHarnessCompilerInputUnit(fileName: string) {
101+
var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileName));
102+
try {
103+
var content = sys.readFile(resolvedPath);
104+
}
105+
catch (e) {
106+
// Leave content undefined.
107+
}
108+
return { unitName: resolvedPath, content: content };
109+
}
173110
});
174111

175112
// Baselines
@@ -178,27 +115,46 @@ module RWC {
178115

179116
it('has the expected emitted code', () => {
180117
Harness.Baseline.runBaseline('has the expected emitted code', baseName + '.output.js', () => {
181-
return collateOutputs(emitterIOHost, fn => Harness.Compiler.isJS(fn), s => SyntacticCleaner.clean(s));
118+
return collateOutputs(compilerResult.files, s => SyntacticCleaner.clean(s));
182119
}, false, baselineOpts);
183120
});
184121

185122
it('has the expected declaration file content', () => {
186123
Harness.Baseline.runBaseline('has the expected declaration file content', baseName + '.d.ts', () => {
187-
var result = collateOutputs(emitterIOHost, fn => Harness.Compiler.isDTS(fn));
188-
return result.length > 0 ? result : null;
124+
if (compilerResult.errors.length || !compilerResult.declFilesCode.length) {
125+
return null;
126+
}
127+
return collateOutputs(compilerResult.declFilesCode);
189128
}, false, baselineOpts);
190129
});
191130

192131
it('has the expected source maps', () => {
193132
Harness.Baseline.runBaseline('has the expected source maps', baseName + '.map', () => {
194-
var result = collateOutputs(emitterIOHost, fn => fn.substr(fn.length - '.map'.length) === '.map');
195-
return result.length > 0 ? result : null;
133+
if (!compilerResult.sourceMaps.length) {
134+
return null;
135+
}
136+
137+
return collateOutputs(compilerResult.sourceMaps);
196138
}, false, baselineOpts);
197139
});
198140

141+
it('has correct source map record', () => {
142+
if (compilerResult.sourceMapRecord) {
143+
Harness.Baseline.runBaseline('has correct source map record', baseName + '.sourcemap.txt', () => {
144+
return compilerResult.sourceMapRecord;
145+
}, false, baselineOpts);
146+
}
147+
});
148+
199149
it('has the expected errors', () => {
200150
Harness.Baseline.runBaseline('has the expected errors', baseName + '.errors.txt', () => {
201-
return errors.length > 0 ? errors : null;
151+
if (compilerResult.errors.length === 0) {
152+
return null;
153+
}
154+
155+
return Harness.Compiler.minimalDiagnosticsToString(compilerResult.errors) +
156+
sys.newLine + sys.newLine +
157+
Harness.Compiler.getErrorBaseline(inputFiles.concat(otherFiles), compilerResult.errors);
202158
}, false, baselineOpts);
203159
});
204160

0 commit comments

Comments
 (0)