501 lines
17 KiB
JavaScript
501 lines
17 KiB
JavaScript
"use strict";
|
|
|
|
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; }; }();
|
|
|
|
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 _path = require("path");
|
|
|
|
var _path2 = _interopRequireDefault(_path);
|
|
|
|
var _fs = require("fs");
|
|
|
|
var _fs2 = _interopRequireDefault(_fs);
|
|
|
|
var _jsYaml = require("js-yaml");
|
|
|
|
var _jsYaml2 = _interopRequireDefault(_jsYaml);
|
|
|
|
var _test262Integrator = require("test262-integrator");
|
|
|
|
var _test262Integrator2 = _interopRequireDefault(_test262Integrator);
|
|
|
|
var _tty = require("tty");
|
|
|
|
var _tty2 = _interopRequireDefault(_tty);
|
|
|
|
var _minimist2 = require("minimist");
|
|
|
|
var _minimist3 = _interopRequireDefault(_minimist2);
|
|
|
|
var _globals = require("../lib/globals.js");
|
|
|
|
var _globals2 = _interopRequireDefault(_globals);
|
|
|
|
var _completions = require("../lib/completions.js");
|
|
|
|
var _arraybuffer = require("../lib/methods/arraybuffer.js");
|
|
|
|
var _construct_realm = require("../lib/construct_realm.js");
|
|
|
|
var _construct_realm2 = _interopRequireDefault(_construct_realm);
|
|
|
|
var _index = require("../lib/values/index.js");
|
|
|
|
var _realm = require("../lib/realm.js");
|
|
|
|
var _singletons = require("../lib/singletons.js");
|
|
|
|
var _get = require("../lib/methods/get.js");
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
|
|
* 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.
|
|
*/
|
|
|
|
var filters = _jsYaml2.default.safeLoad(_fs2.default.readFileSync(_path2.default.join(__dirname, "./test262-filters.yml"), "utf8"));
|
|
|
|
var TestAttrs = function TestAttrs() {
|
|
_classCallCheck(this, TestAttrs);
|
|
};
|
|
|
|
var TestAttrsNegative = function TestAttrsNegative() {
|
|
_classCallCheck(this, TestAttrsNegative);
|
|
};
|
|
|
|
var TestFlags = function TestFlags() {
|
|
_classCallCheck(this, TestFlags);
|
|
};
|
|
|
|
var TestObject = function TestObject() {
|
|
_classCallCheck(this, TestObject);
|
|
};
|
|
|
|
var Result = function Result(pass, error, skip) {
|
|
_classCallCheck(this, Result);
|
|
|
|
this.pass = pass;
|
|
this.error = error;
|
|
this.skip = skip;
|
|
};
|
|
|
|
var TestResult = function (_TestObject) {
|
|
_inherits(TestResult, _TestObject);
|
|
|
|
function TestResult() {
|
|
_classCallCheck(this, TestResult);
|
|
|
|
return _possibleConstructorReturn(this, (TestResult.__proto__ || Object.getPrototypeOf(TestResult)).apply(this, arguments));
|
|
}
|
|
|
|
return TestResult;
|
|
}(TestObject);
|
|
|
|
function execute(timeout, test) {
|
|
var contents = test.contents,
|
|
attrs = test.attrs,
|
|
file = test.file,
|
|
scenario = test.scenario;
|
|
|
|
var _createRealm = createRealm(timeout),
|
|
realm = _createRealm.realm;
|
|
|
|
var strict = scenario === "strict mode";
|
|
|
|
// Run the test.
|
|
try {
|
|
try {
|
|
var completion = realm.$GlobalEnv.execute(contents, file);
|
|
if (completion instanceof _completions.ThrowCompletion) throw completion;
|
|
if (completion instanceof _completions.AbruptCompletion) {
|
|
return new Result(false, new Error("Unexpected abrupt completion"));
|
|
}
|
|
} catch (err) {
|
|
if (err.message === "Timed out") return new Result(false, err);
|
|
if (!attrs.negative) {
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
if (attrs.negative && attrs.negative.type) {
|
|
throw new Error("Was supposed to error with type " + attrs.negative.type + " but passed");
|
|
}
|
|
|
|
// succeeded
|
|
return new Result(true);
|
|
} catch (err) {
|
|
if (err.value && err.value.$Prototype && err.value.$Prototype.intrinsicName === "SyntaxError.prototype") {
|
|
// Skip test
|
|
return new Result(false, null, true);
|
|
}
|
|
|
|
var stack = err.stack;
|
|
if (attrs.negative && attrs.negative.type) {
|
|
var type = attrs.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 Result(true);
|
|
} else {
|
|
// Expected an error, but got something else.
|
|
if (err && err instanceof _completions.ThrowCompletion) {
|
|
return new Result(false, err);
|
|
} else {
|
|
var err2 = new Error("Expected an error, but got something else: " + err.message);
|
|
return new Result(false, err2);
|
|
}
|
|
}
|
|
} 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 ")) {
|
|
// Skip test
|
|
return new Result(false, null, true);
|
|
}
|
|
} else if (err.value instanceof _index.StringValue) {
|
|
interpreterStack = err.value.value;
|
|
if (interpreterStack === "only plain identifiers are supported in parameter lists") {
|
|
// Skip test
|
|
return new Result(false, null, true);
|
|
}
|
|
}
|
|
|
|
// 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 (contents.includes("eval(") && strict) {
|
|
// Skip test
|
|
return new Result(false, null, true);
|
|
}
|
|
|
|
if (interpreterStack) {
|
|
stack = "Interpreter: " + interpreterStack + "\nNative: " + err.nativeStack;
|
|
}
|
|
}
|
|
} catch (_err) {
|
|
stack = _err.stack;
|
|
}
|
|
|
|
return new Result(false, new Error("Got an error, but was not expecting one:\n" + stack));
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
$.defineNativeMethod("destroy", 0, function () {
|
|
return realm.intrinsics.undefined;
|
|
});
|
|
|
|
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, $: $ };
|
|
}
|
|
|
|
var ReportResults = function () {
|
|
function ReportResults(name) {
|
|
_classCallCheck(this, ReportResults);
|
|
|
|
this.skipped = 0;
|
|
this.passed = 0;
|
|
this.total = 0;
|
|
this.name = name;
|
|
}
|
|
|
|
_createClass(ReportResults, [{
|
|
key: "report",
|
|
value: function report(pass, skip) {
|
|
if (skip) {
|
|
this.skipped += 1;
|
|
} else if (pass) {
|
|
this.passed += 1;
|
|
}
|
|
|
|
this.total += 1;
|
|
}
|
|
}, {
|
|
key: "percentage",
|
|
value: function percentage(x, total) {
|
|
if (total === 0) {
|
|
return "100%";
|
|
}
|
|
return (x / total * 100).toFixed(2) + "%";
|
|
}
|
|
}, {
|
|
key: "info",
|
|
value: function info(title, x, y, force) {
|
|
if (!force && x === 0) {
|
|
return "";
|
|
}
|
|
|
|
return title + " " + x + "/" + y + " (" + this.percentage(x, y) + ")";
|
|
}
|
|
}, {
|
|
key: "formatResult",
|
|
value: function formatResult() {
|
|
var subtotal = this.total - this.skipped;
|
|
var failed = subtotal - this.passed;
|
|
return [this.name + ": ", this.info("Ran", subtotal, this.total, true), this.info(", Passed", this.passed, subtotal, false), this.info(", Failed", failed, subtotal, false), this.info(", Skipped", this.skipped, this.total, false)].join("");
|
|
}
|
|
}], [{
|
|
key: "safeTypeReturn",
|
|
value: function safeTypeReturn(map, key) {
|
|
var result = map.get(key);
|
|
if (result instanceof ReportResults) {
|
|
return result;
|
|
}
|
|
throw new Error("Wrong type set in a list of ReportResults");
|
|
}
|
|
}]);
|
|
|
|
return ReportResults;
|
|
}();
|
|
|
|
function processResults(verbose, statusFile, results) {
|
|
var status = "\n";
|
|
var foldersMap = new Map();
|
|
var featuresMap = new Map();
|
|
var allResults = new ReportResults("\nTotal");
|
|
|
|
console.log("\n");
|
|
|
|
results.forEach(function (_ref7) {
|
|
var file = _ref7.file,
|
|
scenario = _ref7.scenario,
|
|
features = _ref7.attrs.features,
|
|
_ref7$result = _ref7.result;
|
|
_ref7$result = _ref7$result === undefined ? {} : _ref7$result;
|
|
var pass = _ref7$result.pass,
|
|
skip = _ref7$result.skip,
|
|
error = _ref7$result.error;
|
|
|
|
// Limits the report result in a max depth of 5 folders.
|
|
// This fits most cases for built-ins prototype methods as e.g.
|
|
// test/built-ins/Array/prototype/sort
|
|
var folder = _path2.default.dirname(file).split(_path2.default.sep).slice(1, 5).join(_path2.default.sep);
|
|
var folderResults = void 0;
|
|
|
|
if (!foldersMap.has(folder)) {
|
|
folderResults = new ReportResults(folder);
|
|
foldersMap.set(folder, folderResults);
|
|
} else {
|
|
folderResults = ReportResults.safeTypeReturn(foldersMap, folder);
|
|
}
|
|
|
|
if (folderResults) {
|
|
folderResults.report(!!pass, !!skip);
|
|
}
|
|
allResults.report(!!pass, !!skip);
|
|
|
|
if (features) {
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = features[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var feature = _step.value;
|
|
|
|
var featureResults = void 0;
|
|
|
|
if (!featuresMap.has(feature)) {
|
|
featureResults = new ReportResults(feature);
|
|
featuresMap.set(feature, featureResults);
|
|
} else {
|
|
featureResults = ReportResults.safeTypeReturn(featuresMap, feature);
|
|
}
|
|
|
|
if (featureResults) {
|
|
featureResults.report(!!pass, !!skip);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (verbose && !skip && !pass) {
|
|
var message = "";
|
|
if (error && error.message) {
|
|
message = error.message;
|
|
}
|
|
status += "Failed: " + file + " (" + scenario + ")\n" + message + "\n\n";
|
|
}
|
|
});
|
|
|
|
foldersMap.forEach(function (folderResults) {
|
|
status += folderResults.formatResult();
|
|
status += "\n";
|
|
});
|
|
|
|
status += "\nFeatures:\n\n";
|
|
|
|
featuresMap.forEach(function (featureResults) {
|
|
status += featureResults.formatResult();
|
|
status += "\n";
|
|
});
|
|
|
|
status += allResults.formatResult();
|
|
|
|
console.log(status);
|
|
|
|
if (statusFile) {
|
|
_fs2.default.writeFileSync(statusFile, status);
|
|
}
|
|
}
|
|
|
|
var MasterProgramArgs = function MasterProgramArgs(verbose, timeout, statusFile, paths, testDir) {
|
|
_classCallCheck(this, MasterProgramArgs);
|
|
|
|
this.verbose = verbose;
|
|
this.timeout = timeout;
|
|
this.statusFile = statusFile;
|
|
this.paths = paths;
|
|
this.testDir = testDir;
|
|
};
|
|
|
|
function masterArgsParse() {
|
|
var _minimist = (0, _minimist3.default)(process.argv.slice(2), {
|
|
string: ["statusFile", "testDir"],
|
|
boolean: ["verbose"],
|
|
default: {
|
|
testDir: ["..", "test", "test262"].join(_path2.default.sep),
|
|
verbose: process.stdout instanceof _tty2.default.WriteStream ? false : true,
|
|
statusFile: "",
|
|
timeout: 10
|
|
}
|
|
}),
|
|
_paths = _minimist._,
|
|
verbose = _minimist.verbose,
|
|
timeout = _minimist.timeout,
|
|
statusFile = _minimist.statusFile,
|
|
testDir = _minimist.testDir;
|
|
|
|
// Test paths can be provided as "built-ins/Array", "language/statements/class", etc.
|
|
|
|
|
|
var paths = _paths.map(function (p) {
|
|
return _path2.default.join("test", p);
|
|
});
|
|
if (typeof verbose !== "boolean") {
|
|
throw new Error("verbose must be a boolean (either --verbose or not)");
|
|
}
|
|
if (typeof timeout !== "number") {
|
|
throw new Error("timeout must be a number (in seconds) (--timeout 10)");
|
|
}
|
|
if (typeof statusFile !== "string") {
|
|
throw new Error("statusFile must be a string (--statusFile file.txt)");
|
|
}
|
|
if (typeof testDir !== "string") {
|
|
throw new Error("testDir must be a string (--testDir ../test/test262)");
|
|
}
|
|
|
|
return new MasterProgramArgs(verbose, timeout, statusFile, paths, testDir);
|
|
}
|
|
|
|
function usage(message) {
|
|
console.error(["Illegal argument: " + message, "Usage: " + process.argv[0] + " " + process.argv[1], "[--verbose] (defaults to false)", "[--timeout <number>] (defaults to 10)", "[--statusFile <string>]", "[--testDir <string>] (defaults to ../test/test262)"].join("\n"));
|
|
}
|
|
|
|
function main() {
|
|
try {
|
|
var _masterArgsParse = masterArgsParse(),
|
|
testDir = _masterArgsParse.testDir,
|
|
verbose = _masterArgsParse.verbose,
|
|
paths = _masterArgsParse.paths,
|
|
statusFile = _masterArgsParse.statusFile,
|
|
timeout = _masterArgsParse.timeout;
|
|
|
|
// Execution
|
|
|
|
|
|
(0, _test262Integrator2.default)({
|
|
filters: filters,
|
|
execute: execute.bind(null, timeout),
|
|
testDir: _path2.default.join(__dirname, testDir),
|
|
verbose: verbose,
|
|
paths: paths.length ? paths : null
|
|
}).then(processResults.bind(null, verbose, statusFile), function (err) {
|
|
console.error("Error running the tests: " + err);
|
|
process.exit(1);
|
|
}).then(function () {
|
|
return process.exit(0);
|
|
});
|
|
} catch (e) {
|
|
usage(e.message);
|
|
process.exit(2);
|
|
}
|
|
}
|
|
|
|
main();
|
|
//# sourceMappingURL=test262.js.map
|