From 4f4e249a042d4fb0365c588b6550ad3ae0ccf268 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 Dec 2014 14:03:31 -0800 Subject: [PATCH] Add tree invariant checking to the test262 runner. --- src/harness/test262Runner.ts | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index 756ff82ef97..fa4dc14e213 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -21,6 +21,38 @@ class Test262BaselineRunner extends RunnerBase { return Test262BaselineRunner.basePath + "/" + filename; } + private static checkInvariants(node: ts.Node, parent: ts.Node): void { + if (node) { + if (node.pos < 0) { + throw new Error("node.pos < 0"); + } + if (node.end < 0) { + throw new Error("node.end < 0"); + } + if (node.end < node.pos) { + throw new Error("node.end < node.pos"); + } + if (node.parent !== parent) { + throw new Error("node.parent !== parent"); + } + ts.forEachChild(node, child => { + Test262BaselineRunner.checkInvariants(child, node); + }); + + var childNodesAndArrays: any[] = []; + ts.forEachChild(node, child => { childNodesAndArrays.push(child) }, array => { childNodesAndArrays.push(array) }); + + for (var childName in node) { + var child = (node)[childName]; + if (Test262BaselineRunner.isNodeOrArray(child)) { + if (childNodesAndArrays.indexOf(child) < 0) { + throw new Error("Child when forEach'ing over node. " + (ts).SyntaxKind[node.kind] + "-" + childName); + } + } + } + } + } + private static serializeSourceFile(file: ts.SourceFile): string { function getKindName(k: number): string { return (ts).SyntaxKind[k] @@ -89,11 +121,15 @@ class Test262BaselineRunner extends RunnerBase { return o; } - return JSON.stringify(file,(k, v) => { - return (v && typeof v.pos === "number") ? serializeNode(v) : v; + 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. @@ -150,6 +186,11 @@ class Test262BaselineRunner extends RunnerBase { }, false, Test262BaselineRunner.baselineOptions); }); + it('satisfies invariants', () => { + var sourceFile = testState.checker.getProgram().getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); + Test262BaselineRunner.checkInvariants(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));