support limited ufuzz testing for export (#4693)

fixes #4692
This commit is contained in:
Alex Lam S.L
2021-02-26 20:56:34 +00:00
committed by GitHub
parent ac26993b5a
commit ba4a771bbc
7 changed files with 166 additions and 47 deletions

View File

@@ -1176,15 +1176,7 @@ var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
}); });
}, },
_validate: function() { _validate: function() {
if (this.body instanceof AST_Class && this.body.name) { if (!(this.body instanceof AST_DefClass || this.body instanceof AST_LambdaDefinition)) {
if (!(this.body instanceof AST_DefClass)) {
throw new Error("body must be AST_DefClass when named");
}
} else if (this.body instanceof AST_Lambda && this.body.name) {
if (!(this.body instanceof AST_LambdaDefinition)) {
throw new Error("body must be AST_LambdaDefinition when named");
}
} else {
must_be_expression(this, "body"); must_be_expression(this, "body");
} }
}, },

View File

@@ -940,6 +940,8 @@ merge(Compressor.prototype, {
}); });
if (!node.name) return; if (!node.name) return;
var d = node.name.definition(); var d = node.name.definition();
var parent = tw.parent();
if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) d.single_use = false;
if (safe_to_assign(tw, d, true)) { if (safe_to_assign(tw, d, true)) {
mark(tw, d); mark(tw, d);
tw.loop_ids[d.id] = tw.in_loop; tw.loop_ids[d.id] = tw.in_loop;
@@ -6709,6 +6711,7 @@ merge(Compressor.prototype, {
var var_decl = 0; var var_decl = 0;
self.walk(new TreeWalker(function(node) { self.walk(new TreeWalker(function(node) {
if (var_decl > 1) return true; if (var_decl > 1) return true;
if (node instanceof AST_ExportDeclaration) return true;
if (node instanceof AST_Scope && node !== self) return true; if (node instanceof AST_Scope && node !== self) return true;
if (node instanceof AST_Var) { if (node instanceof AST_Var) {
var_decl++; var_decl++;
@@ -6728,12 +6731,15 @@ merge(Compressor.prototype, {
dirs.push(node); dirs.push(node);
return make_node(AST_EmptyStatement, node); return make_node(AST_EmptyStatement, node);
} }
if (hoist_funs && node instanceof AST_Defun if (node instanceof AST_Defun) {
&& (tt.parent() === self || !compressor.has_directive("use strict"))) { if (!hoist_funs) return node;
if (tt.parent() !== self && compressor.has_directive("use strict")) return node;
hoisted.push(node); hoisted.push(node);
return make_node(AST_EmptyStatement, node); return make_node(AST_EmptyStatement, node);
} }
if (hoist_vars && node instanceof AST_Var) { if (node instanceof AST_Var) {
if (!hoist_vars) return node;
if (tt.parent() instanceof AST_ExportDeclaration) return node;
if (!all(node.definitions, function(defn) { if (!all(node.definitions, function(defn) {
var sym = defn.name; var sym = defn.name;
return sym instanceof AST_SymbolVar return sym instanceof AST_SymbolVar

View File

@@ -664,7 +664,9 @@ function OutputStream(options) {
function needs_parens_function(output) { function needs_parens_function(output) {
if (!output.has_parens() && first_in_statement(output)) return true; if (!output.has_parens() && first_in_statement(output)) return true;
var p = output.parent(); var p = output.parent();
// export default (function() {})() // export default (function foo() {});
if (this.name && p instanceof AST_ExportDefault) return true;
// export default (function() {})(foo);
if (p && p.TYPE == "Call" && output.parent(1) instanceof AST_ExportDefault) return true; if (p && p.TYPE == "Call" && output.parent(1) instanceof AST_ExportDefault) return true;
if (output.option("webkit") && p instanceof AST_PropAccess && p.expression === this) return true; if (output.option("webkit") && p instanceof AST_PropAccess && p.expression === this) return true;
if (output.option("wrap_iife") && p instanceof AST_Call && p.expression === this) return true; if (output.option("wrap_iife") && p instanceof AST_Call && p.expression === this) return true;
@@ -725,6 +727,8 @@ function OutputStream(options) {
// { [(1, 2)]: foo } = bar // { [(1, 2)]: foo } = bar
// { 1: (2, foo) } = bar // { 1: (2, foo) } = bar
|| p instanceof AST_DestructuredKeyVal || p instanceof AST_DestructuredKeyVal
// export default (foo, bar)
|| p instanceof AST_ExportDefault
// for (foo of (bar, baz)); // for (foo of (bar, baz));
|| p instanceof AST_ForOf || p instanceof AST_ForOf
// { [(1, 2)]: 3 }[2] ---> 3 // { [(1, 2)]: 3 }[2] ---> 3
@@ -1032,9 +1036,16 @@ function OutputStream(options) {
output.space(); output.space();
output.print("default"); output.print("default");
output.space(); output.space();
this.body.print(output); var body = this.body;
if (this.body instanceof AST_Class) return; body.print(output);
if (this.body instanceof AST_Lambda && !is_arrow(this.body)) return; if (body instanceof AST_ClassExpression) {
if (!body.name) return;
}
if (body instanceof AST_DefClass) return;
if (body instanceof AST_LambdaDefinition) return;
if (body instanceof AST_LambdaExpression) {
if (!body.name && !is_arrow(body)) return;
}
output.semicolon(); output.semicolon();
}); });
DEFPRINT(AST_ExportForeign, function(output) { DEFPRINT(AST_ExportForeign, function(output) {

View File

@@ -56,6 +56,20 @@ defaults_parentheses_2: {
expect_exact: 'export default(async function(){console.log("PASS")})();' expect_exact: 'export default(async function(){console.log("PASS")})();'
} }
defaults_parentheses_3: {
input: {
export default (42, "PASS");
}
expect_exact: 'export default(42,"PASS");'
}
defaults_parentheses_4: {
input: {
export default (function f() {});
}
expect_exact: "export default(function f(){});"
}
foreign: { foreign: {
input: { input: {
export * from "foo"; export * from "foo";
@@ -203,6 +217,20 @@ hoist_exports: {
} }
} }
hoist_vars: {
options = {
hoist_vars: true,
}
input: {
var a;
export var b = 42;
}
expect: {
var a;
export var b = 42;
}
}
keep_return_values: { keep_return_values: {
options = { options = {
booleans: true, booleans: true,
@@ -301,3 +329,35 @@ single_use_default: {
f(); f();
} }
} }
single_use_class: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
export class A {}
A.prototype.p = "PASS";
}
expect: {
export class A {}
A.prototype.p = "PASS";
}
}
single_use_class_default: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
export default class A {}
A.prototype.p = "PASS";
}
expect: {
export default class A {}
A.prototype.p = "PASS";
}
}

View File

@@ -132,6 +132,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return; return;
} }
if (parent instanceof U.AST_VarDef && parent.name === node) return; if (parent instanceof U.AST_VarDef && parent.name === node) return;
// preserve exports
if (parent instanceof U.AST_ExportDeclaration) return;
if (parent instanceof U.AST_ExportDefault) return;
if (parent instanceof U.AST_ExportForeign) return;
if (parent instanceof U.AST_ExportReferences) return;
// preserve for (var xxx; ...) // preserve for (var xxx; ...)
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node; if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
// preserve for (xxx in/of ...) // preserve for (xxx in/of ...)
@@ -455,6 +460,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return List.skip; return List.skip;
} }
// preserve sole definition of an export statement
if (node instanceof U.AST_VarDef
&& parent.definitions.length == 1
&& tt.parent(1) instanceof U.AST_ExportDeclaration) {
return node;
}
// remove this node unless its the sole element of a (transient) sequence // remove this node unless its the sole element of a (transient) sequence
if (!(parent instanceof U.AST_Sequence) || parent.expressions.length > 1) { if (!(parent instanceof U.AST_Sequence) || parent.expressions.length > 1) {
node.start._permute++; node.start._permute++;
@@ -720,7 +732,7 @@ function run_code(code, toplevel, result_cache, timeout) {
if (!value) { if (!value) {
var start = Date.now(); var start = Date.now();
result_cache[key] = value = { result_cache[key] = value = {
result: sandbox.run_code(code, toplevel, timeout), result: sandbox.run_code(sandbox.strip_exports(code), toplevel, timeout),
elapsed: Date.now() - start, elapsed: Date.now() - start,
}; };
} }

View File

@@ -49,6 +49,14 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
} : function(expected, actual) { } : function(expected, actual) {
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual); return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
}; };
exports.strip_exports = function(code) {
var count = 0;
return code.replace(/\bexport(?:\s*\{[^}]*};|\s+default\b(?:\s*(\(|\{|class\s*\{|class\s+(?=extends\b)|(?:async\s+)?function\s*(?:\*\s*)?\())?|\b)/g, function(match, header) {
if (!header) return "";
if (header.length == 1) return "~" + header;
return header.slice(0, -1) + " _" + ++count + header.slice(-1);
});
};
function is_error(result) { function is_error(result) {
return result && typeof result.name == "string" && typeof result.message == "string"; return result && typeof result.name == "string" && typeof result.message == "string";

View File

@@ -363,6 +363,7 @@ var lambda_vars = [];
var unique_vars = []; var unique_vars = [];
var classes = []; var classes = [];
var async = false; var async = false;
var export_default = false;
var generator = false; var generator = false;
var loops = 0; var loops = 0;
var funcs = 0; var funcs = 0;
@@ -380,6 +381,17 @@ function strictMode() {
return use_strict && rng(4) == 0 ? '"use strict";' : ""; return use_strict && rng(4) == 0 ? '"use strict";' : "";
} }
function appendExport(stmtDepth, allowDefault) {
if (stmtDepth == 1 && rng(20) == 0) {
if (allowDefault && !export_default && rng(5) == 0) {
export_default = true;
return "export default ";
}
return "export ";
}
return "";
}
function createTopLevelCode() { function createTopLevelCode() {
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
block_vars.length = 0; block_vars.length = 0;
@@ -387,21 +399,28 @@ function createTopLevelCode() {
unique_vars.length = 0; unique_vars.length = 0;
classes.length = 0; classes.length = 0;
async = false; async = false;
export_default = false;
generator = false; generator = false;
loops = 0; loops = 0;
funcs = 0; funcs = 0;
clazz = 0; clazz = 0;
in_class = 0; in_class = 0;
called = Object.create(null); called = Object.create(null);
return [ var s = [
strictMode(), strictMode(),
"var _calls_ = 10, a = 100, b = 10, c = 0;", appendExport(1) + "var _calls_ = 10, a = 100, b = 10, c = 0;",
rng(2) ];
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0) createBlockVariables(MAX_GENERATION_RECURSION_DEPTH, 0, CANNOT_THROW, function(defns) {
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0), s.push(defns());
// preceding `null` makes for a cleaner output (empty string still shows up etc) if (rng(2)) {
"console.log(null, a, b, c, Infinity, NaN, undefined);" s.push(createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0));
].join("\n"); } else {
s.push(createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0));
}
});
// preceding `null` makes for a cleaner output (empty string still shows up etc)
s.push("console.log(null, a, b, c, Infinity, NaN, undefined);");
return s.join("\n");
} }
function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) { function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) {
@@ -668,6 +687,7 @@ function filterDirective(s) {
} }
function createBlockVariables(recurmax, stmtDepth, canThrow, fn) { function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
++stmtDepth;
var block_len = block_vars.length; var block_len = block_vars.length;
var class_len = classes.length; var class_len = classes.length;
var nameLenBefore = VAR_NAMES.length; var nameLenBefore = VAR_NAMES.length;
@@ -691,7 +711,7 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
if (SUPPORT.class) while (rng(100) == 0) { if (SUPPORT.class) while (rng(100) == 0) {
var name = "C" + clazz++; var name = "C" + clazz++;
classes.push(name); classes.push(name);
s.push(createClassLiteral(recurmax,stmtDepth, canThrow, name)); s.push(appendExport(stmtDepth, true) + createClassLiteral(recurmax, stmtDepth, canThrow, name));
} }
if (rng(2)) { if (rng(2)) {
s.push(createDefinitions("const", consts), createDefinitions("let", lets)); s.push(createDefinitions("const", consts), createDefinitions("let", lets));
@@ -707,7 +727,7 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
function createDefinitions(type, names) { function createDefinitions(type, names) {
if (!names.length) return ""; if (!names.length) return "";
var s = type + " "; var s = appendExport(stmtDepth) + type + " ";
switch (SUPPORT.destructuring ? rng(10) : 2) { switch (SUPPORT.destructuring ? rng(10) : 2) {
case 0: case 0:
while (!rng(10)) names.splice(rng(names.length + 1), 0, ""); while (!rng(10)) names.splice(rng(names.length + 1), 0, "");
@@ -780,6 +800,7 @@ function invokeGenerator(was_generator) {
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) { function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
if (--recurmax < 0) { return ";"; } if (--recurmax < 0) { return ";"; }
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0; if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
++stmtDepth;
var s = []; var s = [];
var name, args; var name, args;
var nameLenBefore = VAR_NAMES.length; var nameLenBefore = VAR_NAMES.length;
@@ -831,13 +852,14 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
lambda_vars.length = lambda_len; lambda_vars.length = lambda_len;
VAR_NAMES.length = nameLenBefore; VAR_NAMES.length = nameLenBefore;
if (allowDefun) s = appendExport(stmtDepth, true) + s;
if (!allowDefun) { if (!allowDefun) {
// avoid "function statements" (decl inside statements) // avoid "function statements" (decl inside statements)
s = "var " + createVarName(MANDATORY) + " = " + s; s = appendExport(stmtDepth) + "var " + createVarName(MANDATORY) + " = " + s;
s += args || createArgs(recurmax, stmtDepth, canThrow); s += args || createArgs(recurmax, stmtDepth, canThrow);
s += call_next; s += call_next;
} else if (!(name in called) || args || rng(3)) { } else if (!(name in called) || args || rng(3)) {
s += "var " + createVarName(MANDATORY) + " = " + name; s += appendExport(stmtDepth) + "var " + createVarName(MANDATORY) + " = " + name;
s += args || createArgs(recurmax, stmtDepth, canThrow); s += args || createArgs(recurmax, stmtDepth, canThrow);
s += call_next; s += call_next;
} }
@@ -987,6 +1009,10 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
case STMT_SEMI: case STMT_SEMI:
return use_strict && rng(20) === 0 ? '"use strict";' : ";"; return use_strict && rng(20) === 0 ? '"use strict";' : ";";
case STMT_EXPR: case STMT_EXPR:
if (stmtDepth == 1 && !export_default && rng(20) == 0) {
export_default = true;
return "export default " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ";";
}
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ";"; return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ";";
case STMT_SWITCH: case STMT_SWITCH:
// note: case args are actual expressions // note: case args are actual expressions
@@ -995,7 +1021,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
case STMT_VAR: case STMT_VAR:
if (SUPPORT.destructuring && rng(20) == 0) { if (SUPPORT.destructuring && rng(20) == 0) {
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow); var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow);
return "var " + pairs.names.map(function(name, index) { return appendExport(stmtDepth) + "var " + pairs.names.map(function(name, index) {
return index in pairs.values ? name + " = " + pairs.values[index] : name; return index in pairs.values ? name + " = " + pairs.values[index] : name;
}).join(", ") + ";"; }).join(", ") + ";";
} else switch (rng(3)) { } else switch (rng(3)) {
@@ -1003,20 +1029,20 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
unique_vars.push("c"); unique_vars.push("c");
var name = createVarName(MANDATORY); var name = createVarName(MANDATORY);
unique_vars.pop(); unique_vars.pop();
return "var " + name + ";"; return appendExport(stmtDepth) + "var " + name + ";";
case 1: case 1:
// initializer can only have one expression // initializer can only have one expression
unique_vars.push("c"); unique_vars.push("c");
var name = createVarName(MANDATORY); var name = createVarName(MANDATORY);
unique_vars.pop(); unique_vars.pop();
return "var " + name + " = " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ";"; return appendExport(stmtDepth) + "var " + name + " = " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ";";
default: default:
// initializer can only have one expression // initializer can only have one expression
unique_vars.push("c"); unique_vars.push("c");
var n1 = createVarName(MANDATORY); var n1 = createVarName(MANDATORY);
var n2 = createVarName(MANDATORY); var n2 = createVarName(MANDATORY);
unique_vars.pop(); unique_vars.pop();
return "var " + n1 + " = " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ", " + n2 + " = " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ";"; return appendExport(stmtDepth) + "var " + n1 + " = " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ", " + n2 + " = " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ";";
} }
case STMT_RETURN_ETC: case STMT_RETURN_ETC:
switch (rng(8)) { switch (rng(8)) {
@@ -1939,6 +1965,10 @@ if (require.main !== module) {
return; return;
} }
function run_code(code, toplevel) {
return sandbox.run_code(sandbox.strip_exports(code), toplevel);
}
function writeln(stream, msg) { function writeln(stream, msg) {
if (typeof msg != "undefined") { if (typeof msg != "undefined") {
stream.write(typeof msg == "string" ? msg : msg.stack || "" + msg); stream.write(typeof msg == "string" ? msg : msg.stack || "" + msg);
@@ -1960,7 +1990,7 @@ function try_beautify(code, toplevel, result, printfn, options) {
printfn("// !!! beautify failed !!!"); printfn("// !!! beautify failed !!!");
printfn(beautified.error); printfn(beautified.error);
beautified = null; beautified = null;
} else if (!sandbox.same_stdout(sandbox.run_code(beautified.code, toplevel), result)) { } else if (!sandbox.same_stdout(run_code(beautified.code, toplevel), result)) {
beautified = null; beautified = null;
} else if (options) { } else if (options) {
var uglified = UglifyJS.minify(beautified.code, JSON.parse(options)); var uglified = UglifyJS.minify(beautified.code, JSON.parse(options));
@@ -1970,7 +2000,7 @@ function try_beautify(code, toplevel, result, printfn, options) {
actual = uglified.error; actual = uglified.error;
} else { } else {
expected = uglify_result; expected = uglify_result;
actual = sandbox.run_code(uglified.code, toplevel); actual = run_code(uglified.code, toplevel);
} }
if (!sandbox.same_stdout(expected, actual)) { if (!sandbox.same_stdout(expected, actual)) {
beautified = null; beautified = null;
@@ -2008,7 +2038,7 @@ function log_suspects(minify_options, component) {
errorln("Error testing options." + component + "." + name); errorln("Error testing options." + component + "." + name);
errorln(result.error); errorln(result.error);
} else { } else {
var r = sandbox.run_code(result.code, toplevel); var r = run_code(result.code, toplevel);
return !sandbox.same_stdout(uglify_result, r); return !sandbox.same_stdout(uglify_result, r);
} }
} }
@@ -2036,7 +2066,7 @@ function log_suspects_global(options, toplevel) {
errorln("Error testing options." + component); errorln("Error testing options." + component);
errorln(result.error); errorln(result.error);
} else { } else {
var r = sandbox.run_code(result.code, toplevel); var r = run_code(result.code, toplevel);
return !sandbox.same_stdout(uglify_result, r); return !sandbox.same_stdout(uglify_result, r);
} }
}); });
@@ -2108,7 +2138,7 @@ function log(options) {
} }
function sort_globals(code) { function sort_globals(code) {
var globals = sandbox.run_code("throw Object.keys(this).sort(" + function(global) { var globals = run_code("throw Object.keys(this).sort(" + function(global) {
return function(m, n) { return function(m, n) {
return (n == "toString") - (m == "toString") return (n == "toString") - (m == "toString")
|| (typeof global[n] == "function") - (typeof global[m] == "function") || (typeof global[n] == "function") - (typeof global[m] == "function")
@@ -2221,7 +2251,7 @@ function patch_try_catch(orig, toplevel) {
].join("\n"); ].join("\n");
} }
var new_code = code.slice(0, index) + insert + code.slice(index) + tail_throw; var new_code = code.slice(0, index) + insert + code.slice(index) + tail_throw;
var result = sandbox.run_code(new_code, toplevel); var result = run_code(new_code, toplevel);
if (!sandbox.is_error(result)) { if (!sandbox.is_error(result)) {
if (!stack.filled && match[1]) stack.push({ if (!stack.filled && match[1]) stack.push({
code: code, code: code,
@@ -2292,7 +2322,7 @@ for (var round = 1; round <= num_iterations; round++) {
process.stdout.write(round + " of " + num_iterations + "\r"); process.stdout.write(round + " of " + num_iterations + "\r");
original_code = createTopLevelCode(); original_code = createTopLevelCode();
var orig_result = [ sandbox.run_code(original_code), sandbox.run_code(original_code, true) ]; var orig_result = [ run_code(original_code), run_code(original_code, true) ];
if (orig_result.some(function(result, toplevel) { if (orig_result.some(function(result, toplevel) {
if (typeof result == "string") return; if (typeof result == "string") return;
println(); println();
@@ -2317,7 +2347,7 @@ for (var round = 1; round <= num_iterations; round++) {
errored = typeof original_result != "string"; errored = typeof original_result != "string";
if (!uglify_code.error) { if (!uglify_code.error) {
uglify_code = uglify_code.code; uglify_code = uglify_code.code;
uglify_result = sandbox.run_code(uglify_code, toplevel); uglify_result = run_code(uglify_code, toplevel);
ok = sandbox.same_stdout(original_result, uglify_result); ok = sandbox.same_stdout(original_result, uglify_result);
// ignore v8 parser bug // ignore v8 parser bug
if (!ok && bug_async_arrow_rest(uglify_result)) ok = true; if (!ok && bug_async_arrow_rest(uglify_result)) ok = true;
@@ -2328,13 +2358,13 @@ for (var round = 1; round <= num_iterations; round++) {
ok = true; ok = true;
} else { } else {
// ignore spurious time-outs // ignore spurious time-outs
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = sandbox.run_code(original_code, toplevel, 10000); if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = run_code(original_code, toplevel, 10000);
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result); ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
} }
} }
// ignore declaration order of global variables // ignore declaration order of global variables
if (!ok && !toplevel) { if (!ok && !toplevel) {
ok = sandbox.same_stdout(sandbox.run_code(sort_globals(original_code)), sandbox.run_code(sort_globals(uglify_code))); ok = sandbox.same_stdout(run_code(sort_globals(original_code)), run_code(sort_globals(uglify_code)));
} }
// ignore numerical imprecision caused by `unsafe_math` // ignore numerical imprecision caused by `unsafe_math`
if (!ok && o.compress && o.compress.unsafe_math && typeof original_result == typeof uglify_result) { if (!ok && o.compress && o.compress.unsafe_math && typeof original_result == typeof uglify_result) {
@@ -2344,7 +2374,7 @@ for (var round = 1; round <= num_iterations; round++) {
ok = original_result.name == uglify_result.name && fuzzy_match(original_result.message, uglify_result.message); ok = original_result.name == uglify_result.name && fuzzy_match(original_result.message, uglify_result.message);
} }
if (!ok) { if (!ok) {
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel); var fuzzy_result = run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel);
ok = sandbox.same_stdout(fuzzy_result, uglify_result); ok = sandbox.same_stdout(fuzzy_result, uglify_result);
} }
} }
@@ -2352,8 +2382,8 @@ for (var round = 1; round <= num_iterations; round++) {
if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true; if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
// ignore difference due to implicit strict-mode in `class` // ignore difference due to implicit strict-mode in `class`
if (!ok && /\bclass\b/.test(original_code)) { if (!ok && /\bclass\b/.test(original_code)) {
var original_strict = sandbox.run_code('"use strict";' + original_code, toplevel); var original_strict = run_code('"use strict";' + original_code, toplevel);
var uglify_strict = sandbox.run_code('"use strict";' + uglify_code, toplevel); var uglify_strict = run_code('"use strict";' + uglify_code, toplevel);
if (typeof original_strict != "string" && /strict/.test(original_strict.message)) { if (typeof original_strict != "string" && /strict/.test(original_strict.message)) {
ok = typeof uglify_strict != "string" && /strict/.test(uglify_strict.message); ok = typeof uglify_strict != "string" && /strict/.test(uglify_strict.message);
} else { } else {
@@ -2385,7 +2415,7 @@ for (var round = 1; round <= num_iterations; round++) {
var orig_skipped = patch_try_catch(original_code, toplevel); var orig_skipped = patch_try_catch(original_code, toplevel);
var uglify_skipped = patch_try_catch(uglify_code, toplevel); var uglify_skipped = patch_try_catch(uglify_code, toplevel);
if (orig_skipped && uglify_skipped) { if (orig_skipped && uglify_skipped) {
ok = sandbox.same_stdout(sandbox.run_code(orig_skipped, toplevel), sandbox.run_code(uglify_skipped, toplevel)); ok = sandbox.same_stdout(run_code(orig_skipped, toplevel), run_code(uglify_skipped, toplevel));
} }
} }
} else { } else {