Files
TypeScript/src/harness/test262Runner.ts
Cyrus Najmabadi dd2c869d7b Use chai asserts.
2014-12-09 19:49:40 -08:00

216 lines
9.0 KiB
TypeScript

/// <reference path='harness.ts' />
/// <reference path='runnerbase.ts' />
/// <reference path='syntacticCleaner.ts' />
class Test262BaselineRunner extends RunnerBase {
private static basePath = 'tests/cases/test262';
private static helpersFilePath = 'tests/cases/test262-harness/helpers.d.ts';
private static helperFile = {
unitName: Test262BaselineRunner.helpersFilePath,
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath)
};
private static testFileExtensionRegex = /\.js$/;
private static options: ts.CompilerOptions = {
allowNonTsExtensions: true,
target: ts.ScriptTarget.Latest,
module: ts.ModuleKind.CommonJS
};
private static baselineOptions: Harness.Baseline.BaselineOptions = { Subfolder: 'test262' };
private static getTestFilePath(filename: string): string {
return Test262BaselineRunner.basePath + "/" + filename;
}
private static serializeSourceFile(file: ts.SourceFile): string {
function getKindName(k: number): string {
return (<any>ts).SyntaxKind[k]
}
function getFlagName(flags: any, f: number): any {
if (f === 0) {
return 0;
}
var result = "";
ts.forEach(Object.getOwnPropertyNames(flags), (v: any) => {
if (isFinite(v)) {
v = +v;
if (f === +v) {
result = flags[v];
return true;
}
else if ((f & v) > 0) {
if (result.length)
result += " | ";
result += flags[v];
return false;
}
}
});
return result;
}
function getNodeFlagName(f: number) { return getFlagName((<any>ts).NodeFlags, f); }
function getParserContextFlagName(f: number) { return getFlagName((<any>ts).ParserContextFlags, f); }
function convertDiagnostics(diagnostics: ts.Diagnostic[]) {
return diagnostics.map(convertDiagnostic);
}
function convertDiagnostic(diagnostic: ts.Diagnostic): any {
return {
start: diagnostic.start,
length: diagnostic.length,
messageText: diagnostic.messageText,
category: (<any>ts).DiagnosticCategory[diagnostic.category],
code: diagnostic.code
};
}
function serializeNode(n: ts.Node): any {
var o: any = { kind: getKindName(n.kind) };
ts.forEach(Object.getOwnPropertyNames(n), propertyName => {
switch (propertyName) {
case "parent":
case "symbol":
case "locals":
case "localSymbol":
case "kind":
case "semanticDiagnostics":
case "id":
case "nodeCount":
case "symbolCount":
case "identifierCount":
// Blacklist of items we never put in the baseline file.
break;
case "flags":
// Print out flags with their enum names.
o[propertyName] = getNodeFlagName(n.flags);
break;
case "parserContextFlags":
o[propertyName] = getParserContextFlagName(n.parserContextFlags);
break;
case "referenceDiagnostics":
case "parseDiagnostics":
case "grammarDiagnostics":
o[propertyName] = convertDiagnostics((<any>n)[propertyName]);
break;
case "nextContainer":
if (n.nextContainer) {
o[propertyName] = { kind: n.nextContainer.kind, pos: n.nextContainer.pos, end: n.nextContainer.end };
}
break;
case "text":
// Include 'text' field for identifiers/literals, but not for source files.
if (n.kind !== ts.SyntaxKind.SourceFile) {
o[propertyName] = (<any>n)[propertyName];
}
break;
default:
o[propertyName] = (<any>n)[propertyName];
}
return undefined;
});
return o;
}
return JSON.stringify(file, (k, v) => {
return Test262BaselineRunner.isNodeOrArray(v) ? serializeNode(v) : v;
}, " ");
}
private static isNodeOrArray(a: any): boolean {
return a !== undefined && typeof a.pos === "number";
}
private runTest(filePath: string) {
describe('test262 test for ' + filePath, () => {
// Mocha holds onto the closure environment of the describe callback even after the test is done.
// Everything declared here should be cleared out in the "after" callback.
var testState: {
filename: string;
compilerResult: Harness.Compiler.CompilerResult;
inputFiles: { unitName: string; content: string }[];
checker: ts.TypeChecker;
};
before(() => {
var content = Harness.IO.readFile(filePath);
var testFilename = ts.removeFileExtension(filePath).replace(/\//g, '_') + ".test";
var testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, testFilename);
var inputFiles = testCaseContent.testUnitData.map(unit => {
return { unitName: Test262BaselineRunner.getTestFilePath(unit.name), content: unit.content };
});
// Emit the results
testState = {
filename: testFilename,
inputFiles: inputFiles,
compilerResult: undefined,
checker: undefined,
};
Harness.Compiler.getCompiler().compileFiles([Test262BaselineRunner.helperFile].concat(inputFiles), /*otherFiles*/ [], (compilerResult, checker) => {
testState.compilerResult = compilerResult;
testState.checker = checker;
}, /*settingsCallback*/ undefined, Test262BaselineRunner.options);
});
after(() => {
testState = undefined;
});
it('has the expected emitted code', () => {
Harness.Baseline.runBaseline('has the expected emitted code', testState.filename + '.output.js', () => {
var files = testState.compilerResult.files.filter(f=> f.fileName !== Test262BaselineRunner.helpersFilePath);
return Harness.Compiler.collateOutputs(files, s => SyntacticCleaner.clean(s));
}, false, Test262BaselineRunner.baselineOptions);
});
it('has the expected errors', () => {
Harness.Baseline.runBaseline('has the expected errors', testState.filename + '.errors.txt', () => {
var errors = testState.compilerResult.errors;
if (errors.length === 0) {
return null;
}
return Harness.Compiler.getErrorBaseline(testState.inputFiles, errors);
}, false, Test262BaselineRunner.baselineOptions);
});
it('satisfies invariants', () => {
var sourceFile = testState.checker.getProgram().getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
Utils.assertInvariants(sourceFile, /*parent:*/ undefined);
});
it('has the expected AST',() => {
Harness.Baseline.runBaseline('has the expected AST', testState.filename + '.AST.txt',() => {
var sourceFile = testState.checker.getProgram().getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
return Test262BaselineRunner.serializeSourceFile(sourceFile);
}, false, Test262BaselineRunner.baselineOptions);
});
});
}
public initializeTests() {
// this will set up a series of describe/it blocks to run between the setup and cleanup phases
if (this.tests.length === 0) {
var testFiles = this.enumerateFiles(Test262BaselineRunner.basePath, Test262BaselineRunner.testFileExtensionRegex, { recursive: true });
testFiles.forEach(fn => {
this.runTest(ts.normalizePath(fn));
});
}
else {
this.tests.forEach(test => this.runTest(test));
}
}
}