diff --git a/test/compress/awaits.js b/test/compress/awaits.js index 8caa60c066e..c6e5313ec0e 100644 --- a/test/compress/awaits.js +++ b/test/compress/awaits.js @@ -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" } @@ -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" } diff --git a/test/sandbox.js b/test/sandbox.js index 78a3435e78b..933f882d4f5 100644 --- a/test/sandbox.js +++ b/test/sandbox.js @@ -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, "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; @@ -55,16 +96,9 @@ 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; @@ -72,7 +106,10 @@ function run_code(code, toplevel, timeout) { 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; @@ -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, "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; + } +}