diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7f5f3688817..18d34e94b03 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1434,6 +1434,13 @@ module FourSlash { this.raiseError('Mismatched incremental/reference syntactic diagnostics for file ' + this.activeFile.fileName + '.\n=== Incremental diagnostics ===\n' + incrementalSyntaxDiagnostics + '\n=== Reference Diagnostics ===\n' + referenceSyntaxDiagnostics); } + var incrementalSourceFileJSON = Utils.sourceFileToJSON(incrementalSourceFile); + var referenceSourceFileJSON = Utils.sourceFileToJSON(referenceSourceFile); + + if (incrementalSyntaxDiagnostics !== referenceSyntaxDiagnostics) { + this.raiseError('Mismatched incremental/reference ast for file ' + this.activeFile.fileName + '.\n=== Incremental AST ===\n' + incrementalSourceFileJSON + '\n=== Reference AST ===\n' + referenceSourceFileJSON); + } + //if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { // var compiler = new TypeScript.TypeScriptCompiler(); // for (var i = 0; i < this.testData.files.length; i++) { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 095b0702b12..61e5fcbee65 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -189,6 +189,101 @@ module Utils { code: diagnostic.code }; } + + export function sourceFileToJSON(file: ts.SourceFile): string { + return JSON.stringify(file,(k, v) => { + return isNodeOrArray(v) ? serializeNode(v) : v; + }, " "); + + function getKindName(k: number): string { + return (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((ts).NodeFlags, f); } + function getParserContextFlagName(f: number) { return getFlagName((ts).ParserContextFlags, f); } + + function serializeNode(n: ts.Node): any { + var o: any = { kind: getKindName(n.kind) }; + o.containsParseError = ts.containsParseError(n); + + 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": + case "scriptSnapshot": + // 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] = Utils.convertDiagnostics((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] = (n)[propertyName]; + } + break; + + default: + o[propertyName] = (n)[propertyName]; + } + + return undefined; + }); + + return o; + } + } } module Harness.Path { diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index f6ba448015b..7e5bafde228 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -21,104 +21,6 @@ class Test262BaselineRunner extends RunnerBase { return Test262BaselineRunner.basePath + "/" + filename; } - private static serializeSourceFile(file: ts.SourceFile): string { - function getKindName(k: number): string { - return (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((ts).NodeFlags, f); } - function getParserContextFlagName(f: number) { return getFlagName((ts).ParserContextFlags, f); } - - function serializeNode(n: ts.Node): any { - var o: any = { kind: getKindName(n.kind) }; - o.containsParseError = ts.containsParseError(n); - - 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] = Utils.convertDiagnostics((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] = (n)[propertyName]; - } - break; - - default: - o[propertyName] = (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. @@ -183,7 +85,7 @@ class Test262BaselineRunner extends RunnerBase { 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); + return Utils.sourceFileToJSON(sourceFile); }, false, Test262BaselineRunner.baselineOptions); }); });