• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import * as ts from "./_namespaces/ts";
2import * as compiler from "./_namespaces/compiler";
3import * as Utils from "./_namespaces/Utils";
4import { Baseline, Compiler, IO, RunnerBase, TestCaseParser, TestRunnerKind } from "./_namespaces/Harness";
5
6// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`.
7export class Test262BaselineRunner extends RunnerBase {
8    private static readonly basePath = "internal/cases/test262";
9    private static readonly helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
10    private static readonly helperFile: Compiler.TestFile = {
11        unitName: Test262BaselineRunner.helpersFilePath,
12        content: IO.readFile(Test262BaselineRunner.helpersFilePath)!,
13    };
14    private static readonly testFileExtensionRegex = /\.js$/;
15    private static readonly options: ts.CompilerOptions = {
16        allowNonTsExtensions: true,
17        target: ts.ScriptTarget.Latest,
18        module: ts.ModuleKind.CommonJS
19    };
20    private static readonly baselineOptions: Baseline.BaselineOptions = {
21        Subfolder: "test262",
22        Baselinefolder: "internal/baselines"
23    };
24
25    private static getTestFilePath(filename: string): string {
26        return Test262BaselineRunner.basePath + "/" + filename;
27    }
28
29    private runTest(filePath: string) {
30        describe("test262 test for " + filePath, () => {
31            // Mocha holds onto the closure environment of the describe callback even after the test is done.
32            // Everything declared here should be cleared out in the "after" callback.
33            let testState: {
34                filename: string;
35                compilerResult: compiler.CompilationResult;
36                inputFiles: Compiler.TestFile[];
37            };
38
39            before(() => {
40                const content = IO.readFile(filePath)!;
41                const testFilename = ts.removeFileExtension(filePath).replace(/\//g, "_") + ".test";
42                const testCaseContent = TestCaseParser.makeUnitsFromTest(content, testFilename);
43
44                const inputFiles: Compiler.TestFile[] = testCaseContent.testUnitData.map(unit => {
45                    const unitName = Test262BaselineRunner.getTestFilePath(unit.name);
46                    return { unitName, content: unit.content };
47                });
48
49                // Emit the results
50                testState = {
51                    filename: testFilename,
52                    inputFiles,
53                    compilerResult: undefined!, // TODO: GH#18217
54                };
55
56                testState.compilerResult = Compiler.compileFiles(
57                    [Test262BaselineRunner.helperFile].concat(inputFiles),
58                    /*otherFiles*/ [],
59                    /* harnessOptions */ undefined,
60                    Test262BaselineRunner.options,
61                    /* currentDirectory */ undefined);
62            });
63
64            after(() => {
65                testState = undefined!;
66            });
67
68            it("has the expected emitted code", () => {
69                const files = Array.from(testState.compilerResult.js.values()).filter(f => f.file !== Test262BaselineRunner.helpersFilePath);
70                Baseline.runBaseline(testState.filename + ".output.js", Compiler.collateOutputs(files), Test262BaselineRunner.baselineOptions);
71            });
72
73            it("has the expected errors", () => {
74                const errors = testState.compilerResult.diagnostics;
75                // eslint-disable-next-line no-null/no-null
76                const baseline = errors.length === 0 ? null : Compiler.getErrorBaseline(testState.inputFiles, errors);
77                Baseline.runBaseline(testState.filename + ".errors.txt", baseline, Test262BaselineRunner.baselineOptions);
78            });
79
80            it("satisfies invariants", () => {
81                const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
82                Utils.assertInvariants(sourceFile, /*parent:*/ undefined);
83            });
84
85            it("has the expected AST", () => {
86                const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename))!;
87                Baseline.runBaseline(testState.filename + ".AST.txt", Utils.sourceFileToJSON(sourceFile), Test262BaselineRunner.baselineOptions);
88            });
89        });
90    }
91
92    public kind(): TestRunnerKind {
93        return "test262";
94    }
95
96    public enumerateTestFiles() {
97        // see also: `enumerateTestFiles` in tests/webTestServer.ts
98        return ts.map(this.enumerateFiles(Test262BaselineRunner.basePath, Test262BaselineRunner.testFileExtensionRegex, { recursive: true }), ts.normalizePath);
99    }
100
101    public initializeTests() {
102        // this will set up a series of describe/it blocks to run between the setup and cleanup phases
103        if (this.tests.length === 0) {
104            const testFiles = this.getTestFiles();
105            testFiles.forEach(fn => {
106                this.runTest(fn);
107            });
108        }
109        else {
110            this.tests.forEach(test => this.runTest(typeof test === "string" ? test : test.file));
111        }
112    }
113}