From 570d8d3c73f641eb20a52646265fc680d7b752de Mon Sep 17 00:00:00 2001 From: Sebastian Mayr Date: Sat, 1 Jun 2019 16:34:25 +0200 Subject: [PATCH] Use IDLHarness to test URL interface --- .eslintrc.json | 2 +- test/.eslintrc | 3 + test/harness.test.js | 170 ++++++++++++++++++++++++++++++++++++ test/implementations/URL.js | 3 + 4 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 test/.eslintrc create mode 100644 test/harness.test.js create mode 100644 test/implementations/URL.js diff --git a/.eslintrc.json b/.eslintrc.json index 243aa041..1256188f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,7 +5,7 @@ "es6": true }, "parserOptions": { - "ecmaVersion": 6 + "ecmaVersion": 2019 }, "rules": { // Possible errors diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 00000000..a0b3a037 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,3 @@ +{ + "env": { "jest": true } +} diff --git a/test/harness.test.js b/test/harness.test.js new file mode 100644 index 00000000..a887860a --- /dev/null +++ b/test/harness.test.js @@ -0,0 +1,170 @@ +"use strict"; + +const { readFileSync, promises: fs } = require("fs"); +const path = require("path"); +const vm = require("vm"); + +process.on("unhandledRejection", e => { + throw e; +}); + +function createSandbox(setupScripts) { + const sandbox = vm.createContext(); + sandbox.self = vm.runInContext("this", sandbox); + for (const script of setupScripts) { + script.runInContext(sandbox); + } + sandbox.require = p => { + if (p[0] !== ".") { + // eslint-disable-next-line global-require + return require(p); + } + if (p.startsWith("../implementations/")) { + return { implementation: class Stub {} }; + } + + const resolved = path.resolve(__dirname, "./output", p); + const src = readFileSync(resolved, { encoding: "utf8" }); + return vm.runInContext( + `(() => { + let exports = {}; + const module = { exports }; + (() => {${src}})(); + return module.exports; + })();`, + sandbox, + { filename: resolved, lineOffset: 5, columnOffset: 16 } + ); + }; + return sandbox; +} + +async function prepareInterface({ name, content }, idlArray, sandbox) { + const lcName = name[0].toLowerCase() + name.substring(1); + + vm.runInContext( + `(() => { + const Wrapper = require("./${name}.js"); + Object.defineProperty(self, '${name}', { + value: Wrapper.interface, + enumerable: false, + writable:true, + configurable:true + }); + Object.defineProperty(self, '${lcName}', { + value: Wrapper.create([], {}), + enumerable: false, + writable:true, + configurable:true + }); + })() + `, + sandbox + ); + + idlArray.add_idls(content); + idlArray.add_objects({ [name]: [lcName] }); +} + +describe("IDL Harness", () => { + let setupScripts; + + beforeAll(async () => { + const files = await Promise.all( + ["testharness.js", "webidl2.js", "idlharness.js"].map(async p => ({ + path: path.join(__dirname, "/vendor/", p), + contents: await fs.readFile(path.join(__dirname, "/vendor/", p), { + encoding: "utf8" + }) + })) + ); + setupScripts = files.map( + file => new vm.Script(file.contents, { filename: file.path }) + ); + }); + + const files = [ + "DOMImplementation", + "EnumInterface", + "PromiseTypes", + "ReflectAttribute", + "Storage", + "StringifierAttribute", + "StringifierDefaultOperation", + "StringifierNamedOperation", + "StringifierOperation", + "TypedefsAndUnions", + // "UnderscoredProperties", + "Unforgeable", + "UnforgeableMap", + "URL", + "URLList", + "URLSearchParams", + "URLSearchParamsCollection", + // "URLSearchParamsCollection2", + "Variadic", + "ZeroArgConstructor" + ]; + test(`Interfaces`, async () => { + const idlSources = await Promise.all( + files.map(async f => ({ + name: f.replace(/\.webidl$/, ""), + content: await fs.readFile( + path.join(__dirname, `./cases/${f}.webidl`), + { + encoding: "utf8" + } + ) + })) + ); + const sandbox = createSandbox(setupScripts); + + const idlArray = new sandbox.IdlArray(); + idlSources.forEach(source => { + prepareInterface(source, idlArray, sandbox); + }); + + const prom = new Promise((resolve, reject) => { + const errors = []; + + sandbox.add_result_callback(test => { + if (test.status === 1) { + errors.push( + `Failed in "${test.name}": \n${test.message}\n\n${test.stack}` + ); + } else if (test.status === 2) { + errors.push( + `Timeout in "${test.name}": \n${test.message}\n\n${test.stack}` + ); + } else if (test.status === 3) { + errors.push( + `Uncompleted test "${test.name}": \n${test.message}\n\n${ + test.stack + }` + ); + } + }); + + sandbox.add_completion_callback((tests, harnessStatus) => { + if (harnessStatus.status === 2) { + errors.push(new Error(`test harness should not timeout`)); + } + + if (errors.length === 1) { + reject(new Error(errors[0])); + } else if (errors.length) { + reject( + new Error( + `${errors.length} errors in test:\n\n${errors.join("\n")}` + ) + ); + } else { + resolve(); + } + }); + }); + + idlArray.test(); + await prom; + }); +}); diff --git a/test/implementations/URL.js b/test/implementations/URL.js new file mode 100644 index 00000000..646498f7 --- /dev/null +++ b/test/implementations/URL.js @@ -0,0 +1,3 @@ +"use strict"; + +module.exports = class URL {};