Skip to content

Commit

Permalink
support async test cases properly
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed Jan 10, 2021
1 parent dbfa5d4 commit 1d3b32c
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 79 deletions.
30 changes: 19 additions & 11 deletions test/compress/awaits.js
Original file line number Diff line number Diff line change
Expand Up @@ -612,22 +612,32 @@ issue_4340: {
call_expression: {
input: {
console.log(typeof async function(log) {
(await log)("FAIL");
(await log)("foo");
}(console.log).then);
console.log("bar");
}
expect_exact: 'console.log(typeof async function(log){(await log)("FAIL")}(console.log).then);'
expect_stdout: "function"
expect_exact: 'console.log(typeof async function(log){(await log)("foo")}(console.log).then);console.log("bar");'
expect_stdout: [
"function",
"bar",
"foo",
]
node_version: ">=8"
}

property_access_expression: {
input: {
console.log(typeof async function(con) {
(await con).log("FAIL");
(await con).log("foo");
}(console).then);
console.log("bar");
}
expect_exact: 'console.log(typeof async function(con){(await con).log("FAIL")}(console).then);'
expect_stdout: "function"
expect_exact: 'console.log(typeof async function(con){(await con).log("foo")}(console).then);console.log("bar");'
expect_stdout: [
"function",
"bar",
"foo",
]
node_version: ">=8"
}

Expand Down Expand Up @@ -685,20 +695,18 @@ reduce_iife_3: {
input: {
var a = "foo";
(async function() {
console.log(a);
console.log(await a);
console.log(a, await a, a, await a);
})();
a = "bar";
}
expect: {
var a = "foo";
(async function() {
console.log(a);
console.log(await a);
console.log(a, await a, a, await a);
})();
a = "bar";
}
expect_stdout: "foo"
expect_stdout: "foo foo bar bar"
node_version: ">=8"
}

Expand Down
173 changes: 105 additions & 68 deletions test/sandbox.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,80 @@
var execSync = require("child_process").execSync;
var semver = require("semver");
var vm = require("vm");

var setupContext = new vm.Script([
"[ Array, Boolean, Error, Function, Number, Object, RegExp, String ].forEach(function(f) {",
" f.toString = Function.prototype.toString;",
"});",
"Function.prototype.toString = function() {",
" var id = 100000;",
" return function() {",
" var n = this.name;",
" if (!/^F[0-9]{6}N$/.test(n)) {",
' n = "F" + ++id + "N";',
].concat(Object.getOwnPropertyDescriptor(Function.prototype, "name").configurable ? [
' Object.defineProperty(this, "name", {',
" get: function() {",
" return n;",
" }",
" });",
] : [], [
" }",
' return "function(){}";',
" };",
"}();",
"this;",
]).join("\n"));
var setup_code = "(" + setup + ")(this);";
exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, toplevel, timeout) {
var stdout = run_code_vm(code, toplevel, timeout);
if (typeof stdout != "string" || !/arguments/.test(code)) return stdout;
do {
var prev = stdout;
stdout = run_code_vm(code, toplevel, timeout);
} while (prev !== stdout);
return stdout;
} : semver.satisfies(process.version, "<8") ? run_code_vm : function(code, toplevel, timeout) {
return (/\b(async|setInterval|setTimeout)\b/.test(code) ? run_code_exec : run_code_vm)(code, toplevel, timeout);
};
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
if (typeof expected != typeof actual) return false;
if (typeof expected == "object" && typeof expected.name == "string" && typeof expected.message == "string") {
if (expected.name !== actual.name) return false;
if (typeof actual.message != "string") return false;
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
}
return strip_func_ids(expected) == strip_func_ids(actual);
} : function(expected, actual) {
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
};
exports.has_toplevel = function(options) {
return options.toplevel
|| options.mangle && options.mangle.toplevel
|| options.compress && options.compress.toplevel;
};

function strip_func_ids(text) {
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
}

