mirror of
https://github.com/bendtherules/completion-viz.git
synced 2026-08-18 13:42:51 +00:00
325 lines
8.6 KiB
JavaScript
325 lines
8.6 KiB
JavaScript
'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);
|
|
});
|
|
}
|
|
});
|
|
}
|