Files
asciidisco.com/build/node_modules/prepack/lib/test262-runner.js
2023-08-01 13:49:46 +02:00

1470 lines
53 KiB
JavaScript

"use strict";
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
/* eslint-disable no-extend-native */
// need to use graceful-fs for single-process code because it opens too many
// files
var _completions = require("../lib/completions.js");
var _index = require("../lib/values/index.js");
var _realm = require("../lib/realm.js");
var _construct_realm = require("../lib/construct_realm.js");
var _construct_realm2 = _interopRequireDefault(_construct_realm);
var _globals = require("../lib/globals.js");
var _globals2 = _interopRequireDefault(_globals);
var _arraybuffer = require("../lib/methods/arraybuffer.js");
var _singletons = require("../lib/singletons.js");
var _get = require("../lib/methods/get.js");
var _invariant = require("../lib/invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _jsYaml = require("js-yaml");
var _jsYaml2 = _interopRequireDefault(_jsYaml);
var _chalk = require("chalk");
var _chalk2 = _interopRequireDefault(_chalk);
var _path = require("path");
var _path2 = _interopRequireDefault(_path);
var _gracefulFs = require("graceful-fs");
var _gracefulFs2 = _interopRequireDefault(_gracefulFs);
var _cluster = require("cluster");
var _cluster2 = _interopRequireDefault(_cluster);
var _os = require("os");
var _os2 = _interopRequireDefault(_os);
var _tty = require("tty");
var _tty2 = _interopRequireDefault(_tty);
var _minimist = require("minimist");
var _minimist2 = _interopRequireDefault(_minimist);
var _process = require("process");
var _process2 = _interopRequireDefault(_process);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var EOL = _os2.default.EOL;
var numCPUs = _os2.default.cpus().length;
require("source-map-support").install();
// A TestTask is a task for a worker process to execute, which contains a
// single test to run
var TestTask = function () {
function TestTask(file) {
_classCallCheck(this, TestTask);
this.type = TestTask.sentinel;
this.file = file;
}
// eslint-disable-next-line flowtype/no-weak-types
_createClass(TestTask, null, [{
key: "fromObject",
value: function fromObject(obj) {
// attempt to coerce the object into a test task
if ("file" in obj && _typeof(obj.file) === "object") {
return new TestTask(TestFileInfo.fromObject(obj.file));
} else {
throw new Error("Cannot be converted to a TestTask: " + JSON.stringify(obj));
}
}
}]);
return TestTask;
}();
/**
* Information about a test file to be run.
*
*/
TestTask.sentinel = "TestTask";
var TestFileInfo = function () {
function TestFileInfo(location, isES6) {
_classCallCheck(this, TestFileInfo);
this.location = location;
this.isES6 = isES6;
this.groupName = _path2.default.dirname(location);
}
// eslint-disable-next-line flowtype/no-weak-types
// Location of the test on the filesystem, call fs.readFile on this
_createClass(TestFileInfo, null, [{
key: "fromObject",
value: function fromObject(obj) {
// attempt to coerce the object into a TestFileInfo
if ("location" in obj && typeof obj.location === "string" && "isES6" in obj && typeof obj.isES6 === "boolean") {
return new TestFileInfo(obj.location, obj.isES6);
} else {
throw new Error("Cannot be converted to a TestFileInfo: " + JSON.stringify(obj));
}
}
}]);
return TestFileInfo;
}();
// A Message sent by a worker to the master to say that it has finished its
// current task successfully
var DoneMessage = function () {
function DoneMessage(test) {
var testResult = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
_classCallCheck(this, DoneMessage);
this.type = DoneMessage.sentinel;
this.test = test;
this.testResults = testResult;
}
// eslint-disable-next-line flowtype/no-weak-types
_createClass(DoneMessage, null, [{
key: "fromObject",
value: function fromObject(obj) {
if (!("type" in obj && typeof obj.type === "string" && obj.type === DoneMessage.sentinel)) {
throw new Error("Cannot be converted to a DoneMessage: " + JSON.stringify(obj));
}
if (!("test" in obj && _typeof(obj.test) === "object")) {
throw new Error("A DoneMessage must have a test");
}
var msg = new DoneMessage(obj.test);
if ("testResults" in obj && _typeof(obj.testResults) === "object" && Array.isArray(obj.testResults)) {
msg.testResults = obj.testResults;
}
return msg;
}
}]);
return DoneMessage;
}();
DoneMessage.sentinel = "DoneMessage";
var ErrorMessage = function () {
function ErrorMessage(err) {
_classCallCheck(this, ErrorMessage);
this.type = ErrorMessage.sentinel;
this.err = err;
}
// eslint-disable-next-line flowtype/no-weak-types
_createClass(ErrorMessage, null, [{
key: "fromObject",
value: function fromObject(obj) {
if (!("type" in obj && typeof obj.type === "string" && obj.type === ErrorMessage.sentinel)) {
throw new Error("Cannot be converted to an ErrorMessage: " + JSON.stringify(obj));
}
if (!("err" in obj && _typeof(obj.err) === "object")) {
throw new Error("Cannot be converted to an ErrorMessage: " + JSON.stringify(obj));
}
return new ErrorMessage(obj.err);
}
}]);
return ErrorMessage;
}();
/**
* TestResult contains information about a test that ran.
*/
ErrorMessage.sentinel = "ErrorMessage";
var TestResult = function TestResult(passed, strict) {
var err = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
_classCallCheck(this, TestResult);
this.passed = passed;
this.strict = strict;
this.err = err;
};
// A Message sent by the master to workers to say that there is nothing more
// to do
var QuitMessage = function () {
function QuitMessage() {
_classCallCheck(this, QuitMessage);
this.type = QuitMessage.sentinel;
}
_createClass(QuitMessage, null, [{
key: "fromObject",
value: function fromObject(obj) {
return new QuitMessage();
}
}]);
return QuitMessage;
}();
QuitMessage.sentinel = "QuitMessage";
var BannerData = function () {
function BannerData() {
_classCallCheck(this, BannerData);
this.info = "";
this.es5id = "";
this.es6id = "";
this.description = "";
this.flags = [];
this.features = [];
this.includes = [];
this.negative = {};
}
// eslint-disable-next-line flowtype/no-weak-types
// eslint-disable-next-line flowtype/no-weak-types
_createClass(BannerData, null, [{
key: "fromObject",
value: function fromObject(obj) {
var bd = new BannerData();
if ("info" in obj && typeof obj.info === "string") {
bd.info = obj.info;
}
if ("es5id" in obj && typeof obj.es5id === "string") {
bd.es5id = obj.es5id;
}
if ("es6id" in obj && typeof obj.es6id === "string") {
bd.es6id = obj.es6id;
}
if ("description" in obj && typeof obj.description === "string") {
bd.description = obj.description;
}
if ("flags" in obj && _typeof(obj.flags) === "object" && Array.isArray(obj.flags)) {
bd.flags = obj.flags;
}
if ("features" in obj && _typeof(obj.features) === "object" && Array.isArray(obj.features)) {
bd.features = obj.features;
}
if ("includes" in obj && _typeof(obj.includes) === "object" && Array.isArray(obj.includes)) {
bd.includes = obj.includes;
}
if ("negative" in obj && _typeof(obj.negative) === "object") {
bd.negative = obj.negative;
}
return bd;
}
}]);
return BannerData;
}();
var MasterProgramArgs = function MasterProgramArgs(verbose, timeout, bailAfter, cpuScale, statusFile, filterString, singleThreaded, relativeTestPath) {
_classCallCheck(this, MasterProgramArgs);
this.verbose = verbose;
this.timeout = timeout;
this.bailAfter = bailAfter;
this.cpuScale = cpuScale;
this.statusFile = statusFile;
this.filterString = filterString;
this.singleThreaded = singleThreaded;
this.relativeTestPath = relativeTestPath;
};
var WorkerProgramArgs = function WorkerProgramArgs(timeout, relativeTestPath) {
_classCallCheck(this, WorkerProgramArgs);
this.timeout = timeout;
this.relativeTestPath = relativeTestPath;
};
// NOTE: inheriting from Error does not seem to pass through an instanceof
// check
var ArgsParseError = function ArgsParseError(message) {
_classCallCheck(this, ArgsParseError);
this.message = message;
};
if (!("toJSON" in Error.prototype)) {
// $FlowFixMe this needs to become defined for Error to be serialized
Object.defineProperty(Error.prototype, "toJSON", {
// eslint-disable-line
value: function value() {
var alt = {};
Object.getOwnPropertyNames(this).forEach(function (key) {
alt[key] = this[key];
}, this);
return alt;
},
configurable: true,
writable: true
});
}
main();
function main() {
try {
if (_cluster2.default.isMaster) {
var args = masterArgsParse();
masterRun(args);
} else if (_cluster2.default.isWorker) {
var _args = workerArgsParse();
workerRun(_args);
} else {
throw new Error("Not a master or a worker");
}
} catch (e) {
if (e instanceof ArgsParseError) {
console.error("Illegal argument: %s.\n%s", e.message, usage());
} else {
console.error(e);
}
_process2.default.exit(1);
}
return 0;
}
function usage() {
return "Usage: " + _process2.default.argv[0] + " " + _process2.default.argv[1] + " " + EOL + "[--verbose] [--timeout <number>] [--bailAfter <number>] " + EOL + "[--cpuScale <number>] [--statusFile <string>] [--singleThreaded] [--relativeTestPath <string>]";
}
function masterArgsParse() {
var parsedArgs = (0, _minimist2.default)(_process2.default.argv.slice(2), {
string: ["statusFile", "relativeTestPath"],
boolean: ["verbose", "singleThreaded"],
default: {
verbose: _process2.default.stdout instanceof _tty2.default.WriteStream ? false : true,
statusFile: "",
timeout: 10,
cpuScale: 1,
bailAfter: Infinity,
singleThreaded: false,
relativeTestPath: "/../test/test262"
}
});
var filterString = parsedArgs._[0];
if (typeof parsedArgs.verbose !== "boolean") {
throw new ArgsParseError("verbose must be a boolean (either --verbose or not)");
}
if (typeof parsedArgs.timeout !== "number") {
throw new ArgsParseError("timeout must be a number (in seconds) (--timeout 10)");
}
if (typeof parsedArgs.bailAfter !== "number") {
throw new ArgsParseError("bailAfter must be a number (--bailAfter 10)");
}
if (typeof parsedArgs.cpuScale !== "number") {
throw new ArgsParseError("cpuScale must be a number (--cpuScale 0.5)");
}
if (typeof parsedArgs.statusFile !== "string") {
throw new ArgsParseError("statusFile must be a string (--statusFile file.txt)");
}
if (typeof parsedArgs.singleThreaded !== "boolean") {
throw new ArgsParseError("singleThreaded must be a boolean (either --singleThreaded or not)");
}
if (typeof parsedArgs.relativeTestPath !== "string") {
throw new ArgsParseError("relativeTestPath must be a string (--relativeTestPath /../test/test262)");
}
var programArgs = new MasterProgramArgs(parsedArgs.verbose, parsedArgs.timeout, parsedArgs.bailAfter, parsedArgs.cpuScale, parsedArgs.statusFile, filterString, parsedArgs.singleThreaded, parsedArgs.relativeTestPath);
if (programArgs.filterString) {
// if filterstring is provided, assume that verbosity is desired
programArgs.verbose = true;
}
return programArgs;
}
function workerArgsParse() {
var parsedArgs = (0, _minimist2.default)(_process2.default.argv.slice(2), {
default: {
timeout: 10,
relativeTestPath: "/../test/test262"
}
});
if (typeof parsedArgs.timeout !== "number") {
throw new ArgsParseError("timeout must be a number (in seconds) (--timeout 10)");
}
if (typeof parsedArgs.relativeTestPath !== "string") {
throw new ArgsParseError("relativeTestPath must be a string (--relativeTestPath /../test/test262)");
}
return new WorkerProgramArgs(parsedArgs.timeout, parsedArgs.relativeTestPath);
}
function masterRun(args) {
var testPath = "" + __dirname + args.relativeTestPath + "/test";
var tests = getFilesSync(testPath);
// remove tests that don't need to be run
if (args.filterString) tests = tests.filter(function (test) {
return test.location.includes(args.filterString);
});
var originalTestLength = tests.length;
tests = tests.filter(function (test) {
return testFilterByMetadata(test);
});
var groups = {};
// Now that all the tasks are ready, start up workers to begin processing
// if single threaded, use that route instead
if (args.singleThreaded) {
masterRunSingleProcess(args, groups, tests, originalTestLength - tests.length);
} else {
masterRunMultiProcess(args, groups, tests, originalTestLength - tests.length);
}
}
function masterRunSingleProcess(args, groups, tests, numFiltered) {
console.log("Running " + tests.length + " tests as a single process");
// print out every 5 percent (more granularity than multi-process because multi-process
// runs a lot faster)
var granularity = Math.floor(tests.length / 20);
var harnesses = getHarnesses(args.relativeTestPath);
var numLeft = tests.length;
var _loop = function _loop(t) {
handleTest(t, harnesses, args.timeout, function (err, results) {
if (err) {
if (args.verbose) {
console.error(err);
}
} else {
var ok = handleTestResults(groups, t, results);
if (!ok) {
// handleTestResults returns false if a failure threshold was exceeded
throw new Error("Too many test failures");
}
var progress = getProgressBar(numLeft, tests.length, granularity);
if (progress) {
console.log(progress);
}
}
numLeft--;
if (numLeft === 0) {
// all done
_process2.default.exit(handleFinished(args, groups, numFiltered));
}
});
};
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = tests[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var t = _step.value;
_loop(t);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
function masterRunMultiProcess(args, groups, tests, numFiltered) {
if (!_cluster2.default.on) {
// stop flow errors on "cluster.on"
throw new Error("cluster is malformed");
}
var granularity = Math.floor(tests.length / 10);
var originalTestLength = tests.length;
// Fork workers.
var numWorkers = Math.floor(numCPUs * args.cpuScale);
console.log("Master starting up, forking " + numWorkers + " workers");
for (var i = 0; i < numWorkers; i++) {
_cluster2.default.fork();
}
var exitCount = 0;
_cluster2.default.on("exit", function (worker, code, signal) {
exitCount++;
if (exitCount === numWorkers) {
_process2.default.exit(handleFinished(args, groups, numFiltered));
}
});
var giveTask = function giveTask(worker) {
// grab another test to run and give it to the child process
if (tests.length === 0) {
worker.send(new QuitMessage());
} else {
worker.send(new TestTask(tests.pop()));
}
};
_cluster2.default.on("message", function (worker, message, handle) {
switch (message.type) {
case ErrorMessage.sentinel:
var errMsg = ErrorMessage.fromObject(message);
// just skip the error, thus skipping that test
if (args.verbose) {
console.error("An error occurred in worker #" + worker.process.pid + ":");
console.error(errMsg.err);
}
giveTask(worker);
break;
case DoneMessage.sentinel:
var done = DoneMessage.fromObject(message);
var ok = handleTestResults(groups, done.test, done.testResults);
if (!ok) {
// bail
killWorkers(_cluster2.default.workers);
handleFinished(args, groups, numFiltered);
_process2.default.exit(1);
}
giveTask(worker);
var progress = getProgressBar(tests.length, originalTestLength, granularity);
if (progress) {
console.log(progress);
}
break;
default:
throw new Error("Master got an unexpected message: " + JSON.stringify(message));
}
});
_cluster2.default.on("online", function (worker) {
giveTask(worker);
});
}
function handleFinished(args, groups, earlierNumSkipped) {
var numPassed = 0;
var numPassedES5 = 0;
var numPassedES6 = 0;
var numFailed = 0;
var numFailedES5 = 0;
var numFailedES6 = 0;
var numSkipped = earlierNumSkipped;
var numTimeouts = 0;
var failed_groups = [];
for (var group in groups) {
// count some totals
var group_passed = 0;
var group_failed = 0;
var group_es5_passed = 0;
var group_es5_failed = 0;
var group_es6_passed = 0;
var group_es6_failed = 0;
var groupName = _path2.default.relative(_path2.default.join(__dirname, "..", "..", "test"), group);
var msg = "";
var errmsg = "";
msg += groupName + ": ";
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = groups[group][Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var t = _step2.value;
var testName = _path2.default.relative(group, t.test.location);
var all_passed = true;
var was_skipped = true;
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = t.result[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var testResult = _step3.value;
was_skipped = false;
if (!testResult.passed) {
all_passed = false;
if (args.verbose) {
errmsg += create_test_message(testName, testResult.passed, testResult.err, t.test.isES6, testResult.strict) + EOL;
}
if (testResult.err && testResult.err.message === "Timed out") {
numTimeouts++;
}
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
if (was_skipped) {
numSkipped++;
} else if (all_passed) {
group_passed++;
if (t.test.isES6) {
group_es6_passed++;
} else {
group_es5_passed++;
}
} else {
group_failed++;
if (t.test.isES6) {
group_es6_failed++;
} else {
group_es5_failed++;
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
msg += "Passed: " + group_passed + " / " + (group_passed + group_failed) + " " + ("(" + toPercentage(group_passed, group_passed + group_failed) + "%) ") + _chalk2.default.yellow("(es5)") + (": " + group_es5_passed + " / ") + (group_es5_passed + group_es5_failed + " ") + ("(" + toPercentage(group_es5_passed, group_es5_passed + group_es5_failed) + "%) ") + _chalk2.default.yellow("(es6)") + (": " + group_es6_passed + " / ") + (group_es6_passed + group_es6_failed + " ") + ("(" + toPercentage(group_es6_passed, group_es6_passed + group_es6_failed) + "%)");
if (args.verbose) {
console.log(msg);
if (errmsg) {
console.error(errmsg);
}
}
if (group_es5_failed + group_es6_failed > 0) {
failed_groups.push(msg);
}
numPassed += group_passed;
numPassedES5 += group_es5_passed;
numPassedES6 += group_es6_passed;
numFailed += group_failed;
numFailedES5 += group_es5_failed;
numFailedES6 += group_es6_failed;
}
var status = "=== RESULTS ===" + EOL + ("Passes: " + numPassed + " / " + (numPassed + numFailed) + " ") + ("(" + toPercentage(numPassed, numPassed + numFailed) + "%)") + EOL + ("ES5 passes: " + numPassedES5 + " / " + (numPassedES5 + numFailedES5) + " ") + ("(" + toPercentage(numPassedES5, numPassedES5 + numFailedES5) + "%) ") + EOL + ("ES6 passes: " + numPassedES6 + " / " + (numPassedES6 + numFailedES6) + " ") + ("(" + toPercentage(numPassedES6, numPassedES6 + numFailedES6) + "%)") + EOL + ("Skipped: " + numSkipped) + EOL + ("Timeouts: " + numTimeouts) + EOL;
console.log(status);
if (failed_groups.length !== 0) {
console.log("Groups with failures:");
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = failed_groups[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var groupMessage = _step4.value;
console.log(groupMessage);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
}
if (args.statusFile) {
_gracefulFs2.default.writeFileSync(args.statusFile, status);
}
// exit status
if (!args.filterString && (numPassedES5 < 11738 || numPassedES6 < 3981 || numTimeouts > 0)) {
console.error(_chalk2.default.red("Overall failure. Expected more tests to pass!"));
return 1;
} else {
// use 0 to avoid the npm error messages
return 0;
}
}
function getProgressBar(currentTestLength, originalTestLength, granularity) {
if (currentTestLength % granularity === 0 && currentTestLength !== 0) {
// print out a percent of tests completed to keep the user informed
return "Running... " + toPercentage(originalTestLength - currentTestLength, originalTestLength) + "%";
} else {
return "";
}
}
// Returns false if test processing should stop.
function handleTestResults(groups, test, testResults) {
// test results are in, add it to its corresponding group
if (!(test.groupName in groups)) {
groups[test.groupName] = [];
}
groups[test.groupName].push({ test: test, result: testResults });
return true;
}
// $FlowFixMe cluster.Worker is marked as not exported by the node API by flow.
function killWorkers(workers) {
for (var workerID in workers) {
workers[workerID].kill();
}
}
function toPercentage(x, total) {
if (total === 0) {
return 100;
}
return Math.floor(x / total * 100);
}
function create_test_message(name, success, err, isES6, isStrict) {
var checkmark = _chalk2.default.green("\u2713");
var xmark = _chalk2.default.red("\u2717");
var msg = "\t";
msg += (success ? checkmark : xmark) + " ";
msg += "" + (isES6 ? _chalk2.default.yellow("(es6) ") : "") + (isStrict ? "(strict)" : "(nostrict)") + ": " + name;
if (!success) {
(0, _invariant2.default)(err, "Error must be non null if success is false");
if (err.message) {
// split the message by newline, add tabs, and join
var parts = err.message.split(EOL);
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = parts[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var line = _step5.value;
msg += EOL + ("\t\t" + line);
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
msg += EOL;
} else if (err.stack) {
msg += JSON.stringify(err.stack);
}
}
return msg;
}
function getHarnesses(relativeTestPath) {
var harnessPath = "" + __dirname + relativeTestPath + "/harness";
var harnessesList = getFilesSync(harnessPath);
// convert to a mapping from harness name to file contents
var harnesses = {};
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = harnessesList[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var harness = _step6.value;
// sync is fine, it's an initialization stage and there's not that many
// harnesses
harnesses[_path2.default.basename(harness.location)] = _gracefulFs2.default.readFileSync(harness.location).toString();
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
return harnesses;
}
function workerRun(args) {
// NOTE: all harnesses (including contents of harness files) need to be
// used on workers. It needs to either be read from the fs once and
// distributed via IPC or once from each process. This is the
// "once from each process" approach.
// get all the harnesses
var harnesses = getHarnesses(args.relativeTestPath);
// we're a worker, run a portion of the tests
_process2.default.on("message", function (message) {
switch (message.type) {
case TestTask.sentinel:
// begin executing this TestTask
var task = TestTask.fromObject(message);
handleTest(task.file, harnesses, args.timeout, function (err, results) {
handleTestResultsMultiProcess(err, task.file, results);
});
break;
case QuitMessage.sentinel:
_process2.default.exit(0);
break;
default:
throw new Error("Worker #" + _process2.default.pid + " got an unexpected message:\n " + JSON.stringify(message));
}
});
}
function handleTestResultsMultiProcess(err, test, testResults) {
if (err) {
_process2.default.send(new ErrorMessage(err));
} else {
var msg = new DoneMessage(test);
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
try {
for (var _iterator7 = testResults[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
var t = _step7.value;
msg.testResults.push(t);
}
} catch (err) {
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion7 && _iterator7.return) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
try {
_process2.default.send(msg);
} catch (jsonCircularSerializationErr) {
// JSON circular serialization, ThrowCompletion is too deep to be
// serialized!
// Solution, truncate the "err" field if this happens
var _iteratorNormalCompletion8 = true;
var _didIteratorError8 = false;
var _iteratorError8 = undefined;
try {
for (var _iterator8 = msg.testResults[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var _t = _step8.value;
if (_t.err) {
_t.err = new Error(_t.err.message);
}
}
// now try again
} catch (err) {
_didIteratorError8 = true;
_iteratorError8 = err;
} finally {
try {
if (!_iteratorNormalCompletion8 && _iterator8.return) {
_iterator8.return();
}
} finally {
if (_didIteratorError8) {
throw _iteratorError8;
}
}
}
_process2.default.send(msg);
}
}
}
function handleTest(test, harnesses, timeout, cb) {
prepareTest(test, testFilterByContents, function (err, banners, testFileContents) {
if (err != null) {
cb(err, []);
return;
}
if (!banners) {
// skip this test
cb(null, []);
} else {
(0, _invariant2.default)(testFileContents, "testFileContents should not be null if banners are not None");
// filter out by flags, features, and includes
var keepThisTest = filterFeatures(banners) && filterFlags(banners) && filterIncludes(banners) && filterDescription(banners) && filterCircleCI(banners) && filterSneakyGenerators(banners, testFileContents);
var _testResults = [];
if (keepThisTest) {
// now run the test
_testResults = runTestWithStrictness(test, testFileContents, banners, harnesses, timeout);
}
cb(null, _testResults);
}
});
}
/**
* FIXME: this code is unsound in the presence of ENOENT (file not found)
* This function returns nested arrays of all the file names. It can be
* flattened at the call site, but the type hint is incorrect.
* DON'T USE THIS FUNCTION until it is fixed to behave exactly like getFilesSync
*/
/*
function getFiles(
filepath: string,
): Promise<TestFileInfo[]> {
return new Promise((resolve, reject) => {
fs.stat(filepath, (err, stat) => {
if (err !== null) {
reject(err);
} else {
if (stat.isFile()) {
// return an array of size 1
resolve([new TestFileInfo(filepath)]);
} else if (stat.isDirectory()) {
// recurse on its children
fs.readdir(filepath, (err, files) => {
if (err !== null) {
reject(err);
} else {
// FIXME flattening bug
// tmp is Promise<TestFileInfo[]>[] (array of promises of arrays)
// want to flatten that into Promise<TestFileInfo[]> where each
// promise is added to a single array
let tmp = files.map(f => getFiles(path.join(filepath, f)));
resolve(Promise.all(tmp));
}
});
}
}
});
});
}
*/
/**
* getFilesSync returns a TestFileInfo for each file that is underneath the
* directory ${filepath}. If ${filepath} is just a file, then it returns an
* array of size 1.
* This function synchronously fetches from the filesystem, as such it should
* only be used in initialization code that only runs once.
*/
function getFilesSync(filepath) {
var stat = _gracefulFs2.default.statSync(filepath);
if (stat.isFile()) {
return [new TestFileInfo(filepath, false)];
} else if (stat.isDirectory()) {
var subFiles = _gracefulFs2.default.readdirSync(filepath);
return flatten(subFiles.map(function (f) {
return getFilesSync(_path2.default.join(filepath, f));
}));
} else {
throw new Error("That type of file is not supported");
}
}
function flatten(arr) {
return arr.reduce(function (a, b) {
return a.concat(b);
}, []);
}
/**
* prepareTest opens the file corresponding to ${test} and calls ${cb} on the
* results, expect the ones for which ${filterFn} returns false.
* The value passed to ${cb} will be an error if the file could not be read,
* or the banner data for the test if successful.
* NOTE: if the test file contents match the filter function given, ${cb} will
* not be called for that test.
*/
function prepareTest(test, filterFn, cb) {
_gracefulFs2.default.readFile(test.location, function (err, contents) {
if (err != null) {
cb(err, null, null);
} else {
var contentsStr = contents.toString();
// check if this test should be filtered
if (!filterFn(test, contentsStr)) {
// skip this test
cb(null, null, null);
} else {
try {
var banners = getBanners(test, contentsStr);
cb(null, banners, contentsStr);
} catch (bannerParseErr) {
cb(bannerParseErr, null, null);
}
}
}
});
}
function createRealm(timeout) {
// Create a new realm.
var realm = (0, _construct_realm2.default)({
strictlyMonotonicDateNow: true,
timeout: timeout * 1000
});
(0, _globals2.default)(realm);
var executionContext = new _realm.ExecutionContext();
executionContext.realm = realm;
realm.pushContext(executionContext);
// Create the Host-Defined functions.
var $ = new _index.ObjectValue(realm);
$.defineNativeMethod("createRealm", 0, function (context) {
return createRealm(timeout).$;
});
$.defineNativeMethod("detachArrayBuffer", 1, function (context, _ref) {
var _ref2 = _slicedToArray(_ref, 1),
buffer = _ref2[0];
return (0, _arraybuffer.DetachArrayBuffer)(realm, buffer);
});
$.defineNativeMethod("evalScript", 1, function (context, _ref3) {
var _ref4 = _slicedToArray(_ref3, 1),
sourceText = _ref4[0];
// TODO: eval
return realm.intrinsics.undefined;
});
$.defineNativeProperty("global", realm.$GlobalObject);
var glob = realm.$GlobalObject;
glob.defineNativeProperty("$262", $);
glob.defineNativeMethod("print", 1, function (context, _ref5) {
var _ref6 = _slicedToArray(_ref5, 1),
arg = _ref6[0];
return realm.intrinsics.undefined;
});
return { realm: realm, $: $ };
}
/**
* runTest executes the test given by ${test} whose contents are
* ${testFileContents}.
* It returns None if the test should is skipped, otherwise it returns a
* TestResult.
*/
function runTest(test, testFileContents, data,
// eslint-disable-next-line flowtype/no-weak-types
harnesses, strict, timeout) {
var _createRealm = createRealm(timeout),
realm = _createRealm.realm;
// Run the test.
try {
try {
// execute the harnesss first
var _iteratorNormalCompletion9 = true;
var _didIteratorError9 = false;
var _iteratorError9 = undefined;
try {
for (var _iterator9 = ["sta.js", "assert.js"].concat(data.includes || [])[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var name = _step9.value;
var harness = harnesses[name];
var _completion = realm.$GlobalEnv.execute(harness, name);
if (_completion instanceof _completions.ThrowCompletion) throw _completion;
}
} catch (err) {
_didIteratorError9 = true;
_iteratorError9 = err;
} finally {
try {
if (!_iteratorNormalCompletion9 && _iterator9.return) {
_iterator9.return();
}
} finally {
if (_didIteratorError9) {
throw _iteratorError9;
}
}
}
var completion = realm.$GlobalEnv.execute((strict ? '"use strict";' + EOL : "") + testFileContents, test.location);
if (completion instanceof _completions.ThrowCompletion) throw completion;
if (completion instanceof _completions.AbruptCompletion) return new TestResult(false, strict, new Error("Unexpected abrupt completion"));
} catch (err) {
if (err.message === "Timed out") return new TestResult(false, strict, err);
if (!data.negative || data.negative !== err.name) {
throw err;
}
}
if (data.negative.type) {
throw new Error("Was supposed to error with type " + data.negative.type + " but passed");
}
// succeeded
return new TestResult(true, strict);
} catch (err) {
if (err.value && err.value.$Prototype && err.value.$Prototype.intrinsicName === "SyntaxError.prototype") {
return null;
}
var stack = err.stack;
if (data.negative.type) {
var type = data.negative.type;
if (err && err instanceof _completions.ThrowCompletion && (0, _get.Get)(realm, err.value, "name").value === type) {
// Expected an error and got one.
return new TestResult(true, strict);
} else {
// Expected an error, but got something else.
if (err && err instanceof _completions.ThrowCompletion) {
return new TestResult(false, strict, err);
} else {
return new TestResult(false, strict, new Error("Expected an error, but got something else: " + err.message));
}
}
} else {
// Not expecting an error, but got one.
try {
if (err && err instanceof _completions.ThrowCompletion) {
var interpreterStack = void 0;
if (err.value instanceof _index.ObjectValue) {
if (err.value.$HasProperty("stack")) {
interpreterStack = _singletons.To.ToStringPartial(realm, (0, _get.Get)(realm, err.value, "stack"));
} else {
interpreterStack = _singletons.To.ToStringPartial(realm, (0, _get.Get)(realm, err.value, "message"));
}
// filter out if the error stack is due to async
if (interpreterStack.includes("async ")) {
return null;
}
} else if (err.value instanceof _index.StringValue) {
interpreterStack = err.value.value;
if (interpreterStack === "only plain identifiers are supported in parameter lists") {
return null;
}
}
// Many strict-only tests involving eval check if certain SyntaxErrors are thrown.
// Some of those would require changes to Babel to support properly, and some we should handle ourselves in Prepack some day.
// But for now, ignore.
if (testFileContents.includes("eval(") && strict) {
return null;
}
if (interpreterStack) {
stack = "Interpreter: " + interpreterStack + EOL + "Native: " + err.nativeStack;
}
}
} catch (_err) {
stack = _err.stack;
}
return new TestResult(false, strict, new Error("Got an error, but was not expecting one:" + EOL + stack));
}
}
}
/**
* Returns true if ${test} should be run, false otherwise
*/
function testFilterByMetadata(test) {
// filter hidden files
if (_path2.default.basename(test.location)[0] === ".") return false;
// emacs!
if (test.location.includes("~")) return false;
// SIMD isn't in JS yet
if (test.location.includes("Simd")) return false;
// temporarily disable intl402 tests (ES5)
if (test.location.includes("intl402") && !test.location.includes("/Date/prototype/to")) {
return false;
}
// temporarily disable tests which use realm.
if (test.location.includes("realm")) return false;
// temporarily disable tests which use with. (??)
if (test.location.includes("/with/")) return false;
// disable tests which use Atomics
if (test.location.includes("/Atomics/")) return false;
// disable tests which use generators
if (test.location.includes("/generators/")) return false;
if (test.location.includes("/yield/")) return false;
// disable tests which use modules
if (test.location.includes("/module-code/")) return false;
// disable browser specific tests
if (test.location.includes("/annexB/")) return false;
// disable tail-call optimization tests
if (test.location.includes("tco")) return false;
// disable nasty unicode tests.
if (test.location.includes("U180") || test.location.includes("u180") || test.location.includes("mongolian")) return false;
// disable function toString tests.
if (test.location.includes("Function/prototype/toString")) return false;
// disable tests that check for detached-buffer-after-toindex
if (test.location.includes("detached-buffer-after-toindex")) return false;
// disable tests to check for detatched-buffer during iteration
if (test.location.includes("detach-typedarray-in-progress.js")) return false;
// disable broken RegExp tests
if (test.location.includes("RegExp/S15.10.2.12_A1_T1.js")) return false;
if (test.location.includes("RegExp/S15.10.2.12_A2_T1.js")) return false;
if (test.location.includes("RegExp/prototype/Symbol.search/lastindex-no-restore")) return false;
if (test.location.includes("RegExp/prototype/exec/failure-lastindex-no-access.js")) return false;
if (test.location.includes("RegExp/prototype/exec/success-lastindex-no-access.js")) return false;
// disable RegExp tests that use extended unicode
if (test.location.includes("Symbol.match/builtin-success-u-return-val-groups")) return false;
// disable SharedArrayBuffer tests
if (test.location.includes("sharedarraybuffer") || test.location.includes("SharedArrayBuffer")) return false;
return true;
}
function testFilterByContents(test, testFileContents) {
// ES6 tests (can only be verified by contents, not by metadata)
var is_es6 = testFileContents.includes(EOL + "es6id: ");
test.isES6 = is_es6;
// Ignore phase: early tests because those are errors that babel should catch
// not issues related to Prepack
var phase_early = testFileContents.indexOf(" phase: early");
var end_of_comment = testFileContents.indexOf("---*/");
if (phase_early > 0 && phase_early < end_of_comment) return false;
var esid_pending = testFileContents.indexOf("esid: pending");
if (esid_pending > 0 && esid_pending < end_of_comment) return false;
// disable tests that require parser to throw SyntaxError in strict Mode
if (test.location.includes("/directive-prologue/") && testFileContents.includes("assert.throws(SyntaxError,")) return false;
// disable SharedArrayBuffer tests
if (testFileContents.includes("SharedArrayBuffer")) return false;
return true;
}
function filterFlags(data) {
return !data.flags.includes("async");
}
function filterFeatures(data) {
var features = data.features;
if (features.includes("default-parameters")) return false;
if (features.includes("generators")) return false;
if (features.includes("generator")) return false;
if (features.includes("BigInt")) return false;
if (features.includes("class-fields")) return false;
if (features.includes("async-iteration")) return false;
if (features.includes("Function.prototype.toString")) return false;
if (features.includes("SharedArrayBuffer")) return false;
if (features.includes("cross-realm")) return false;
if (features.includes("atomics")) return false;
if (features.includes("u180e")) return false;
if (features.includes("Symbol.isConcatSpreadable")) return false;
if (features.includes("destructuring-binding")) return false;
if (features.includes("IsHTMLDDA")) return false;
if (features.includes("regexp-unicode-property-escapes")) return false;
if (features.includes("regexp-named-groups")) return false;
if (features.includes("regexp-lookbehind")) return false;
if (features.includes("regexp-dotall")) return false;
if (features.includes("optional-catch-binding")) return false;
if (features.includes("Symbol.asyncIterator")) return false;
if (features.includes("Promise.prototype.finally")) return false;
return true;
}
function filterIncludes(data) {
// disable tail call optimization tests.
return !data.includes.includes("tco-helper.js");
}
function filterDescription(data) {
// For now, "Complex tests" is used in the description of some
// encode/decodeURI tests to indicate that they are long running.
// Filter these
return !data.description.includes("Complex tests") && !data.description.includes("iterating") && !data.description.includes("iterable");
}
function filterCircleCI(data) {
var skipTests = ["7.8.5_A1.4_T2", "7.8.5_A2.4_T2", "7.8.5_A2.1_T2", "7.8.5_A1.1_T2", "15.1.2.2_A8", "15.1.2.3_A6", "7.4_A5", "7.4_A6", "15.10.2.12_A3_T1", "15.10.2.12_A4_T1", "15.10.2.12_A5_T1", "15.10.2.12_A6_T1"];
var skipTests6 = ["22.1.3.1_3"];
return !!_process2.default.env.NIGHTLY_BUILD || skipTests.indexOf(data.es5id) < 0 && skipTests6.indexOf(data.es6id) < 0;
}
function filterSneakyGenerators(data, testFileContents) {
// There are some sneaky tests that use generators but are not labeled with
// the "generators" or "generator" feature tag. Here we use a simple heuristic
// to filter out tests with sneaky generators.
if (data.features.includes("destructuring-binding")) {
return !testFileContents.includes("function*") && !testFileContents.includes("*method");
}
return true;
}
/**
* Run a given ${test} whose file contents are ${testFileContents} and return
* a list of results, one for each strictness level (strict or not).
* If the list's length is less than 2, than the missing tests were skipped.
*/
function runTestWithStrictness(test, testFileContents, data,
// eslint-disable-next-line flowtype/no-weak-types
harnesses, timeout) {
var fn = function fn(strict) {
return runTest(test, testFileContents, data, harnesses, strict, timeout);
};
if (data.flags.includes("onlyStrict")) {
if (testFileContents.includes("assert.throws(SyntaxError")) return [];
var _result = fn(true);
return _result ? [_result] : [];
} else if (data.flags.includes("noStrict") || test.location.includes("global/global-object.js")) {
if (testFileContents.includes('"use strict";') && testFileContents.includes("assert.throws(SyntaxError")) return [];
var _result2 = fn(false);
return _result2 ? [_result2] : [];
} else {
// run both strict and non-strict
var strictResult = fn(true);
var unStrictResult = fn(false);
var finalResult = [];
if (strictResult) {
finalResult.push(strictResult);
}
if (unStrictResult) {
finalResult.push(unStrictResult);
}
return finalResult;
}
}
/**
* Parses the banners, and returns the banners as arbitrary object data if they
* were found, or returns an error if the banner it couldn't be parsed.
*/
function getBanners(test, fileContents) {
var banners = fileContents.match(/---[\s\S]+---/);
var data = {};
if (banners) {
var bannerText = banners[0] || "";
if (bannerText.includes("StrictMode")) {
if (bannerText.includes("'arguments'")) return null;
if (bannerText.includes("'caller'")) return null;
} else if (bannerText.includes('properties "caller" or "arguments"')) {
return null;
} else if (bannerText.includes("function caller")) {
return null;
} else if (bannerText.includes("attribute of 'caller' property")) {
return null;
} else if (bannerText.includes("attribute of 'arguments'")) {
return null;
} else if (bannerText.includes("poisoned")) return null;
try {
data = _jsYaml2.default.safeLoad(banners[0].slice(3, -3));
} catch (e) {
// Some versions of test262 have comments inside of yaml banners.
// parsing these will usually fail.
return null;
}
}
return BannerData.fromObject(data);
}
//# sourceMappingURL=test262-runner.js.map