function createContext() {
var ctx = vm.createContext(Object.defineProperties({}, {
console: { value: { log: log } },
function setup(global) {
[ Array, Boolean, Error, Function, Number, Object, RegExp, String ].forEach(function(f) {
f.toString = Function.prototype.toString;
});
Function.prototype.toString = function() {
var configurable = Object.getOwnPropertyDescriptor(Function.prototype, "name").configurable;
var id = 100000;
return function() {
var n = this.name;
if (!/^F[0-9]{6}N$/.test(n)) {
n = "F" + ++id + "N";
if (configurable) Object.defineProperty(this, "name", {
get: function() {
return n;
}
});
}
return "function(){}";
};
}();
if (typeof process != "undefined") process.on("unhandledRejection", function() {});
var log = console.log;
var safe_console = {
log: function(msg) {
if (arguments.length == 1 && typeof msg == "string") return log("%s", msg);
return log.apply(null, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
},
};
// for Node.js v0.12
global.console = safe_console;
Object.defineProperties(global, {
// for Node.js v8
console: { value: safe_console },
global: { get: self },
self: { get: self },
window: { get: self },
}));
var global = setupContext.runInContext(ctx);
return ctx;
});

function self() {
return this;
Expand All @@ -55,24 +96,20 @@ function createContext() {
}
return arg;
}

function log(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);
}));
}
}

function run_code(code, toplevel, timeout) {
function run_code_vm(code, toplevel, timeout) {
timeout = timeout || 5000;
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
vm.runInContext(toplevel ? "(function(){" + code + "})()" : code, createContext(), { timeout: timeout });
var ctx = vm.createContext({ console: console });
// for Node.js v6
vm.runInContext(setup_code, ctx);
vm.runInContext(toplevel ? "(function(){" + code + "})();" : code, ctx, { timeout: timeout });
return stdout;
} catch (ex) {
return ex;
Expand All @@ -81,34 +118,34 @@ function run_code(code, toplevel, timeout) {
}
}

exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, toplevel, timeout) {
var stdout = run_code(code, toplevel, timeout);
if (typeof stdout != "string" || !/arguments/.test(code)) return stdout;
do {
var prev = stdout;
stdout = run_code(code, toplevel, timeout);
} while (prev !== stdout);
return stdout;
} : run_code;

function strip_func_ids(text) {
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
}

exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
if (typeof expected != typeof actual) return false;
if (typeof expected == "object" && typeof expected.name == "string" && typeof expected.message == "string") {
if (expected.name !== actual.name) return false;
if (typeof actual.message != "string") return false;
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
function run_code_exec(code, toplevel, timeout) {
if (toplevel) {
code = setup_code + "(function(){" + code + "})();";
} else {
code = code.replace(/^((["'])[^"']*\1(;|$))?/, function(directive) {
return directive + setup_code;
});
}
return strip_func_ids(expected) == strip_func_ids(actual);
} : function(expected, actual) {
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
};
exports.has_toplevel = function(options) {
return options.toplevel
|| options.mangle && options.mangle.toplevel
|| options.compress && options.compress.toplevel;
};
try {
return execSync('"' + process.argv[0] + '"', {
encoding: "utf8",
input: code,
stdio: "pipe",
timeout: timeout || 5000,
});
} catch (ex) {
var msg = ex.message.replace(/\r\n/g, "\n");
var match = /\n([^:\s]*Error)(?:: ([\s\S]+?))?\n( at [\s\S]+)\n$/.exec(msg);
if (match) {
ex = new global[match[1]](match[2]);
ex.stack = ex.stack.slice(0, ex.stack.indexOf(" at ")) + match[3];
} else if (/ETIMEDOUT/.test(msg)) {
ex = new Error("Script execution timed out.");
} else if (match = /\n *\^\n(\n.+|[^{[].*)\n/.exec(msg)) try {
ex = vm.runInNewContext("(" + match[1].trim() + ")");
} catch (e) {
ex = match[1];
}
return ex;
}
}

0 comments on commit 1d3b32c

Please sign in to comment.