698 lines
34 KiB
JavaScript
698 lines
34 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"); } }; }(); /**
|
|
* 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 _invariant = require("../lib/invariant.js");
|
|
|
|
var _invariant2 = _interopRequireDefault(_invariant);
|
|
|
|
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 FatalError = require("../lib/errors.js").FatalError;
|
|
var prepackSources = require("../lib/prepack-node.js").prepackSources;
|
|
|
|
|
|
var Serializer = require("../lib/serializer/index.js").default;
|
|
var construct_realm = require("../lib/construct_realm.js").default;
|
|
var initializeGlobals = require("../lib/globals.js").default;
|
|
var chalk = require("chalk");
|
|
var path = require("path");
|
|
var fs = require("fs");
|
|
var vm = require("vm");
|
|
var os = require("os");
|
|
var minimist = require("minimist");
|
|
var babel = require("babel-core");
|
|
var child_process = require("child_process");
|
|
var EOL = os.EOL;
|
|
var execSpec = void 0;
|
|
|
|
function transformWithBabel(code, plugins, presets) {
|
|
return babel.transform(code, {
|
|
plugins: plugins,
|
|
presets: presets
|
|
}).code;
|
|
}
|
|
|
|
function search(dir, relative) {
|
|
var tests = [];
|
|
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = fs.readdirSync(dir)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var name = _step.value;
|
|
|
|
var loc = path.join(dir, name);
|
|
var stat = fs.statSync(loc);
|
|
|
|
if (stat.isFile()) {
|
|
tests.push({
|
|
file: fs.readFileSync(loc, "utf8"),
|
|
name: path.join(relative, name)
|
|
});
|
|
} else if (stat.isDirectory()) {
|
|
tests = tests.concat(search(loc, path.join(relative, name)));
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
return tests;
|
|
}
|
|
|
|
var LAZY_OBJECTS_RUNTIME_NAME = "LazyObjectsRuntime";
|
|
var tests = search(__dirname + "/../test/serializer", "test/serializer");
|
|
|
|
// run JS subprocess
|
|
// externalSpec defines how to invoke external REPL and how to print.
|
|
// - cmd - cmd to execute, script is piped into this.
|
|
// - printName - name of function which can be used to print to stdout.
|
|
function execExternal(externalSpec, code) {
|
|
// essentially the code from execInContext run through babel
|
|
var script = "\n var global = this;\n var self = this;\n var _logOutput = \"\";\n function write(prefix, values) {\n _logOutput += \"\\n\" + prefix + values.join(\"\");\n }\n var cachePrint = " + externalSpec.printName + ";\n global.console = {}\n global.console.log = function log() {\n for (var _len = arguments.length, s = Array(_len), _key = 0; _key < _len; _key++) {\n s[_key] = arguments[_key];\n }\n write(\"\", s);\n };\n global.console.warn = function warn() {\n for (var _len2 = arguments.length, s = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n s[_key2] = arguments[_key2];\n }\n write(\"WARN:\", s);\n };\n global.console.error = function error() {\n for (var _len3 = arguments.length, s = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n s[_key3] = arguments[_key3];\n }\n write(\"ERROR:\", s);\n };\n try {\n " + code + "\n cachePrint(inspect() + _logOutput);\n } catch (e) {\n cachePrint(e);\n }";
|
|
|
|
var child = child_process.spawnSync(externalSpec.cmd, { input: script });
|
|
|
|
var output = String(child.stdout);
|
|
|
|
return String(output.trim());
|
|
}
|
|
|
|
function augmentCodeWithLazyObjectSupport(code, lazyRuntimeName) {
|
|
var mockLazyObjectsSupport = "\n /* Lazy objects mock support begin */\n var " + lazyRuntimeName + " = {\n _lazyObjectIds: new Map(),\n _callback: null,\n setLazyObjectInitializer: function(callback) {\n this._callback = callback;\n },\n createLazyObject: function(id) {\n var obj = {};\n this._lazyObjectIds.set(obj, id);\n return obj;\n },\n hydrateObject: function(obj) {\n const AlreadyHydratedLazyId = -1;\n const lazyId = this._lazyObjectIds.get(obj);\n if (lazyId === AlreadyHydratedLazyId) {\n return;\n }\n this._callback(obj, lazyId);\n this._lazyObjectIds.set(obj, AlreadyHydratedLazyId);\n }\n };\n\n var __hydrationHook = {\n get: function(target, prop) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.get(target, prop);\n },\n set: function(target, property, value, receiver) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.set(target, property, value, receiver);\n },\n has: function(target, prop) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.has(target, prop);\n },\n getOwnPropertyDescriptor: function(target, prop) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.getOwnPropertyDescriptor(target, prop);\n },\n ownKeys: function(target) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.ownKeys(target);\n },\n defineProperty: function(target, property, descriptor) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.defineProperty(target, property, descriptor);\n },\n isExtensible: function(target) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.isExtensible(target);\n },\n preventExtensions: function(target) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.preventExtensions(target);\n },\n deleteProperty: function(target, prop) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.deleteProperty(target, prop);\n },\n getPrototypeOf: function(target) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.getPrototypeOf(target);\n },\n setPrototypeOf: function(target, prototype) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.setPrototypeOf(target, prototype);\n },\n apply: function(target, thisArg, argumentsList) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.apply(target, thisArg, argumentsList);\n },\n construct: function(target, argumentsList, newTarget) {\n " + LAZY_OBJECTS_RUNTIME_NAME + ".hydrateObject(target);\n return Reflect.construct(target, argumentsList, newTarget);\n }\n };\n /* Lazy objects mock support end */\n ";
|
|
function wrapLazyObjectWithProxyHook(lazyCode) {
|
|
var lazyObjectCreationRegex = new RegExp("(" + lazyRuntimeName + ".createLazyObject\\(\\d+\\))", "g");
|
|
return lazyCode.replace(lazyObjectCreationRegex, "new Proxy($1, __hydrationHook)");
|
|
}
|
|
code = wrapLazyObjectWithProxyHook(code);
|
|
return mockLazyObjectsSupport + "\n " + code + "; // keep newline here as code may end with comment";
|
|
}
|
|
|
|
// run code in a seperate context
|
|
function execInContext(code) {
|
|
var script = new vm.Script("var global = this;\n var self = this;\n " + code + "\n report(inspect());", { cachedDataProduced: false });
|
|
var result = "";
|
|
var logOutput = "";
|
|
|
|
function write(prefix, values) {
|
|
logOutput += "\n" + prefix + values.join("");
|
|
}
|
|
script.runInNewContext({
|
|
setTimeout: setTimeout,
|
|
setInterval: setInterval,
|
|
clearTimeout: clearTimeout,
|
|
clearInterval: clearInterval,
|
|
report: function report(s) {
|
|
result = s;
|
|
},
|
|
console: {
|
|
log: function log() {
|
|
for (var _len = arguments.length, s = Array(_len), _key = 0; _key < _len; _key++) {
|
|
s[_key] = arguments[_key];
|
|
}
|
|
|
|
write("", s);
|
|
},
|
|
warn: function warn() {
|
|
for (var _len2 = arguments.length, s = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
s[_key2] = arguments[_key2];
|
|
}
|
|
|
|
write("WARN:", s);
|
|
},
|
|
error: function error() {
|
|
for (var _len3 = arguments.length, s = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
|
s[_key3] = arguments[_key3];
|
|
}
|
|
|
|
write("ERROR:", s);
|
|
}
|
|
}
|
|
});
|
|
return (result + logOutput).trim();
|
|
}
|
|
|
|
function parseFunctionOrderings(code) {
|
|
var orders = [];
|
|
var functionOrderPattern = /Function ordering: (\d+)/g;
|
|
var match = void 0;
|
|
while ((match = functionOrderPattern.exec(code)) != null) {
|
|
orders.push(match[1]);
|
|
}
|
|
return orders;
|
|
}
|
|
|
|
function verifyFunctionOrderings(code) {
|
|
var orders = parseFunctionOrderings(code);
|
|
for (var i = 1; i < orders.length; ++i) {
|
|
(0, _invariant2.default)(orders[i] !== orders[i - 1]);
|
|
if (orders[i] < orders[i - 1]) {
|
|
console.error(chalk.red("Funtion ordering is not preserved: function " + orders[i - 1] + " is before " + orders[i]));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function unescapleUniqueSuffix(code, uniqueSuffix) {
|
|
return uniqueSuffix != null ? code.replace(new RegExp(uniqueSuffix, "g"), "") : code;
|
|
}
|
|
|
|
function runTest(name, code, options, args) {
|
|
console.log(chalk.inverse(name) + " " + JSON.stringify(options));
|
|
var compatibility = code.includes("// jsc") ? "jsc-600-1-4-17" : undefined;
|
|
var initializeMoreModules = code.includes("// initialize more modules");
|
|
var delayUnsupportedRequires = code.includes("// delay unsupported requires");
|
|
if (code.includes("// inline expressions")) options.inlineExpressions = true;
|
|
if (code.includes("// do not inline expressions")) options.inlineExpressions = false;
|
|
if (code.includes("// omit invariants")) options.omitInvariants = true;
|
|
if (code.includes("// additional functions")) options.additionalFunctions = ["additional1", "additional2"];
|
|
if (code.includes("// abstract effects")) options.abstractEffectsInAdditionalFunctions = true;
|
|
if (code.includes("// exceeds stack limit")) options.maxStackDepth = 10;
|
|
if (code.includes("// react")) {
|
|
options.reactEnabled = true;
|
|
options.reactOutput = "jsx";
|
|
}
|
|
var compileJSXWithBabel = code.includes("// babel:jsx");
|
|
var functionCloneCountMatch = code.match(/\/\/ serialized function clone count: (\d+)/);
|
|
options = Object.assign({}, options, {
|
|
compatibility: compatibility,
|
|
debugNames: args.debugNames,
|
|
initializeMoreModules: initializeMoreModules,
|
|
delayUnsupportedRequires: delayUnsupportedRequires,
|
|
errorHandler: function errorHandler(diag) {
|
|
return "Fail";
|
|
},
|
|
internalDebug: true,
|
|
serialize: true,
|
|
uniqueSuffix: ""
|
|
}); // Since PrepackOptions is an exact type I have to cast
|
|
if (code.includes("// throws introspection error")) {
|
|
try {
|
|
var realmOptions = {
|
|
serialize: true,
|
|
compatibility: compatibility,
|
|
uniqueSuffix: "",
|
|
errorHandler: function errorHandler(diag) {
|
|
return "Fail";
|
|
},
|
|
maxStackDepth: options.maxStackDepth
|
|
};
|
|
var realm = construct_realm(realmOptions);
|
|
initializeGlobals(realm);
|
|
var serializerOptions = {
|
|
initializeMoreModules: initializeMoreModules,
|
|
delayUnsupportedRequires: delayUnsupportedRequires,
|
|
internalDebug: true,
|
|
additionalFunctions: options.additionalFunctions,
|
|
lazyObjectsRuntime: options.lazyObjectsRuntime
|
|
};
|
|
var serializer = new Serializer(realm, serializerOptions);
|
|
var sources = [{ filePath: name, fileContents: code }];
|
|
var serialized = serializer.init(sources, false);
|
|
if (!serialized) {
|
|
console.error(chalk.red("Error during serialization"));
|
|
} else {
|
|
console.error(chalk.red("Test should have caused introspection error!"));
|
|
}
|
|
} catch (err) {
|
|
if (err instanceof FatalError) return true;
|
|
console.error("Test should have caused introspection error, but instead caused a different internal error!");
|
|
console.error(err);
|
|
console.error(err.stack);
|
|
}
|
|
return false;
|
|
} else if (code.includes("// cannot serialize")) {
|
|
try {
|
|
prepackSources([{ filePath: name, fileContents: code, sourceMapContents: "" }], options);
|
|
} catch (err) {
|
|
if (err instanceof FatalError) {
|
|
return true;
|
|
}
|
|
console.error(err);
|
|
console.error(err.stack);
|
|
}
|
|
console.error(chalk.red("Test should have caused error during serialization!"));
|
|
return false;
|
|
} else if (code.includes("// no effect")) {
|
|
try {
|
|
var _serialized = prepackSources([{ filePath: name, fileContents: code, sourceMapContents: "" }], options);
|
|
if (!_serialized) {
|
|
console.error(chalk.red("Error during serialization!"));
|
|
return false;
|
|
}
|
|
if (!_serialized.code.trim()) {
|
|
return true;
|
|
}
|
|
console.error(chalk.red("Generated code should be empty but isn't!"));
|
|
console.error(chalk.underline("original code"));
|
|
console.error(code);
|
|
console.error(chalk.underline("generated code"));
|
|
console.error(_serialized.code);
|
|
} catch (err) {
|
|
console.error(err);
|
|
console.error(err.stack);
|
|
}
|
|
return false;
|
|
} else {
|
|
var expected = void 0,
|
|
actual = void 0;
|
|
var codeIterations = [];
|
|
var markersToFind = [];
|
|
var _arr = [[true, "// does contain:"], [false, "// does not contain:"]];
|
|
for (var _i = 0; _i < _arr.length; _i++) {
|
|
var _ref = _arr[_i];
|
|
|
|
var _ref2 = _slicedToArray(_ref, 2);
|
|
|
|
var positive = _ref2[0];
|
|
var marker = _ref2[1];
|
|
|
|
if (code.includes(marker)) {
|
|
var _i4 = code.indexOf(marker);
|
|
var _value2 = code.substring(_i4 + marker.length, code.indexOf("\n", _i4));
|
|
markersToFind.push({ positive: positive, value: _value2, start: _i4 + marker.length });
|
|
}
|
|
}
|
|
var copiesToFind = new Map();
|
|
var copyMarker = "// Copies of ";
|
|
if (!options.simpleClosures) {
|
|
var searchStart = code.indexOf(copyMarker);
|
|
while (searchStart !== -1) {
|
|
var searchEnd = code.indexOf(":", searchStart);
|
|
var value = code.substring(searchStart + copyMarker.length, searchEnd);
|
|
var newline = code.indexOf("\n", searchStart);
|
|
var count = parseInt(code.substring(searchEnd + 1, newline), 10);
|
|
copiesToFind.set(new RegExp(value, "gi"), count);
|
|
searchStart = code.indexOf(copyMarker, newline);
|
|
}
|
|
}
|
|
var addedCode = "";
|
|
var injectAtRuntime = "// add at runtime:";
|
|
if (code.includes(injectAtRuntime)) {
|
|
var i = code.indexOf(injectAtRuntime);
|
|
addedCode = code.substring(i + injectAtRuntime.length, code.indexOf("\n", i));
|
|
}
|
|
if (args.es5) {
|
|
code = transformWithBabel(code, [], [["env", { forceAllTransforms: true, modules: false }]]);
|
|
}
|
|
var unique = 27277;
|
|
var oldUniqueSuffix = "";
|
|
var expectedCode = code;
|
|
var actualStack = void 0;
|
|
if (compileJSXWithBabel) {
|
|
expectedCode = transformWithBabel(expectedCode, ["transform-react-jsx"]);
|
|
}
|
|
try {
|
|
try {
|
|
expected = execInContext(addedCode + "\n(function () {" + expectedCode + " // keep newline here as code may end with comment\n }).call(this);");
|
|
} catch (e) {
|
|
expected = "" + e;
|
|
}
|
|
|
|
var _i2 = 0;
|
|
var singleIterationOnly = addedCode || copiesToFind.size > 0 || args.fast;
|
|
var max = singleIterationOnly ? 1 : 4;
|
|
var oldCode = code;
|
|
var anyDelayedValues = false;
|
|
for (; _i2 < max; _i2++) {
|
|
var newUniqueSuffix = "_unique" + unique++;
|
|
if (!singleIterationOnly) options.uniqueSuffix = newUniqueSuffix;
|
|
var _serialized2 = prepackSources([{ filePath: name, fileContents: code, sourceMapContents: "" }], options);
|
|
if (_serialized2.statistics && _serialized2.statistics.delayedValues > 0) anyDelayedValues = true;
|
|
if (!_serialized2) {
|
|
console.error(chalk.red("Error during serialization!"));
|
|
break;
|
|
}
|
|
var newCode = _serialized2.code;
|
|
if (compileJSXWithBabel) {
|
|
newCode = transformWithBabel(newCode, ["transform-react-jsx"]);
|
|
}
|
|
var markersIssue = false;
|
|
var _iteratorNormalCompletion2 = true;
|
|
var _didIteratorError2 = false;
|
|
var _iteratorError2 = undefined;
|
|
|
|
try {
|
|
for (var _iterator2 = markersToFind[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
var _ref3 = _step2.value;
|
|
var _positive = _ref3.positive,
|
|
_value = _ref3.value,
|
|
start = _ref3.start;
|
|
|
|
var found = newCode.indexOf(_value, start) !== -1;
|
|
if (found !== _positive) {
|
|
console.error(chalk.red("Output " + (_positive ? "does not contain" : "contains") + " forbidden string: " + _value));
|
|
markersIssue = true;
|
|
console.error(newCode);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError2 = true;
|
|
_iteratorError2 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
_iterator2.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError2) {
|
|
throw _iteratorError2;
|
|
}
|
|
}
|
|
}
|
|
|
|
var matchesIssue = false;
|
|
var _iteratorNormalCompletion3 = true;
|
|
var _didIteratorError3 = false;
|
|
var _iteratorError3 = undefined;
|
|
|
|
try {
|
|
for (var _iterator3 = copiesToFind[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
|
var _ref4 = _step3.value;
|
|
|
|
var _ref5 = _slicedToArray(_ref4, 2);
|
|
|
|
var pattern = _ref5[0];
|
|
var _count = _ref5[1];
|
|
|
|
var matches = _serialized2.code.match(pattern);
|
|
if (!matches && _count > 0 || matches && matches.length !== _count) {
|
|
matchesIssue = true;
|
|
console.error(chalk.red("Wrong number of occurrances of " + pattern.toString() + " got " + (matches ? matches.length : 0) + " instead of " + _count));
|
|
console.error(newCode);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError3 = true;
|
|
_iteratorError3 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion3 && _iterator3.return) {
|
|
_iterator3.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError3) {
|
|
throw _iteratorError3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (markersIssue || matchesIssue) break;
|
|
var codeToRun = addedCode + newCode;
|
|
if (!execSpec && options.lazyObjectsRuntime !== undefined) {
|
|
codeToRun = augmentCodeWithLazyObjectSupport(codeToRun, args.lazyObjectsRuntime);
|
|
}
|
|
if (args.verbose) console.log(codeToRun);
|
|
codeIterations.push(unescapleUniqueSuffix(codeToRun, options.uniqueSuffix));
|
|
if (args.es5) {
|
|
codeToRun = transformWithBabel(codeToRun, [], [["env", { forceAllTransforms: true, modules: false }]]);
|
|
}
|
|
try {
|
|
if (execSpec) {
|
|
actual = execExternal(execSpec, codeToRun);
|
|
} else {
|
|
actual = execInContext(codeToRun);
|
|
}
|
|
} catch (e) {
|
|
// always compare strings.
|
|
actual = "" + e;
|
|
actualStack = e.stack;
|
|
}
|
|
if (expected !== actual) {
|
|
console.error(chalk.red("Output mismatch!"));
|
|
break;
|
|
}
|
|
if (!verifyFunctionOrderings(codeToRun)) {
|
|
break;
|
|
}
|
|
// Test the number of clone functions generated with the inital prepack call
|
|
if (_i2 === 0 && functionCloneCountMatch && !options.simpleClosures) {
|
|
var functionCount = parseInt(functionCloneCountMatch[1], 10);
|
|
if (_serialized2.statistics && functionCount !== _serialized2.statistics.functionClones) {
|
|
console.error(chalk.red("Code generation serialized an unexpected number of clone functions. Expected: " + functionCount + ", Got: " + _serialized2.statistics.functionClones));
|
|
break;
|
|
}
|
|
}
|
|
if (singleIterationOnly) return true;
|
|
if (unescapleUniqueSuffix(oldCode, oldUniqueSuffix) === unescapleUniqueSuffix(newCode, newUniqueSuffix) || delayUnsupportedRequires) {
|
|
// The generated code reached a fixed point!
|
|
return true;
|
|
}
|
|
oldCode = newCode;
|
|
oldUniqueSuffix = newUniqueSuffix;
|
|
}
|
|
if (_i2 === max) {
|
|
if (anyDelayedValues) {
|
|
// TODO #835: Make delayed initializations logic more sophisticated in order to still reach a fixed point.
|
|
return true;
|
|
}
|
|
console.error(chalk.red("Code generation did not reach fixed point after " + max + " iterations!"));
|
|
}
|
|
} catch (err) {
|
|
console.error(err);
|
|
console.error(err.stack);
|
|
}
|
|
console.log(chalk.underline("original code"));
|
|
console.log(code);
|
|
console.log(chalk.underline("output of inspect() on original code"));
|
|
console.log(expected);
|
|
for (var _i3 = 0; _i3 < codeIterations.length; _i3++) {
|
|
console.log(chalk.underline("generated code in iteration " + _i3));
|
|
console.log(codeIterations[_i3]);
|
|
}
|
|
console.log(chalk.underline("output of inspect() on last generated code iteration"));
|
|
console.log(actual);
|
|
if (actualStack) console.log(actualStack);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function prepareReplExternalSepc(procPath) {
|
|
if (!fs.existsSync(procPath)) {
|
|
throw new ArgsParseError("runtime " + procPath + " does not exist");
|
|
}
|
|
// find out how to print
|
|
var script = "\n if (typeof (console) !== 'undefined' && console.log !== undefined) {\n console.log('console.log')\n }\n else if (typeof('print') !== 'undefined') {\n print('print')\n }";
|
|
var out = child_process.spawnSync(procPath, { input: script });
|
|
var output = String(out.stdout);
|
|
if (output.trim() === "") {
|
|
throw new ArgsParseError("could not figure out how to print in inferior repl " + procPath);
|
|
}
|
|
return { printName: output.trim(), cmd: procPath.trim() };
|
|
}
|
|
|
|
function run(args) {
|
|
var failed = 0;
|
|
var passed = 0;
|
|
var total = 0;
|
|
if (args.outOfProcessRuntime !== "") {
|
|
execSpec = prepareReplExternalSepc(args.outOfProcessRuntime);
|
|
}
|
|
|
|
var _iteratorNormalCompletion4 = true;
|
|
var _didIteratorError4 = false;
|
|
var _iteratorError4 = undefined;
|
|
|
|
try {
|
|
for (var _iterator4 = tests[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
|
|
var test = _step4.value;
|
|
|
|
// filter hidden files
|
|
if (path.basename(test.name)[0] === ".") continue;
|
|
if (test.name.endsWith("~")) continue;
|
|
if (test.file.includes("// skip")) continue;
|
|
if (args.es5 && test.file.includes("// es6")) continue;
|
|
//only run specific tests if desired
|
|
if (!test.name.includes(args.filter)) continue;
|
|
var isAdditionalFunctionTest = test.name.includes("additional-functions");
|
|
var isCaptureTest = test.name.includes("Closure") || test.name.includes("Capture");
|
|
var isSimpleClosureTest = test.file.includes("// simple closures");
|
|
// Skip lazy objects mode for certain known incompatible tests, react compiler and additional-functions tests.
|
|
var skipLazyObjects = test.file.includes("// skip lazy objects") || isAdditionalFunctionTest || test.name.includes("react");
|
|
|
|
var flagPermutations = [[false, false, undefined, isSimpleClosureTest], [true, true, undefined, isSimpleClosureTest], [false, false, args.lazyObjectsRuntime, isSimpleClosureTest]];
|
|
if (isAdditionalFunctionTest || isCaptureTest) {
|
|
flagPermutations.push([false, false, undefined, true]);
|
|
flagPermutations.push([false, true, undefined, true]);
|
|
}
|
|
if (args.fast) flagPermutations = [[false, false, undefined, isSimpleClosureTest]];
|
|
var _iteratorNormalCompletion5 = true;
|
|
var _didIteratorError5 = false;
|
|
var _iteratorError5 = undefined;
|
|
|
|
try {
|
|
for (var _iterator5 = flagPermutations[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
|
|
var _ref6 = _step5.value;
|
|
|
|
var _ref7 = _slicedToArray(_ref6, 4);
|
|
|
|
var delayInitializations = _ref7[0];
|
|
var inlineExpressions = _ref7[1];
|
|
var lazyObjectsRuntime = _ref7[2];
|
|
var simpleClosures = _ref7[3];
|
|
|
|
if ((skipLazyObjects || args.noLazySupport) && lazyObjectsRuntime) {
|
|
continue;
|
|
}
|
|
total++;
|
|
var options = { delayInitializations: delayInitializations, inlineExpressions: inlineExpressions, lazyObjectsRuntime: lazyObjectsRuntime, simpleClosures: simpleClosures };
|
|
if (runTest(test.name, test.file, options, args)) passed++;else failed++;
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError5 = true;
|
|
_iteratorError5 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion5 && _iterator5.return) {
|
|
_iterator5.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError5) {
|
|
throw _iteratorError5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError4 = true;
|
|
_iteratorError4 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion4 && _iterator4.return) {
|
|
_iterator4.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError4) {
|
|
throw _iteratorError4;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log("Passed:", passed + "/" + total, (Math.floor(passed / total * 100) || 0) + "%");
|
|
return failed === 0;
|
|
}
|
|
|
|
// Object to store all command line arguments
|
|
|
|
var ProgramArgs = function ProgramArgs(debugNames, verbose, filter, outOfProcessRuntime, es5, lazyObjectsRuntime, noLazySupport, fast) {
|
|
_classCallCheck(this, ProgramArgs);
|
|
|
|
this.debugNames = debugNames;
|
|
this.verbose = verbose;
|
|
this.filter = filter; //lets user choose specific test files, runs all tests if omitted
|
|
this.outOfProcessRuntime = outOfProcessRuntime;
|
|
this.es5 = es5;
|
|
this.lazyObjectsRuntime = lazyObjectsRuntime;
|
|
this.noLazySupport = noLazySupport;
|
|
this.fast = fast;
|
|
};
|
|
|
|
// Execution of tests begins here
|
|
|
|
|
|
function main() {
|
|
try {
|
|
var args = argsParse();
|
|
if (!run(args)) {
|
|
process.exit(1);
|
|
} else {
|
|
return 0;
|
|
}
|
|
} catch (e) {
|
|
if (e instanceof ArgsParseError) {
|
|
console.error("Illegal argument: %s.\n%s", e.message, usage());
|
|
} else {
|
|
console.error(e);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Helper function to provide correct usage information to the user
|
|
function usage() {
|
|
return "Usage: " + process.argv[0] + " " + process.argv[1] + " " + EOL + "[--verbose] [--filter <string>] [--outOfProcessRuntime <path>] [--es5] [--noLazySupport]";
|
|
}
|
|
|
|
// NOTE: inheriting from Error does not seem to pass through an instanceof
|
|
// check
|
|
|
|
var ArgsParseError = function ArgsParseError(message) {
|
|
_classCallCheck(this, ArgsParseError);
|
|
|
|
this.message = message;
|
|
};
|
|
|
|
// Parses through the command line arguments and throws errors if usage is incorrect
|
|
|
|
|
|
function argsParse() {
|
|
var parsedArgs = minimist(process.argv.slice(2), {
|
|
string: ["filter", "outOfProcessRuntime"],
|
|
boolean: ["debugNames", "verbose", "es5", "fast"],
|
|
default: {
|
|
debugNames: false,
|
|
verbose: false,
|
|
es5: false, // if true test marked as es6 only are not run
|
|
filter: "",
|
|
outOfProcessRuntime: "", // if set, assumed to be a JS runtime and is used
|
|
// to run tests. If not a seperate node context used.
|
|
lazyObjectsRuntime: LAZY_OBJECTS_RUNTIME_NAME,
|
|
noLazySupport: false,
|
|
fast: false
|
|
}
|
|
});
|
|
if (typeof parsedArgs.debugNames !== "boolean") {
|
|
throw new ArgsParseError("debugNames must be a boolean (either --debugNames or not)");
|
|
}
|
|
if (typeof parsedArgs.verbose !== "boolean") {
|
|
throw new ArgsParseError("verbose must be a boolean (either --verbose or not)");
|
|
}
|
|
if (typeof parsedArgs.es5 !== "boolean") {
|
|
throw new ArgsParseError("es5 must be a boolean (either --es5 or not)");
|
|
}
|
|
if (typeof parsedArgs.fast !== "boolean") {
|
|
throw new ArgsParseError("fast must be a boolean (either --fast or not)");
|
|
}
|
|
if (typeof parsedArgs.filter !== "string") {
|
|
throw new ArgsParseError("filter must be a string (relative path from serialize directory) (--filter abstract/Residual.js)");
|
|
}
|
|
if (typeof parsedArgs.outOfProcessRuntime !== "string") {
|
|
throw new ArgsParseError("outOfProcessRuntime must be path pointing to an javascript runtime");
|
|
}
|
|
if (typeof parsedArgs.lazyObjectsRuntime !== "string") {
|
|
throw new ArgsParseError("lazyObjectsRuntime must be a string");
|
|
}
|
|
if (typeof parsedArgs.noLazySupport !== "boolean") {
|
|
throw new ArgsParseError("noLazySupport must be a boolean (either --noLazySupport or not)");
|
|
}
|
|
var programArgs = new ProgramArgs(parsedArgs.debugNames, parsedArgs.verbose, parsedArgs.filter, parsedArgs.outOfProcessRuntime, parsedArgs.es5, parsedArgs.lazyObjectsRuntime, parsedArgs.noLazySupport, parsedArgs.fast);
|
|
return programArgs;
|
|
}
|
|
|
|
main();
|
|
//# sourceMappingURL=test-runner.js.map
|