improve `--reduce-test` (#3719)
authorAlex Lam S.L <alexlamsl@gmail.com>
Fri, 14 Feb 2020 02:47:20 +0000 (02:47 +0000)
committerGitHub <noreply@github.com>
Fri, 14 Feb 2020 02:47:20 +0000 (02:47 +0000)
- cover missing cases when eliminating unreferenced labels
- format multi-line outputs correctly

test/input/reduce/label.js [new file with mode: 0644]
test/input/reduce/label.reduced.js [new file with mode: 0644]
test/input/reduce/unsafe_math.js [moved from test/input/reduce/input.js with 100% similarity]
test/input/reduce/unsafe_math.reduced.js [moved from test/input/reduce/output.js with 65% similarity]
test/mocha/reduce.js
test/reduce.js

diff --git a/test/input/reduce/label.js b/test/input/reduce/label.js
new file mode 100644 (file)
index 0000000..aee57a4
--- /dev/null
@@ -0,0 +1,9 @@
+var o = this;
+
+for (var k in o) L17060: {
+    a++;
+}
+
+var a;
+
+console.log(k);
diff --git a/test/input/reduce/label.reduced.js b/test/input/reduce/label.reduced.js
new file mode 100644 (file)
index 0000000..faaa206
--- /dev/null
@@ -0,0 +1,16 @@
+var o = this;
+
+for (var k in o) {
+    0;
+}
+
+var a;
+
+console.log(k);
+// output: a
+// 
+// minify: k
+// 
+// options: {
+//   "mangle": false
+// }
\ No newline at end of file
similarity index 65%
rename from test/input/reduce/output.js
rename to test/input/reduce/unsafe_math.reduced.js
index 25ea7fe..ac2f189 100644 (file)
@@ -11,5 +11,12 @@ var a_1 = f0();
 
 console.log(b);
 // output: -19
+// 
 // minify: -4
-// options: {"compress":{"unsafe_math":true},"mangle":false}
\ No newline at end of file
+// 
+// options: {
+//   "compress": {
+//     "unsafe_math": true
+//   },
+//   "mangle": false
+// }
\ No newline at end of file
index 0e21666..f55c278 100644 (file)
@@ -8,9 +8,9 @@ function read(path) {
 }
 
 describe("test/reduce.js", function() {
+    this.timeout(60000);
     it("Should reduce test case", function() {
-        this.timeout(60000);
-        var result = reduce_test(read("test/input/reduce/input.js"), {
+        var result = reduce_test(read("test/input/reduce/unsafe_math.js"), {
             compress: {
                 unsafe_math: true,
             },
@@ -19,7 +19,16 @@ describe("test/reduce.js", function() {
             verbose: false,
         });
         if (result.error) throw result.error;
-        assert.strictEqual(result.code, read("test/input/reduce/output.js"));
+        assert.strictEqual(result.code, read("test/input/reduce/unsafe_math.reduced.js"));
+    });
+    it("Should eliminate unreferenced labels", function() {
+        var result = reduce_test(read("test/input/reduce/label.js"), {
+            mangle: false,
+        }, {
+            verbose: false,
+        });
+        if (result.error) throw result.error;
+        assert.strictEqual(result.code, read("test/input/reduce/label.reduced.js"));
     });
     it("Should handle test cases with --toplevel", function() {
         var result = reduce_test([
@@ -31,7 +40,9 @@ describe("test/reduce.js", function() {
         if (result.error) throw result.error;
         assert.strictEqual(result.code, [
             "// Can't reproduce test failure with minify options provided:",
-            '// {"toplevel":true}',
+            "// {",
+            '//   "toplevel": true',
+            "// }",
             "",
         ].join("\n"));
     });
@@ -40,7 +51,10 @@ describe("test/reduce.js", function() {
         if (result.error) throw result.error;
         assert.strictEqual(result.code, [
             "// Can't reproduce test failure with minify options provided:",
-            '// {"compress":{},"mangle":false}',
+            "// {",
+            '//   "compress": {},',
+            '//   "mangle": false',
+            "// }",
             "",
         ].join("\n"));
     });
@@ -61,8 +75,15 @@ describe("test/reduce.js", function() {
             "    return f.length;",
             "}());",
             "// output: 1",
+            "// ",
             "// minify: 0",
-            '// options: {"compress":{"keep_fargs":false},"mangle":false}',
+            "// ",
+            "// options: {",
+            '//   "compress": {',
+            '//     "keep_fargs": false',
+            "//   },",
+            '//   "mangle": false',
+            "// }",
         ].join("\n"));
     });
     it("Should fail when invalid option is supplied", function() {
@@ -81,4 +102,38 @@ describe("test/reduce.js", function() {
         assert.ok(err instanceof Error);
         assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Name expected");
     });
+    it("Should format multi-line output correctly", function() {
+        var code = [
+            "var a = 0;",
+            "",
+            "for (var b in [ 1, 2, 3 ]) {",
+            "    a = +a + 1 - .2;",
+            "    console.log(a);",
+            "}",
+        ].join("\n");
+        var result = reduce_test(code, {
+            compress: {
+                unsafe_math: true,
+            },
+            mangle: false,
+        });
+        if (result.error) throw result.error;
+        assert.strictEqual(result.code, [
+            code,
+            "// output: 0.8",
+            "// 1.6",
+            "// 2.4",
+            "// ",
+            "// minify: 0.8",
+            "// 1.6",
+            "// 2.4000000000000004",
+            "// ",
+            "// options: {",
+            '//   "compress": {',
+            '//     "unsafe_math": true',
+            "//   },",
+            '//   "mangle": false',
+            "// }",
+        ].join("\n"));
+    });
 });
index c997a87..20b1dd5 100644 (file)
@@ -22,7 +22,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
     var max_iterations = reduce_options.max_iterations || 1000;
     var max_timeout = reduce_options.max_timeout || 15000;
     var verbose = reduce_options.verbose;
-    var minify_options_json = JSON.stringify(minify_options);
+    var minify_options_json = JSON.stringify(minify_options, null, 2);
     var timeout = 1000; // start with a low timeout
     var differs;
 
@@ -256,6 +256,15 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
                 CHANGED = true;
                 return node.expression;
             }
+            else if (node instanceof U.AST_LabeledStatement) {
+                if (node.body instanceof U.AST_Statement
+                    && !has_loopcontrol(node.body, node.body, node)) {
+                    // replace labelled statement with its non-labelled body
+                    node.start._permute = REPLACEMENTS.length;
+                    CHANGED = true;
+                    return node.body;
+                }
+            }
 
             if (in_list) {
                 // special case to drop object properties and switch branches
@@ -268,14 +277,6 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
 
                 // replace or skip statement
                 if (node instanceof U.AST_Statement) {
-                    if (node instanceof U.AST_LabeledStatement
-                        && node.body instanceof U.AST_Statement
-                        && !has_loopcontrol(node.body, node.body, node)) {
-                        // replace labelled statement with its non-labelled body
-                        node.start._permute = REPLACEMENTS.length;
-                        CHANGED = true;
-                        return node.body;
-                    }
                     node.start._permute++;
                     CHANGED = true;
                     return List.skip;
@@ -379,13 +380,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
                 console.error("// reduce test pass " + pass + ": " + testcase.length + " bytes");
             }
         }
-        testcase += "\n// output: " + differs.unminified_result
-            + "\n// minify: " + differs.minified_result
-            + "\n// options: " + minify_options_json;
+        testcase += "\n// output: " + to_comment(differs.unminified_result)
+            + "\n// minify: " + to_comment(differs.minified_result)
+            + "\n// options: " + to_comment(minify_options_json);
     } else {
         // same stdout result produced when minified
         testcase = "// Can't reproduce test failure with minify options provided:"
-            + "\n// " + minify_options_json;
+            + "\n// " + to_comment(minify_options_json);
     }
     var result = U.minify(testcase.replace(/\u001b\[\d+m/g, ""), {
         compress: false,
@@ -399,6 +400,10 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
     return result;
 };
 
+function to_comment(value) {
+    return ("" + value).replace(/\n/g, "\n// ");
+}
+
 function has_loopcontrol(body, loop, label) {
     var found = false;
     var tw = new U.TreeWalker(function(node) {