mirror of
https://github.com/bendtherules/completion-viz.git
synced 2026-08-18 13:42:51 +00:00
Clone engine262 in /engine262
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
'use strict';
|
||||
|
||||
const readline = require('readline');
|
||||
const os = require('os');
|
||||
|
||||
process.on('unhandledRejection', (reason) => {
|
||||
require('fs').writeSync(0, `\n${require('util').inspect(reason)}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
const CI = !!process.env.CONTINUOUS_INTEGRATION;
|
||||
|
||||
const ANSI = CI ? {
|
||||
reset: '',
|
||||
red: '',
|
||||
green: '',
|
||||
yellow: '',
|
||||
blue: '',
|
||||
} : {
|
||||
reset: '\u001b[0m',
|
||||
red: '\u001b[31m',
|
||||
green: '\u001b[32m',
|
||||
yellow: '\u001b[33m',
|
||||
blue: '\u001b[34m',
|
||||
};
|
||||
|
||||
const CPU_COUNT = os.cpus().length;
|
||||
|
||||
let skipped = 0;
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
let total = 0;
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
const handledPerSecLast5 = [];
|
||||
const pad = (n, l, c = '0') => n.toString().padStart(l, c);
|
||||
const average = (array) => (array.reduce((a, b) => a + b, 0) / array.length) || 0;
|
||||
|
||||
const printStatusLine = () => {
|
||||
const elapsed = Math.floor((Date.now() - start) / 1000);
|
||||
const min = Math.floor(elapsed / 60);
|
||||
const sec = elapsed % 60;
|
||||
|
||||
const time = `${pad(min, 2)}:${pad(sec, 2)}`;
|
||||
const found = `${ANSI.blue}:${pad(total, 5, ' ')}${ANSI.reset}`;
|
||||
const p = `${ANSI.green}+${pad(passed, 5, ' ')}${ANSI.reset}`;
|
||||
const f = `${ANSI.red}-${pad(failed, 5, ' ')}${ANSI.reset}`;
|
||||
const s = `${ANSI.yellow}»${pad(skipped, 5, ' ')}${ANSI.reset}`;
|
||||
const testsPerSec = average(handledPerSecLast5);
|
||||
|
||||
const line = `[${time}|${found}|${p}|${f}|${s}] (${testsPerSec.toFixed(2)}/s)`;
|
||||
|
||||
if (!CI) {
|
||||
readline.clearLine(process.stdout, 0);
|
||||
readline.cursorTo(process.stdout, 0);
|
||||
}
|
||||
process.stdout.write(`${line}${CI ? '\n' : ''}`);
|
||||
};
|
||||
|
||||
let handledPerSecCounter = 0;
|
||||
|
||||
setInterval(() => {
|
||||
handledPerSecLast5.unshift(handledPerSecCounter);
|
||||
handledPerSecCounter = 0;
|
||||
if (handledPerSecLast5.length > 5) {
|
||||
handledPerSecLast5.length = 5;
|
||||
}
|
||||
}, 1000).unref();
|
||||
|
||||
module.exports = {
|
||||
total() {
|
||||
total += 1;
|
||||
},
|
||||
pass() {
|
||||
passed += 1;
|
||||
handledPerSecCounter += 1;
|
||||
},
|
||||
fail(name, error) {
|
||||
failed += 1;
|
||||
handledPerSecCounter += 1;
|
||||
process.exitCode = 1;
|
||||
process.stderr.write(`\nFAILURE! ${name}\n${error}\n`);
|
||||
},
|
||||
skip() {
|
||||
skipped += 1;
|
||||
handledPerSecCounter += 1;
|
||||
},
|
||||
CPU_COUNT,
|
||||
CI,
|
||||
};
|
||||
|
||||
process.stdout.write(`
|
||||
#######################
|
||||
engine262 Test Runner
|
||||
Detected ${CPU_COUNT} CPUs
|
||||
${CI ? 'Running' : 'Not running'} on CI
|
||||
#######################
|
||||
|
||||
`);
|
||||
|
||||
printStatusLine();
|
||||
setInterval(() => {
|
||||
printStatusLine();
|
||||
}, CI ? 5000 : 500).unref();
|
||||
|
||||
process.on('exit', () => {
|
||||
printStatusLine();
|
||||
process.stdout.write('\n');
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-use-in-def': require('./no-use-in-def'),
|
||||
'valid-feature': require('./valid-feature'),
|
||||
'valid-throw': require('./valid-throw'),
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
|
||||
// https://github.com/eslint/eslint/blob/master/lib/rules/no-use-before-define.js
|
||||
|
||||
const SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/u;
|
||||
const FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/u;
|
||||
|
||||
function isInRange(node, location) {
|
||||
return node && node.range[0] <= location && location <= node.range[1];
|
||||
}
|
||||
|
||||
function isUsedInDef(reference) {
|
||||
const variable = reference.resolved;
|
||||
if (!variable || variable.scope !== reference.from) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let node = variable.identifiers[0].parent;
|
||||
const location = reference.identifier.range[1];
|
||||
|
||||
while (node) {
|
||||
if (node.type === 'VariableDeclarator') {
|
||||
if (isInRange(node.init, location)) {
|
||||
return true;
|
||||
}
|
||||
if (FOR_IN_OF_TYPE.test(node.parent.parent.type) && isInRange(node.parent.parent.right, location)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (node.type === 'AssignmentPattern' && isInRange(node.right, location)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SENTINEL_TYPE.test(node.type)) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
create(context) {
|
||||
function findVariablesInScope(scope) {
|
||||
scope.references.forEach((reference) => {
|
||||
if (isUsedInDef(reference)) {
|
||||
context.report({
|
||||
node: reference.identifier,
|
||||
message: '{{name}} was used in its own definition',
|
||||
data: reference.identifier,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
scope.childScopes.forEach((s) => findVariablesInScope(s));
|
||||
}
|
||||
|
||||
return {
|
||||
Program() {
|
||||
findVariablesInScope(context.getScope());
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
let features;
|
||||
try {
|
||||
features = require('../..').FEATURES.map((f) => f.flag);
|
||||
} catch {}
|
||||
|
||||
function isFeatureCall(node) {
|
||||
return node.callee.type === 'MemberExpression'
|
||||
&& node.callee.computed === false
|
||||
&& node.callee.property.name === 'feature';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (!isFeatureCall(node)) {
|
||||
return;
|
||||
}
|
||||
if (node.arguments.length !== 1) {
|
||||
context.report(node, 'Invalid arguments passed to feature()');
|
||||
return;
|
||||
}
|
||||
const featureName = node.arguments[0].value;
|
||||
if (!features.includes(featureName)) {
|
||||
context.report(node.arguments[0], `'${featureName}' is not a valid feature. Check src/engine.mjs.`);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const acorn = require('acorn');
|
||||
|
||||
function isThrowCall(node) {
|
||||
return node.callee.type === 'MemberExpression'
|
||||
&& node.callee.computed === false
|
||||
&& node.callee.object.type === 'Identifier'
|
||||
&& node.callee.object.name === 'surroundingAgent'
|
||||
&& node.callee.property.type === 'Identifier'
|
||||
&& node.callee.property.name === 'Throw';
|
||||
}
|
||||
|
||||
const templates = {};
|
||||
|
||||
{
|
||||
const source = fs.readFileSync(path.join(__dirname, '../../src/messages.mjs'), 'utf8');
|
||||
const ast = acorn.parse(source, { ecmaVersion: 2020, sourceType: 'module' });
|
||||
|
||||
ast.body.forEach((n) => {
|
||||
if (n.type !== 'ExportNamedDeclaration') {
|
||||
return;
|
||||
}
|
||||
const [v] = n.declaration.declarations;
|
||||
const name = v.id.name;
|
||||
const length = v.init.params.length;
|
||||
templates[name] = length;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (!isThrowCall(node)) {
|
||||
return;
|
||||
}
|
||||
if (node.arguments.length === 1 && node.arguments[0].type !== 'Literal') {
|
||||
return;
|
||||
}
|
||||
const [type, template, ...templateArgs] = node.arguments;
|
||||
if (!type || type.type !== 'Literal') {
|
||||
context.report(node, 'Throw must use a valid error constructor');
|
||||
return;
|
||||
}
|
||||
if (!template || template.type !== 'Literal') {
|
||||
context.report(node, 'Throw must use a valid message template');
|
||||
return;
|
||||
}
|
||||
const tfn = templates[template.value];
|
||||
if (tfn === undefined) {
|
||||
context.report(template, `'${template.value}' is not a valid message template`);
|
||||
return;
|
||||
}
|
||||
if (tfn !== templateArgs.length) {
|
||||
context.report(node, `Template expects ${tfn} args`);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const {
|
||||
pass, fail, skip, total,
|
||||
} = require('../base');
|
||||
const {
|
||||
Agent,
|
||||
setSurroundingAgent,
|
||||
ManagedRealm,
|
||||
AbruptCompletion,
|
||||
inspect,
|
||||
} = require('../..');
|
||||
|
||||
const BASE_DIR = path.resolve(__dirname, 'JSONTestSuite');
|
||||
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
|
||||
function test(filename) {
|
||||
const realm = new ManagedRealm();
|
||||
|
||||
const source = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = realm.evaluateScript(`'use strict';
|
||||
const source = ${JSON.stringify(source)};
|
||||
JSON.parse(source);
|
||||
`);
|
||||
} catch {
|
||||
// ...
|
||||
}
|
||||
|
||||
const testName = path.basename(filename);
|
||||
|
||||
if (!result || result instanceof AbruptCompletion) {
|
||||
if (testName.startsWith('n_')) {
|
||||
pass();
|
||||
} else if (testName.startsWith('i_')) {
|
||||
skip();
|
||||
} else {
|
||||
fail(testName, inspect(result));
|
||||
}
|
||||
} else {
|
||||
if (testName.startsWith('n_')) {
|
||||
fail(testName, 'JSON parsed but should have failed!');
|
||||
} else {
|
||||
pass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tests = glob.sync(`${path.resolve(BASE_DIR, 'test_parsing')}/**/*.json`)
|
||||
.concat(glob.sync(`${path.resolve(BASE_DIR, 'test_transform')}/**/*.json`));
|
||||
|
||||
tests.forEach((t) => {
|
||||
total();
|
||||
test(t);
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
require('@snek/source-map-support/register');
|
||||
const {
|
||||
isMainThread, parentPort, workerData, Worker,
|
||||
} = require('worker_threads');
|
||||
const fs = require('fs');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const { codeFrameColumns } = require('@babel/code-frame');
|
||||
|
||||
if (isMainThread) {
|
||||
const shared = new SharedArrayBuffer(4);
|
||||
const shared32 = new Int32Array(shared);
|
||||
const source = fs.readFileSync(process.argv[2], 'utf8');
|
||||
const worker = new Worker(__filename, {
|
||||
workerData: { shared, source },
|
||||
});
|
||||
process.stdin.on('data', () => {
|
||||
const old = Atomics.compareExchange(shared32, 0, 0, 1);
|
||||
if (old === 0) {
|
||||
Atomics.notify(shared32, 0, 1);
|
||||
}
|
||||
});
|
||||
worker.on('message', (data) => {
|
||||
const node = JSON.parse(data);
|
||||
const frame = codeFrameColumns(source, node.location, {
|
||||
highlightCode: true,
|
||||
message: node.type,
|
||||
});
|
||||
process.stdout.write(`${frame}\n\n\n`);
|
||||
});
|
||||
worker.on('exit', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
} else {
|
||||
const {
|
||||
Agent,
|
||||
setSurroundingAgent,
|
||||
ManagedRealm,
|
||||
AbruptCompletion,
|
||||
inspect,
|
||||
} = require('..');
|
||||
|
||||
const shared32 = new Int32Array(workerData.shared);
|
||||
setSurroundingAgent(new Agent({
|
||||
onNodeEvaluation(node) {
|
||||
if (node.type === 'ExpressionStatement') {
|
||||
return;
|
||||
}
|
||||
parentPort.postMessage(JSON.stringify(node));
|
||||
Atomics.wait(shared32, 0, 0);
|
||||
Atomics.store(shared32, 0, 0);
|
||||
},
|
||||
}));
|
||||
|
||||
const realm = new ManagedRealm();
|
||||
|
||||
realm.scope(() => {
|
||||
const completion = realm.evaluateScript(workerData.source);
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
process.stdout.write(`${inspect(completion, realm)}\n`);
|
||||
}
|
||||
});
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
'use strict';
|
||||
|
||||
require('@snek/source-map-support/register');
|
||||
const assert = require('assert');
|
||||
const {
|
||||
Agent,
|
||||
setSurroundingAgent,
|
||||
ManagedRealm,
|
||||
Value,
|
||||
FEATURES,
|
||||
Get,
|
||||
CreateArrayFromList,
|
||||
CreateDataProperty,
|
||||
} = require('..');
|
||||
const test262realm = require('../bin/test262_realm');
|
||||
const { total, pass, fail } = require('./base');
|
||||
|
||||
// Features that cannot be tested by test262 should go here.
|
||||
|
||||
[
|
||||
() => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript('debugger;');
|
||||
assert.strictEqual(result.Value, Value.undefined);
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent({
|
||||
onDebugger() {
|
||||
return new Value(42);
|
||||
},
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript('debugger;');
|
||||
assert.strictEqual(result.Value.numberValue(), 42);
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`\
|
||||
function x() { throw new Error('owo'); }
|
||||
function y() { x(); }
|
||||
try {
|
||||
y();
|
||||
} catch (e) {
|
||||
e.stack;
|
||||
}
|
||||
`);
|
||||
assert.strictEqual(result.Value.stringValue(), `\
|
||||
Error: owo
|
||||
at x (<anonymous>:1:32)
|
||||
at y (<anonymous>:2:16)
|
||||
at <anonymous>:4:3`);
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`\
|
||||
async function x() { await 1; throw new Error('owo'); }
|
||||
async function y() { await x(); }
|
||||
y().catch((e) => e.stack);
|
||||
`);
|
||||
assert.strictEqual(result.Value.PromiseResult.stringValue(), `\
|
||||
Error: owo
|
||||
at async x (<anonymous>:1:47)
|
||||
at async y (<anonymous>:2:28)`);
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`\
|
||||
function x() { Reflect.get(); }
|
||||
try {
|
||||
x();
|
||||
} catch (e) {
|
||||
e.stack;
|
||||
}
|
||||
`);
|
||||
assert.strictEqual(result.Value.stringValue(), `\
|
||||
TypeError: undefined is not an object
|
||||
at get (native)
|
||||
at x (<anonymous>:1:16)
|
||||
at <anonymous>:3:3`);
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`\
|
||||
function Y() { throw new Error('owo'); }
|
||||
function x() { new Y(); }
|
||||
try {
|
||||
x();
|
||||
} catch (e) {
|
||||
e.stack;
|
||||
}
|
||||
`);
|
||||
assert.strictEqual(result.Value.stringValue(), `\
|
||||
Error: owo
|
||||
at new Y (<anonymous>:1:32)
|
||||
at x (<anonymous>:2:20)
|
||||
at <anonymous>:4:3`);
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`\
|
||||
let e;
|
||||
new Promise(() => {
|
||||
e = new Error('owo');
|
||||
});
|
||||
e.stack;
|
||||
`);
|
||||
assert.strictEqual(result.Value.stringValue(), `\
|
||||
Error: owo
|
||||
at <anonymous> (<anonymous>:3:17)
|
||||
at new Promise (native)
|
||||
at <anonymous>:2:13`);
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent({
|
||||
features: ['WeakRefs'],
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`
|
||||
const w = new WeakRef({});
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'object') {
|
||||
throw new Error();
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'undefined') {
|
||||
throw new Error();
|
||||
}
|
||||
})
|
||||
.then(() => 'pass');
|
||||
`);
|
||||
assert.strictEqual(result.Value.PromiseResult.stringValue(), 'pass');
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent({
|
||||
features: ['WeakRefs'],
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
realm.scope(() => {
|
||||
const module = realm.createSourceTextModule('test.mjs', `
|
||||
const w = new WeakRef({});
|
||||
globalThis.result = Promise.resolve()
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'object') {
|
||||
throw new Error('should be object');
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'undefined') {
|
||||
throw new Error('should be undefined');
|
||||
}
|
||||
})
|
||||
.then(() => 'pass');
|
||||
`);
|
||||
module.Link();
|
||||
module.Evaluate();
|
||||
const result = Get(realm.GlobalObject, new Value('result'));
|
||||
assert.strictEqual(result.Value.PromiseResult.stringValue(), 'pass');
|
||||
});
|
||||
},
|
||||
() => {
|
||||
const agent = new Agent({
|
||||
features: FEATURES.map((f) => f.name),
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
const { realm } = test262realm.createRealm();
|
||||
realm.scope(() => {
|
||||
CreateDataProperty(
|
||||
realm.GlobalObject,
|
||||
new Value('fail'),
|
||||
new Value(([path]) => {
|
||||
throw new Error(`${path.stringValue()} did not have a section`);
|
||||
}),
|
||||
);
|
||||
const targets = [];
|
||||
Object.entries(realm.Intrinsics)
|
||||
.forEach(([k, v]) => {
|
||||
targets.push(CreateArrayFromList([new Value(k), v]));
|
||||
});
|
||||
CreateDataProperty(
|
||||
realm.GlobalObject,
|
||||
new Value('targets'),
|
||||
CreateArrayFromList(targets),
|
||||
);
|
||||
});
|
||||
const result = realm.evaluateScript(`
|
||||
'use strict';
|
||||
|
||||
{
|
||||
const targets = globalThis.targets;
|
||||
delete globalThis.targets;
|
||||
const fail = globalThis.fail;
|
||||
delete globalThis.fail;
|
||||
|
||||
const topQueue = new Set();
|
||||
const scanned = new Set();
|
||||
const scan = (ns, path) => {
|
||||
if (scanned.has(ns)) {
|
||||
return;
|
||||
}
|
||||
scanned.add(ns);
|
||||
if (typeof ns === 'function') {
|
||||
if ($262.spec(ns) === undefined) {
|
||||
fail(path);
|
||||
}
|
||||
}
|
||||
if (typeof ns !== 'function' && (typeof ns !== 'object' || ns === null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const descriptors = Object.getOwnPropertyDescriptors(ns);
|
||||
Reflect.ownKeys(descriptors)
|
||||
.forEach((name) => {
|
||||
const desc = descriptors[name];
|
||||
const p = typeof name === 'symbol'
|
||||
? path + '[Symbol(' + name.description + ')]'
|
||||
: path + '.' + name;
|
||||
if ('value' in desc) {
|
||||
if (!topQueue.has(desc.value)) {
|
||||
scan(desc.value, p);
|
||||
}
|
||||
} else {
|
||||
if (!topQueue.has(desc.get)) {
|
||||
scan(desc.get, p);
|
||||
}
|
||||
if (!topQueue.has(desc.set)) {
|
||||
scan(desc.set, p);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
targets.forEach((t) => {
|
||||
topQueue.add(t[1]);
|
||||
});
|
||||
targets.forEach((t) => {
|
||||
scan(t[1], t[0]);
|
||||
});
|
||||
}
|
||||
`);
|
||||
assert.strictEqual(result.Value, Value.undefined);
|
||||
},
|
||||
].forEach((test) => {
|
||||
total();
|
||||
try {
|
||||
test();
|
||||
pass();
|
||||
} catch (e) {
|
||||
fail('', e.stack || e);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
# https://github.com/tc39/test262/blob/master/features.txt
|
||||
|
||||
# Start with `-` to skip feature
|
||||
# Map feature to engine262 feature using `feature = engine262featurename`
|
||||
|
||||
-Atomics
|
||||
-Atomics.waitAsync
|
||||
|
||||
-caller
|
||||
|
||||
-SharedArrayBuffer
|
||||
|
||||
-tail-call-optimization
|
||||
|
||||
-class-fields-public
|
||||
-class-fields-private
|
||||
-class-methods-private
|
||||
-class-static-fields-public
|
||||
-class-static-fields-private
|
||||
-class-static-methods-private
|
||||
|
||||
# https://github.com/tc39/proposal-top-level-await
|
||||
top-level-await = top-level-await
|
||||
|
||||
# https://github.com/tc39/proposal-hashbang
|
||||
hashbang = hashbang
|
||||
|
||||
# https://github.com/tc39/proposal-numeric-separator
|
||||
numeric-separator-literal = numeric-separators
|
||||
|
||||
# https://github.com/tc39/proposal-regexp-match-indices
|
||||
regexp-match-indices = regexp-match-indices
|
||||
|
||||
# https://github.com/tc39/proposal-cleanup-some
|
||||
cleanupSome = cleanup-some
|
||||
@@ -0,0 +1,59 @@
|
||||
#####################
|
||||
### Skipped Tests ###
|
||||
#####################
|
||||
|
||||
# Comments start with `#`.
|
||||
# Paths are relative to the `test262/test` directory.
|
||||
# Paths may contain globs.
|
||||
|
||||
# Spec bug
|
||||
built-ins/Date/prototype/setMonth/this-value-invalid-date.js
|
||||
|
||||
# Spec bug
|
||||
built-ins/Function/prototype/bind/instance-length-tointeger.js
|
||||
|
||||
# https://github.com/tc39/test262/issues/427
|
||||
language/expressions/prefix-increment/S11.4.4_A5_T4.js
|
||||
language/expressions/prefix-increment/S11.4.4_A5_T5.js
|
||||
language/expressions/postfix-increment/S11.3.1_A5_T4.js
|
||||
language/expressions/postfix-increment/S11.3.1_A5_T5.js
|
||||
language/expressions/prefix-decrement/S11.4.5_A5_T4.js
|
||||
language/expressions/prefix-decrement/S11.4.5_A5_T5.js
|
||||
language/expressions/postfix-decrement/S11.3.2_A5_T4.js
|
||||
language/expressions/postfix-decrement/S11.3.2_A5_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.1_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.4_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.7_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.10_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.11_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.2_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.3_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.5_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.6_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.9_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.8_T4.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.1_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.2_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.3_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.4_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.5_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.6_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.7_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.8_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.9_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.10_T5.js
|
||||
language/expressions/compound-assignment/S11.13.2_A5.11_T5.js
|
||||
language/expressions/assignment/S11.13.1_A5_T5.js
|
||||
language/expressions/assignment/S11.13.1_A5_T4.js
|
||||
|
||||
# https://github.com/tc39/ecma262/issues/1426
|
||||
built-ins/String/prototype/replace/S15.5.4.11_A3_T*.js
|
||||
|
||||
# We need our own date parser
|
||||
built-ins/Date/parse/without-utc-offset.js
|
||||
|
||||
# TODO: RegExp
|
||||
built-ins/RegExp/property-escapes/**/*.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-plus-quantifier.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-plus-quantifier.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-plus-quantifier.js
|
||||
@@ -0,0 +1,26 @@
|
||||
##################
|
||||
### Slow Tests ###
|
||||
##################
|
||||
|
||||
# Comments start with `#`.
|
||||
# Paths are relative to the `test262/test` directory.
|
||||
# Paths may contain globs.
|
||||
|
||||
built-ins/RegExp/character-class-escape-non-whitespace.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-flags-u.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-plus-quantifier-flags-u.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-flags-u.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-plus-quantifier-flags-u.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-flags-u.js
|
||||
built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-plus-quantifier-flags-u.js
|
||||
language/literals/regexp/S7.8.5_A1.1_T2.js
|
||||
language/literals/regexp/S7.8.5_A1.4_T2.js
|
||||
language/literals/regexp/S7.8.5_A2.1_T2.js
|
||||
language/literals/regexp/S7.8.5_A2.4_T2.js
|
||||
|
||||
language/comments/S7.4_A5.js
|
||||
language/comments/S7.4_A6.js
|
||||
|
||||
built-ins/{encode,decode}URI?(Component)/**/*.js
|
||||
|
||||
built-ins/Function/prototype/toString/built-in-function-object.js
|
||||
@@ -0,0 +1,324 @@
|
||||
'use strict';
|
||||
|
||||
try {
|
||||
require('@snek/source-map-support/register');
|
||||
} catch {}
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const util = require('util');
|
||||
const glob = require('glob');
|
||||
|
||||
const readList = (name) => {
|
||||
const source = fs.readFileSync(path.resolve(__dirname, name), 'utf8');
|
||||
return source.split('\n').filter((l) => l && !l.startsWith('#'));
|
||||
};
|
||||
const readListPaths = (name) => readList(name)
|
||||
.flatMap((t) => glob.sync(path.resolve(__dirname, 'test262', 'test', t)))
|
||||
.map((f) => path.relative(path.resolve(__dirname, 'test262'), f));
|
||||
|
||||
const disabledFeatures = [];
|
||||
const featureMap = {};
|
||||
readList('features')
|
||||
.forEach((f) => {
|
||||
if (f.startsWith('-')) {
|
||||
disabledFeatures.push(f.slice(1));
|
||||
}
|
||||
if (f.includes('=')) {
|
||||
const [k, v] = f.split('=');
|
||||
featureMap[k.trim()] = v.trim();
|
||||
}
|
||||
});
|
||||
|
||||
if (!process.send) {
|
||||
// supervisor
|
||||
|
||||
const childProcess = require('child_process');
|
||||
const TestStream = require('test262-stream');
|
||||
|
||||
const {
|
||||
pass,
|
||||
fail,
|
||||
skip,
|
||||
total,
|
||||
CPU_COUNT,
|
||||
} = require('../base');
|
||||
|
||||
const override = process.argv.find((e, i) => i > 1 && !e.startsWith('-'));
|
||||
const NUM_WORKERS = process.env.NUM_WORKERS
|
||||
? Number.parseInt(process.env.NUM_WORKERS, 10)
|
||||
: Math.round(CPU_COUNT * 0.75);
|
||||
const RUN_SLOW_TESTS = process.argv.includes('--run-slow-tests');
|
||||
|
||||
const createWorker = () => {
|
||||
const c = childProcess.fork(__filename);
|
||||
c.on('message', (message) => {
|
||||
const { description, status, error } = message;
|
||||
switch (status) {
|
||||
case 'PASS':
|
||||
pass();
|
||||
break;
|
||||
case 'FAIL':
|
||||
fail(description, error);
|
||||
break;
|
||||
case 'SKIP':
|
||||
skip();
|
||||
break;
|
||||
default:
|
||||
throw new RangeError(JSON.stringify(message));
|
||||
}
|
||||
});
|
||||
c.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
return c;
|
||||
};
|
||||
|
||||
const workers = Array.from({ length: NUM_WORKERS }, () => createWorker());
|
||||
let longRunningWorker;
|
||||
if (RUN_SLOW_TESTS) {
|
||||
longRunningWorker = createWorker();
|
||||
}
|
||||
|
||||
const slowlist = readListPaths('slowlist');
|
||||
const skiplist = readListPaths('skiplist');
|
||||
|
||||
const stream = new TestStream(path.resolve(__dirname, 'test262'), {
|
||||
paths: [override || 'test'],
|
||||
omitRuntime: true,
|
||||
});
|
||||
|
||||
let workerIndex = 0;
|
||||
stream.on('data', (test) => {
|
||||
if (test.attrs.flags.module && test.scenario !== 'default') {
|
||||
// test262-stream duplicates module tests, deduplicate here
|
||||
return;
|
||||
}
|
||||
|
||||
if (/annexB|intl402/.test(test.file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
total();
|
||||
|
||||
if ((test.attrs.features && test.attrs.features.some((feature) => disabledFeatures.includes(feature)))
|
||||
|| skiplist.includes(test.file)) {
|
||||
skip();
|
||||
return;
|
||||
}
|
||||
|
||||
if (slowlist.includes(test.file)) {
|
||||
if (RUN_SLOW_TESTS) {
|
||||
longRunningWorker.send(test);
|
||||
} else {
|
||||
skip();
|
||||
}
|
||||
} else {
|
||||
workers[workerIndex].send(test);
|
||||
workerIndex += 1;
|
||||
if (workerIndex >= workers.length) {
|
||||
workerIndex = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
workers.forEach((w) => {
|
||||
w.send('DONE');
|
||||
});
|
||||
if (RUN_SLOW_TESTS) {
|
||||
longRunningWorker.send('DONE');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// worker
|
||||
|
||||
const {
|
||||
Agent,
|
||||
setSurroundingAgent,
|
||||
inspect,
|
||||
|
||||
Value,
|
||||
|
||||
IsCallable,
|
||||
IsDataDescriptor,
|
||||
Type,
|
||||
|
||||
AbruptCompletion,
|
||||
Throw,
|
||||
} = require('../..');
|
||||
const { createRealm } = require('../../bin/test262_realm');
|
||||
|
||||
const isError = (type, value) => {
|
||||
if (Type(value) !== 'Object') {
|
||||
return false;
|
||||
}
|
||||
const proto = value.Prototype;
|
||||
if (!proto || Type(proto) !== 'Object') {
|
||||
return false;
|
||||
}
|
||||
const ctorDesc = proto.properties.get(new Value('constructor'));
|
||||
if (!ctorDesc || !IsDataDescriptor(ctorDesc)) {
|
||||
return false;
|
||||
}
|
||||
const ctor = ctorDesc.Value;
|
||||
if (Type(ctor) !== 'Object' || IsCallable(ctor) !== Value.true) {
|
||||
return false;
|
||||
}
|
||||
const namePropDesc = ctor.properties.get(new Value('name'));
|
||||
if (!namePropDesc || !IsDataDescriptor(namePropDesc)) {
|
||||
return false;
|
||||
}
|
||||
const nameProp = namePropDesc.Value;
|
||||
return Type(nameProp) === 'String' && nameProp.stringValue() === type;
|
||||
};
|
||||
|
||||
const includeCache = {};
|
||||
|
||||
const run = (test) => {
|
||||
const features = [];
|
||||
if (test.attrs.features) {
|
||||
test.attrs.features.forEach((f) => {
|
||||
if (featureMap[f]) {
|
||||
features.push(featureMap[f]);
|
||||
}
|
||||
});
|
||||
}
|
||||
const agent = new Agent({
|
||||
features,
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
|
||||
const {
|
||||
realm, trackedPromises,
|
||||
resolverCache, setPrintHandle,
|
||||
} = createRealm({ file: test.file });
|
||||
const r = realm.scope(() => {
|
||||
test.attrs.includes.unshift('assert.js', 'sta.js');
|
||||
if (test.attrs.flags.async) {
|
||||
test.attrs.includes.unshift('doneprintHandle.js');
|
||||
}
|
||||
|
||||
for (const include of test.attrs.includes) {
|
||||
if (includeCache[include] === undefined) {
|
||||
const p = path.resolve(__dirname, `./test262/harness/${include}`);
|
||||
includeCache[include] = {
|
||||
source: fs.readFileSync(p, 'utf8'),
|
||||
specifier: p,
|
||||
};
|
||||
}
|
||||
const entry = includeCache[include];
|
||||
const completion = realm.evaluateScript(entry.source, { specifier: entry.specifier });
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
return { status: 'FAIL', error: inspect(completion) };
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const completion = realm.evaluateScript(`\
|
||||
var Test262Error = class Test262Error extends Error {};
|
||||
|
||||
function $DONE(error) {
|
||||
if (error) {
|
||||
if (typeof error === 'object' && error !== null && 'stack' in error) {
|
||||
__consolePrintHandle__('Test262:AsyncTestFailure:' + error.stack);
|
||||
} else {
|
||||
__consolePrintHandle__('Test262:AsyncTestFailure:Test262Error: ' + error);
|
||||
}
|
||||
} else {
|
||||
__consolePrintHandle__('Test262:AsyncTestComplete');
|
||||
}
|
||||
}`);
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
return { status: 'FAIL', error: inspect(completion) };
|
||||
}
|
||||
}
|
||||
|
||||
let asyncResult;
|
||||
if (test.attrs.flags.async) {
|
||||
setPrintHandle((m) => {
|
||||
if (m.stringValue && m.stringValue() === 'Test262:AsyncTestComplete') {
|
||||
asyncResult = { status: 'PASS' };
|
||||
} else {
|
||||
asyncResult = { status: 'FAIL', error: m.stringValue ? m.stringValue() : inspect(m) };
|
||||
}
|
||||
setPrintHandle(undefined);
|
||||
});
|
||||
}
|
||||
|
||||
const specifier = path.resolve(__dirname, 'test262', test.file);
|
||||
|
||||
let completion;
|
||||
if (test.attrs.flags.module) {
|
||||
completion = realm.createSourceTextModule(specifier, test.contents);
|
||||
if (!(completion instanceof AbruptCompletion)) {
|
||||
const module = completion;
|
||||
resolverCache.set(specifier, module);
|
||||
completion = module.Link();
|
||||
if (!(completion instanceof AbruptCompletion)) {
|
||||
completion = module.Evaluate();
|
||||
}
|
||||
if (!(completion instanceof AbruptCompletion)) {
|
||||
if (completion.PromiseState === 'rejected') {
|
||||
completion = Throw(completion.PromiseResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completion = realm.evaluateScript(test.contents, { specifier });
|
||||
}
|
||||
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
if (test.attrs.negative && isError(test.attrs.negative.type, completion.Value)) {
|
||||
return { status: 'PASS' };
|
||||
} else {
|
||||
return { status: 'FAIL', error: inspect(completion) };
|
||||
}
|
||||
}
|
||||
|
||||
if (test.attrs.flags.async) {
|
||||
if (!asyncResult) {
|
||||
throw new Error('missing async result');
|
||||
}
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
if (trackedPromises.length > 0) {
|
||||
return { status: 'FAIL', error: inspect(trackedPromises[0]) };
|
||||
}
|
||||
|
||||
if (test.attrs.negative) {
|
||||
return { status: 'FAIL', error: `Expected ${test.attrs.negative.type} during ${test.attrs.negative.phase}` };
|
||||
} else {
|
||||
return { status: 'PASS' };
|
||||
}
|
||||
});
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
let p = Promise.resolve();
|
||||
const handleSendError = (e) => {
|
||||
if (e) {
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
process.on('message', (test) => {
|
||||
if (test === 'DONE') {
|
||||
p.then(() => process.exit(0));
|
||||
p = undefined;
|
||||
} else {
|
||||
const description = `${test.file}\n${test.attrs.description}`;
|
||||
p = p
|
||||
.then(() => run(test))
|
||||
.then((r) => {
|
||||
process.send({ description, ...r }, handleSendError);
|
||||
})
|
||||
.catch((e) => {
|
||||
process.send({ description, status: 'FAIL', error: util.inspect(e) }, handleSendError);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
E=0
|
||||
|
||||
npm run test:test262 || E=$?
|
||||
npm run test:json || E=$?
|
||||
npm run test:supplemental || E=$?
|
||||
|
||||
exit $E
|
||||
Reference in New Issue
Block a user