improve test/run-test.js performance (#2971)

- allow reuse of contextified sandbox
- minimise bottleneck from `vm.createContext()`
This commit is contained in:
Alex Lam S.L
2018-03-04 04:50:00 +08:00
committed by GitHub
parent a75a046abb
commit 798fc21530
2 changed files with 36 additions and 18 deletions

View File

@@ -182,7 +182,7 @@ function run_compress_tests() {
} }
if (test.expect_stdout if (test.expect_stdout
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) { && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
var stdout = sandbox.run_code(input_code); var stdout = sandbox.run_code(input_code, true);
if (test.expect_stdout === true) { if (test.expect_stdout === true) {
test.expect_stdout = stdout; test.expect_stdout = stdout;
} }
@@ -196,7 +196,7 @@ function run_compress_tests() {
}); });
return false; return false;
} }
stdout = sandbox.run_code(output); stdout = sandbox.run_code(output, true);
if (!sandbox.same_stdout(test.expect_stdout, stdout)) { if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", { log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted, input: input_formatted,
@@ -378,7 +378,7 @@ function reminify(orig_options, input_code, input_formatted, expect_stdout) {
}); });
return false; return false;
} else { } else {
var stdout = sandbox.run_code(result.code); var stdout = sandbox.run_code(result.code, true);
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) { if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
stdout = expect_stdout; stdout = expect_stdout;
} }

View File

@@ -1,6 +1,27 @@
var semver = require("semver"); var semver = require("semver");
var vm = require("vm"); var vm = require("vm");
function createContext() {
var context = Object.create(null);
Object.defineProperty(context, "console", {
value: function() {
var con = Object.create(null);
Object.defineProperty(con, "log", {
value: function(msg) {
if (arguments.length == 1 && typeof msg == "string") {
return console.log("%s", msg);
}
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
}
});
return con;
}()
});
return vm.createContext(context);
}
function safe_log(arg, level) { function safe_log(arg, level) {
if (arg) switch (typeof arg) { if (arg) switch (typeof arg) {
case "function": case "function":
@@ -9,7 +30,8 @@ function safe_log(arg, level) {
if (/Error$/.test(arg.name)) return arg.toString(); if (/Error$/.test(arg.name)) return arg.toString();
arg.constructor.toString(); arg.constructor.toString();
if (level--) for (var key in arg) { if (level--) for (var key in arg) {
if (!Object.getOwnPropertyDescriptor(arg, key).get) { var desc = Object.getOwnPropertyDescriptor(arg, key);
if (!desc || !desc.get) {
arg[key] = safe_log(arg[key], level); arg[key] = safe_log(arg[key], level);
} }
} }
@@ -21,6 +43,7 @@ function strip_func_ids(text) {
return text.toString().replace(/F[0-9]{6}N/g, "<F<>N>"); return text.toString().replace(/F[0-9]{6}N/g, "<F<>N>");
} }
var context;
var FUNC_TOSTRING = [ var FUNC_TOSTRING = [
"[ Array, Boolean, Error, Function, Number, Object, RegExp, String].forEach(function(f) {", "[ Array, Boolean, Error, Function, Number, Object, RegExp, String].forEach(function(f) {",
" f.toString = Function.prototype.toString;", " f.toString = Function.prototype.toString;",
@@ -43,35 +66,30 @@ var FUNC_TOSTRING = [
" };", " };",
"}();", "}();",
]).join("\n"); ]).join("\n");
exports.run_code = function(code) { exports.run_code = function(code, reuse) {
var stdout = ""; var stdout = "";
var original_write = process.stdout.write; var original_write = process.stdout.write;
process.stdout.write = function(chunk) { process.stdout.write = function(chunk) {
stdout += chunk; stdout += chunk;
}; };
try { try {
vm.runInNewContext([ if (!reuse || !context) context = createContext();
vm.runInContext([
FUNC_TOSTRING, FUNC_TOSTRING,
"!function() {", "!function() {",
code, code,
"}();", "}();",
].join("\n"), { ].join("\n"), context, { timeout: 5000 });
console: {
log: function(msg) {
if (arguments.length == 1 && typeof msg == "string") {
return console.log("%s", msg);
}
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
}
}
}, { timeout: 5000 });
return stdout; return stdout;
} catch (ex) { } catch (ex) {
return ex; return ex;
} finally { } finally {
process.stdout.write = original_write; process.stdout.write = original_write;
if (!reuse || /prototype/.test(code)) {
context = null;
} else for (var key in context) {
delete context[key];
}
} }
}; };
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) { exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {