aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/mocha/reduce.js48
-rw-r--r--test/reduce.js114
2 files changed, 124 insertions, 38 deletions
diff --git a/test/mocha/reduce.js b/test/mocha/reduce.js
index a6c8a752..779dd99f 100644
--- a/test/mocha/reduce.js
+++ b/test/mocha/reduce.js
@@ -246,4 +246,52 @@ describe("test/reduce.js", function() {
"// }",
].join("\n"));
});
+ it("Should reduce test case which differs only in Error.message", function() {
+ var code = [
+ "var a=0;",
+ "try{",
+ "null[function(){}]",
+ "}catch(e){",
+ "for(var i in e.toString())a++",
+ "}",
+ "console.log(a);",
+ ].join("");
+ var result = reduce_test(code, {
+ compress: false,
+ mangle: false,
+ output: {
+ beautify: true,
+ },
+ });
+ if (result.error) throw result.error;
+ assert.strictEqual(result.code.replace(/function \(/g, "function("), (semver.satisfies(process.version, "<=0.10") ? [
+ "// Can't reproduce test failure",
+ "// minify options: {",
+ '// "compress": false,',
+ '// "mangle": false,',
+ '// "output": {',
+ '// "beautify": true',
+ "// }",
+ "// }",
+ ] : [
+ [
+ "try{",
+ "null[function(){}]",
+ "}catch(e){",
+ "console.log(e)",
+ "}",
+ ].join(""),
+ "// output: TypeError: Cannot read property 'function(){}' of null",
+ "// ",
+ "// minify: TypeError: Cannot read property 'function() {}' of null",
+ "// ",
+ "// options: {",
+ '// "compress": false,',
+ '// "mangle": false,',
+ '// "output": {',
+ '// "beautify": true',
+ "// }",
+ "// }",
+ ]).join("\n"));
+ });
});
diff --git a/test/reduce.js b/test/reduce.js
index 7d358968..c3ee7c93 100644
--- a/test/reduce.js
+++ b/test/reduce.js
@@ -125,40 +125,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
}
else if (node instanceof U.AST_Binary) {
- CHANGED = true;
var permute = ((node.start._permute += step) * steps | 0) % 4;
var expr = [
node.left,
node.right,
][ permute & 1 ];
- if (permute < 2) return expr;
- // wrap with console.log()
- return new U.AST_Call({
- expression: new U.AST_Dot({
- expression: new U.AST_SymbolRef({
- name: "console",
- start: {},
- }),
- property: "log",
- start: {},
- }),
- args: [ expr ],
- start: {},
- });
- }
- else if (node instanceof U.AST_Catch || node instanceof U.AST_Finally) {
- // drop catch or finally block
- node.start._permute++;
- CHANGED = true;
- return null;
- }
- else if (node instanceof U.AST_Conditional) {
CHANGED = true;
- return [
- node.condition,
- node.consequent,
- node.alternative,
- ][ ((node.start._permute += step) * steps | 0) % 3 ];
+ return permute < 2 ? expr : wrap_with_console_log(expr);
}
else if (node instanceof U.AST_BlockStatement) {
if (in_list) {
@@ -193,12 +166,26 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return to_sequence(seq);
}
}
+ else if (node instanceof U.AST_Catch) {
+ // drop catch block
+ node.start._permute++;
+ CHANGED = true;
+ return null;
+ }
+ else if (node instanceof U.AST_Conditional) {
+ CHANGED = true;
+ return [
+ node.condition,
+ node.consequent,
+ node.alternative,
+ ][ ((node.start._permute += step) * steps | 0) % 3 ];
+ }
else if (node instanceof U.AST_Defun) {
switch (((node.start._permute += step) * steps | 0) % 2) {
case 0:
CHANGED = true;
return List.skip;
- case 1:
+ default:
if (!has_exit(node)) {
// hoist function declaration body
var body = node.body;
@@ -230,15 +217,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return to_statement(expr);
}
}
- else if (node instanceof U.AST_PropAccess) {
- var expr = [
- node.expression,
- node.property instanceof U.AST_Node && node.property,
- ][ node.start._permute++ % 2 ];
- if (expr) {
- CHANGED = true;
- return expr;
- }
+ else if (node instanceof U.AST_Finally) {
+ // drop finally block
+ node.start._permute++;
+ CHANGED = true;
+ return null;
}
else if (node instanceof U.AST_For) {
var expr = [
@@ -287,6 +270,16 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return expr;
}
}
+ else if (node instanceof U.AST_PropAccess) {
+ var expr = [
+ node.expression,
+ node.property instanceof U.AST_Node && node.property,
+ ][ node.start._permute++ % 2 ];
+ if (expr) {
+ CHANGED = true;
+ return expr;
+ }
+ }
else if (node instanceof U.AST_SimpleStatement) {
if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) {
// hoist simple statement IIFE function expression body
@@ -414,8 +407,36 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
});
+ var diff_error_message;
for (var pass = 1; pass <= 3; ++pass) {
var testcase_ast = U.parse(testcase);
+ if (diff_error_message === testcase) {
+ // only difference detected is in error message, so expose that and try again
+ testcase_ast.transform(new U.TreeTransformer(function(node, descend) {
+ if (node.TYPE == "Call" && node.expression.print_to_string() == "console.log") {
+ return new U.AST_Sequence({
+ expressions: node.args,
+ start: {},
+ });
+ }
+ if (node instanceof U.AST_Catch) {
+ descend(node, this);
+ node.body.unshift(new U.AST_SimpleStatement({
+ body: wrap_with_console_log(new U.AST_SymbolRef(node.argname)),
+ start: {},
+ }));
+ return node;
+ }
+ }));
+ var code = testcase_ast.print_to_string();
+ if (diff = producesDifferentResultWhenMinified(result_cache, code, minify_options, max_timeout)) {
+ testcase = code;
+ differs = diff;
+ } else {
+ testcase_ast = U.parse(testcase);
+ }
+ }
+ diff_error_message = null;
testcase_ast.walk(new U.TreeWalker(function(node) {
// unshare start props to retain visit data between iterations
node.start = JSON.parse(JSON.stringify(node.start));
@@ -457,6 +478,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
&& is_error(diff.minified_result)
&& diff.unminified_result.name == diff.minified_result.name) {
// ignore difference in error messages caused by minification
+ diff_error_message = testcase;
} else {
// latest permutation is valid, so use it as the basis of new changes
testcase_ast = code_ast;
@@ -592,6 +614,22 @@ function to_statement(node) {
});
}
+function wrap_with_console_log(node) {
+ // wrap with console.log()
+ return new U.AST_Call({
+ expression: new U.AST_Dot({
+ expression: new U.AST_SymbolRef({
+ name: "console",
+ start: {},
+ }),
+ property: "log",
+ start: {},
+ }),
+ args: [ node ],
+ start: {},
+ });
+}
+
function run_code(result_cache, code, toplevel, timeout) {
var key = crypto.createHash("sha1").update(code).digest("base64");
return result_cache[key] || (result_cache[key] = sandbox.run_code(code, toplevel, timeout));