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