detect `toplevel` option properly (#3735)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sat, 29 Feb 2020 17:33:48 +0000 (17:33 +0000)
committerGitHub <noreply@github.com>
Sat, 29 Feb 2020 17:33:48 +0000 (17:33 +0000)
fixes #3730

test/compress.js
test/mocha/minify.js
test/mocha/reduce.js
test/reduce.js
test/sandbox.js
test/ufuzz/index.js

index 6fc0b97..7672b20 100644 (file)
@@ -207,8 +207,9 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
             });
             return false;
         } else {
-            var expected = stdout[options.toplevel ? 1 : 0];
-            var actual = run_code(result.code, options.toplevel);
+            var toplevel = sandbox.has_toplevel(options);
+            var expected = stdout[toplevel ? 1 : 0];
+            var actual = run_code(result.code, toplevel);
             if (typeof expected != "string" && typeof actual != "string" && expected.name == actual.name) {
                 actual = expected;
             }
@@ -378,7 +379,10 @@ function test_case(test) {
     }
     if (test.expect_stdout && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
         var stdout = [ run_code(input_code), run_code(input_code, true) ];
-        var toplevel = test.options.toplevel;
+        var toplevel = sandbox.has_toplevel({
+            compress: test.options,
+            mangle: test.mangle
+        });
         var actual = stdout[toplevel ? 1 : 0];
         if (test.expect_stdout === true) {
             test.expect_stdout = actual;
index 786edd8..a41289f 100644 (file)
@@ -51,7 +51,7 @@ describe("minify", function() {
             "var a=n(3),b=r(12);",
             'c("qux",a,b),o(11);',
         ].join(""));
-        assert.strictEqual(run_code(compressed), run_code(original));
+        assert.strictEqual(run_code(compressed, true), run_code(original, true));
     });
 
     it("Should work with nameCache", function() {
@@ -84,7 +84,7 @@ describe("minify", function() {
             "var a=n(3),b=r(12);",
             'c("qux",a,b),o(11);',
         ].join(""));
-        assert.strictEqual(run_code(compressed), run_code(original));
+        assert.strictEqual(run_code(compressed, true), run_code(original, true));
     });
 
     it("Should avoid cached names when mangling top-level variables", function() {
@@ -113,7 +113,7 @@ describe("minify", function() {
             '"xxyyy";var y={y:2,a:3},a=4;',
             'console.log(x.x,y.y,y.a,a);',
         ].join(""));
-        assert.strictEqual(run_code(compressed), run_code(original));
+        assert.strictEqual(run_code(compressed, true), run_code(original, true));
     });
 
     it("Should avoid cached names when mangling inner-scoped variables", function() {
@@ -137,7 +137,7 @@ describe("minify", function() {
             'var o=function(o,n){console.log("extend");o();n()};function n(){console.log("A")}',
             'var e=function(n){function e(){console.log("B")}o(e,n);return e}(n);',
         ].join(""));
-        assert.strictEqual(run_code(compressed), run_code(original));
+        assert.strictEqual(run_code(compressed, true), run_code(original, true));
     });
 
     it("Should not parse invalid use of reserved words", function() {
index c7d5a7d..7eacbd7 100644 (file)
@@ -46,6 +46,44 @@ describe("test/reduce.js", function() {
             "// }",
         ].join("\n"));
     });
+    it("Should handle test cases with --compress toplevel", function() {
+        var result = reduce_test([
+            "var NaN = 42;",
+            "console.log(NaN);",
+        ].join("\n"), {
+            compress: {
+                toplevel: true,
+            },
+        });
+        if (result.error) throw result.error;
+        assert.strictEqual(result.code, [
+            "// Can't reproduce test failure with minify options provided:",
+            "// {",
+            '//   "compress": {',
+            '//     "toplevel": true',
+            "//   }",
+            "// }",
+        ].join("\n"));
+    });
+    it("Should handle test cases with --mangle toplevel", function() {
+        var result = reduce_test([
+            "var undefined = 42;",
+            "console.log(undefined);",
+        ].join("\n"), {
+            mangle: {
+                toplevel: true,
+            },
+        });
+        if (result.error) throw result.error;
+        assert.strictEqual(result.code, [
+            "// Can't reproduce test failure with minify options provided:",
+            "// {",
+            '//   "mangle": {',
+            '//     "toplevel": true',
+            "//   }",
+            "// }",
+        ].join("\n"));
+    });
     it("Should handle test result of NaN", function() {
         var result = reduce_test("throw 0 / 0;");
         if (result.error) throw result.error;
index 557fffd..eb6fb5c 100644 (file)
@@ -543,7 +543,7 @@ function producesDifferentResultWhenMinified(result_cache, code, minify_options,
     var minified = U.minify(code, minify_options);
     if (minified.error) return minified;
 
-    var toplevel = minify_options.toplevel;
+    var toplevel = sandbox.has_toplevel(minify_options);
     var elapsed = Date.now();
     var unminified_result = run_code(result_cache, code, toplevel, max_timeout);
     elapsed = Date.now() - elapsed;
index ef77d2a..2f9ec67 100644 (file)
@@ -87,3 +87,8 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
 } : 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;
+};
index 2083a90..e462d9d 100644 (file)
@@ -1022,7 +1022,7 @@ function log_suspects(minify_options, component) {
                 errorln("Error testing options." + component + "." + name);
                 errorln(result.error);
             } else {
-                var r = sandbox.run_code(result.code, m.toplevel);
+                var r = sandbox.run_code(result.code, sandbox.has_toplevel(m));
                 return sandbox.same_stdout(original_result, r);
             }
         }
@@ -1037,14 +1037,14 @@ function log_suspects(minify_options, component) {
 }
 
 function log_rename(options) {
-    var m = JSON.parse(JSON.stringify(options));
+    var m = JSON.parse(options);
     m.rename = false;
     var result = UglifyJS.minify(original_code, m);
     if (result.error) {
         errorln("Error testing options.rename");
         errorln(result.error);
     } else {
-        var r = sandbox.run_code(result.code, m.toplevel);
+        var r = sandbox.run_code(result.code, sandbox.has_toplevel(m));
         if (sandbox.same_stdout(original_result, r)) {
             errorln("Suspicious options:");
             errorln("  rename");
@@ -1054,19 +1054,18 @@ function log_rename(options) {
 }
 
 function log(options) {
-    var options_copy = JSON.parse(options);
-    options = JSON.parse(options);
+    var toplevel = sandbox.has_toplevel(JSON.parse(options));
     if (!ok) errorln("\n\n\n\n\n\n!!!!!!!!!!\n\n\n");
     errorln("//=============================================================");
     if (!ok) errorln("// !!!!!! Failed... round " + round);
     errorln("// original code");
-    try_beautify(original_code, options.toplevel, original_result, errorln);
+    try_beautify(original_code, toplevel, original_result, errorln);
     errorln();
     errorln();
     errorln("//-------------------------------------------------------------");
     if (typeof uglify_code == "string") {
         errorln("// uglified code");
-        try_beautify(uglify_code, options.toplevel, uglify_result, errorln);
+        try_beautify(uglify_code, toplevel, uglify_result, errorln);
         errorln();
         errorln();
         errorln("original result:");
@@ -1074,7 +1073,7 @@ function log(options) {
         errorln("uglified result:");
         errorln(uglify_result);
         errorln("//-------------------------------------------------------------");
-        var reduced = reduce_test(original_code, options_copy, {
+        var reduced = reduce_test(original_code, JSON.parse(options), {
             verbose: false,
         }).code;
         if (reduced) {
@@ -1096,10 +1095,10 @@ function log(options) {
         }
     }
     errorln("minify(options):");
-    errorln(JSON.stringify(options, null, 2));
+    errorln(JSON.stringify(JSON.parse(options), null, 2));
     errorln();
     if (!ok && typeof uglify_code == "string") {
-        Object.keys(default_options).forEach(log_suspects.bind(null, options));
+        Object.keys(default_options).forEach(log_suspects.bind(null, JSON.parse(options)));
         log_rename(options);
         errorln("!!!!!! Failed... round " + round);
     }
@@ -1135,16 +1134,17 @@ for (var round = 1; round <= num_iterations; round++) {
     if (!errored) orig_result.push(sandbox.run_code(original_code, true));
     (errored ? fallback_options : minify_options).forEach(function(options) {
         var o = JSON.parse(options);
+        var toplevel = sandbox.has_toplevel(o);
         uglify_code = UglifyJS.minify(original_code, o);
-        original_result = orig_result[o.toplevel ? 1 : 0];
+        original_result = orig_result[toplevel ? 1 : 0];
         if (!uglify_code.error) {
             uglify_code = uglify_code.code;
-            uglify_result = sandbox.run_code(uglify_code, o.toplevel);
+            uglify_result = sandbox.run_code(uglify_code, toplevel);
             ok = sandbox.same_stdout(original_result, uglify_result);
             if (!ok && typeof uglify_result == "string" && o.compress.unsafe_math) {
                 ok = fuzzy_match(original_result, uglify_result);
                 if (!ok) {
-                    var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"));
+                    var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel);
                     ok = sandbox.same_stdout(fuzzy_result, uglify_result);
                 }
             }
@@ -1158,7 +1158,7 @@ for (var round = 1; round <= num_iterations; round++) {
         else if (errored) {
             println("//=============================================================");
             println("// original code");
-            try_beautify(original_code, o.toplevel, original_result, println);
+            try_beautify(original_code, toplevel, original_result, println);
             println();
             println();
             println("original result:");