diff options
Diffstat (limited to 'test')
39 files changed, 3517 insertions, 269 deletions
diff --git a/test/benchmark.js b/test/benchmark.js new file mode 100644 index 00000000..dc176a88 --- /dev/null +++ b/test/benchmark.js @@ -0,0 +1,49 @@ +#! /usr/bin/env node +// -*- js -*- + +"use strict"; + +var createHash = require("crypto").createHash; +var fork = require("child_process").fork; +var args = process.argv.slice(2); +if (!args.length) { + args.push("-mc", "warnings=false"); +} +args.push("--stats"); +var urls = [ + "https://code.jquery.com/jquery-3.1.1.js", + "https://code.angularjs.org/1.6.1/angular.js", + "https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js", + "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js", + "https://unpkg.com/react@15.3.2/dist/react.js", + "http://builds.emberjs.com/tags/v2.11.0/ember.prod.js", + "https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js", + "https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js", +]; +var results = {}; +var remaining = 2 * urls.length; +function done() { + if (!--remaining) { + urls.forEach(function(url) { + console.log(); + console.log(url); + console.log(results[url].time); + console.log("SHA1:", results[url].sha1); + }); + } +} +urls.forEach(function(url) { + results[url] = { time: "" }; + require(url.slice(0, url.indexOf(":"))).get(url, function(res) { + var uglifyjs = fork("bin/uglifyjs", args, { silent: true }); + res.pipe(uglifyjs.stdin); + uglifyjs.stdout.pipe(createHash("sha1")).on("data", function(data) { + results[url].sha1 = data.toString("hex"); + done(); + }); + uglifyjs.stderr.setEncoding("utf8"); + uglifyjs.stderr.on("data", function(data) { + results[url].time += data; + }).on("end", done) + }); +}); diff --git a/test/compress/arrays.js b/test/compress/arrays.js index 77ef761a..f0ded06c 100644 --- a/test/compress/arrays.js +++ b/test/compress/arrays.js @@ -21,10 +21,19 @@ constant_join: { input: { var a = [ "foo", "bar", "baz" ].join(""); var a1 = [ "foo", "bar", "baz" ].join(); + var a2 = [ "foo", "bar", "baz" ].join(null); + var a3 = [ "foo", "bar", "baz" ].join(void 0); + var a4 = [ "foo", , "baz" ].join(); + var a5 = [ "foo", null, "baz" ].join(); + var a6 = [ "foo", void 0, "baz" ].join(); var b = [ "foo", 1, 2, 3, "bar" ].join(""); var c = [ boo(), "foo", 1, 2, 3, "bar", bar() ].join(""); var c1 = [ boo(), bar(), "foo", 1, 2, 3, "bar", bar() ].join(""); var c2 = [ 1, 2, "foo", "bar", baz() ].join(""); + var c3 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join(""); + var c4 = [ 1, 2, null, undefined, "foo", "bar", baz() ].join(""); + var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join(); + var c6 = [ 1, 2, null, undefined, "foo", "bar", baz() ].join(); var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-"); var e = [].join(foo + bar); var f = [].join(""); @@ -33,10 +42,19 @@ constant_join: { expect: { var a = "foobarbaz"; var a1 = "foo,bar,baz"; + var a2 = "foonullbarnullbaz"; + var a3 = "foo,bar,baz"; + var a4 = "foo,,baz"; + var a5 = "foo,,baz"; + var a6 = "foo,,baz"; var b = "foo123bar"; var c = boo() + "foo123bar" + bar(); var c1 = "" + boo() + bar() + "foo123bar" + bar(); var c2 = "12foobar" + baz(); + var c3 = boo() + bar() + "foo123bar" + bar() + "foo"; + var c4 = "12foobar" + baz(); + var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join(); + var c6 = [ "1,2,,,foo,bar", baz() ].join(); var d = "foo-3bar-baz"; var e = [].join(foo + bar); var f = ""; @@ -73,6 +91,41 @@ constant_join_2: { } } +constant_join_3: { + options = { + unsafe: true, + evaluate: true, + }; + input: { + var a = [ null ].join(); + var b = [ , ].join(); + var c = [ , 1, , 3 ].join(); + var d = [ foo ].join(); + var e = [ foo, null, undefined, bar ].join("-"); + var f = [ foo, bar ].join(""); + var g = [ null, "foo", null, bar + "baz" ].join(""); + var h = [ null, "foo", null, bar + "baz" ].join("-"); + var i = [ "foo" + bar, null, baz + "moo" ].join(""); + var j = [ foo + "bar", baz ].join(""); + var k = [ foo, "bar" + baz ].join(""); + var l = [ foo, bar + "baz" ].join(""); + } + expect: { + var a = ""; + var b = ""; + var c = ",1,,3"; + var d = "" + foo; + var e = [ foo, "-", bar ].join("-"); + var f = "" + foo + bar; + var g = "foo" + bar + "baz"; + var h = [ "-foo-", bar + "baz" ].join("-"); + var i = "foo" + bar + baz + "moo"; + var j = foo + "bar" + baz; + var k = foo + "bar" + baz; + var l = foo + (bar + "baz"); + } +} + for_loop: { options = { unsafe : true, diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index ef7af9ed..d7432f3f 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -338,8 +338,9 @@ collapse_vars_while: { collapse_vars_do_while: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, - comparisons:true, evaluate:true, booleans:false, loops:false, unused:true, hoist_funs:true, - keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true + comparisons:true, evaluate:true, booleans:false, loops:false, unused:"keep_assign", + hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, + side_effects:true } input: { function f1(y) { @@ -409,6 +410,79 @@ collapse_vars_do_while: { } } +collapse_vars_do_while_drop_assign: { + options = { + collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, + comparisons:true, evaluate:true, booleans:false, loops:false, unused:true, hoist_funs:true, + keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true + } + input: { + function f1(y) { + // The constant do-while condition `c` will be replaced. + var c = 9; + do { } while (c === 77); + } + function f2(y) { + // The non-constant do-while condition `c` will not be replaced. + var c = 5 - y; + do { } while (c); + } + function f3(y) { + // The constant `x` will be replaced in the do loop body. + function fn(n) { console.log(n); } + var a = 2, x = 7; + do { + fn(a = x); + break; + } while (y); + } + function f4(y) { + // The non-constant `a` will not be replaced in the do loop body. + var a = y / 4; + do { + return a; + } while (y); + } + function f5(y) { + function p(x) { console.log(x); } + do { + // The non-constant `a` will be replaced in p(a) + // because it is declared in same block. + var a = y - 3; + p(a); + } while (--y); + } + } + expect: { + function f1(y) { + do ; while (false); + } + function f2(y) { + var c = 5 - y; + do ; while (c); + } + function f3(y) { + function fn(n) { console.log(n); } + do { + fn(7); + break; + } while (y); + } + function f4(y) { + var a = y / 4; + do + return a; + while (y); + } + function f5(y) { + function p(x) { console.log(x); } + do { + p(y - 3); + } while (--y); + } + } +} + collapse_vars_seq: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, @@ -567,8 +641,9 @@ collapse_vars_assignment: { collapse_vars_lvalues: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, - comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, - keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true + comparisons:true, evaluate:true, booleans:true, loops:true, unused:"keep_assign", + hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, + side_effects:true } input: { function f0(x) { var i = ++x; return x += i; } @@ -593,7 +668,38 @@ collapse_vars_lvalues: { function f7(x) { var w = e1(), v = e2(), c = v - x; return (w = x) - c; } function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); } function f9(x) { var w = e1(); return e2() - x - (w = x); } + } +} +collapse_vars_lvalues_drop_assign: { + options = { + collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, + comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, + keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true + } + input: { + function f0(x) { var i = ++x; return x += i; } + function f1(x) { var a = (x -= 3); return x += a; } + function f2(x) { var z = x, a = ++z; return z += a; } + function f3(x) { var a = (x -= 3), b = x + a; return b; } + function f4(x) { var a = (x -= 3); return x + a; } + function f5(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return b - c; } + function f6(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return c - b; } + function f7(x) { var w = e1(), v = e2(), c = v - x, b = w = x; return b - c; } + function f8(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return b - c; } + function f9(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return c - b; } + } + expect: { + function f0(x) { var i = ++x; return x += i; } + function f1(x) { var a = (x -= 3); return x += a; } + function f2(x) { var z = x, a = ++z; return z += a; } + function f3(x) { var a = (x -= 3); return x + a; } + function f4(x) { var a = (x -= 3); return x + a; } + function f5(x) { var v = (e1(), e2()), c = v = --x; return x - c; } + function f6(x) { e1(), e2(); return --x - x; } + function f7(x) { var v = (e1(), e2()), c = v - x; return x - c; } + function f8(x) { var v = (e1(), e2()); return x - (v - x); } + function f9(x) { e1(); return e2() - x - x; } } } diff --git a/test/compress/concat-strings.js b/test/compress/concat-strings.js index 50eef8b8..d2503c6d 100644 --- a/test/compress/concat-strings.js +++ b/test/compress/concat-strings.js @@ -24,3 +24,143 @@ concat_1: { var f = "\x00360\08\0"; } } + +concat_2: { + options = {}; + input: { + console.log( + 1 + (2 + 3), + 1 + (2 + "3"), + 1 + ("2" + 3), + 1 + ("2" + "3"), + "1" + (2 + 3), + "1" + (2 + "3"), + "1" + ("2" + 3), + "1" + ("2" + "3") + ); + } + expect: { + console.log( + 1 + (2 + 3), + 1 + (2 + "3"), + 1 + "2" + 3, + 1 + "2" + "3", + "1" + (2 + 3), + "1" + 2 + "3", + "1" + "2" + 3, + "1" + "2" + "3" + ); + } +} + +concat_3: { + options = {}; + input: { + console.log( + 1 + 2 + (3 + 4 + 5), + 1 + 2 + (3 + 4 + "5"), + 1 + 2 + (3 + "4" + 5), + 1 + 2 + (3 + "4" + "5"), + 1 + 2 + ("3" + 4 + 5), + 1 + 2 + ("3" + 4 + "5"), + 1 + 2 + ("3" + "4" + 5), + 1 + 2 + ("3" + "4" + "5") + ); + } + expect: { + console.log( + 1 + 2 + (3 + 4 + 5), + 1 + 2 + (3 + 4 + "5"), + 1 + 2 + (3 + "4") + 5, + 1 + 2 + (3 + "4") + "5", + 1 + 2 + "3" + 4 + 5, + 1 + 2 + "3" + 4 + "5", + 1 + 2 + "3" + "4" + 5, + 1 + 2 + "3" + "4" + "5" + ); + } +} + +concat_4: { + options = {}; + input: { + console.log( + 1 + "2" + (3 + 4 + 5), + 1 + "2" + (3 + 4 + "5"), + 1 + "2" + (3 + "4" + 5), + 1 + "2" + (3 + "4" + "5"), + 1 + "2" + ("3" + 4 + 5), + 1 + "2" + ("3" + 4 + "5"), + 1 + "2" + ("3" + "4" + 5), + 1 + "2" + ("3" + "4" + "5") + ); + } + expect: { + console.log( + 1 + "2" + (3 + 4 + 5), + 1 + "2" + (3 + 4) + "5", + 1 + "2" + 3 + "4" + 5, + 1 + "2" + 3 + "4" + "5", + 1 + "2" + "3" + 4 + 5, + 1 + "2" + "3" + 4 + "5", + 1 + "2" + "3" + "4" + 5, + 1 + "2" + "3" + "4" + "5" + ); + } +} + +concat_5: { + options = {}; + input: { + console.log( + "1" + 2 + (3 + 4 + 5), + "1" + 2 + (3 + 4 + "5"), + "1" + 2 + (3 + "4" + 5), + "1" + 2 + (3 + "4" + "5"), + "1" + 2 + ("3" + 4 + 5), + "1" + 2 + ("3" + 4 + "5"), + "1" + 2 + ("3" + "4" + 5), + "1" + 2 + ("3" + "4" + "5") + ); + } + expect: { + console.log( + "1" + 2 + (3 + 4 + 5), + "1" + 2 + (3 + 4) + "5", + "1" + 2 + 3 + "4" + 5, + "1" + 2 + 3 + "4" + "5", + "1" + 2 + "3" + 4 + 5, + "1" + 2 + "3" + 4 + "5", + "1" + 2 + "3" + "4" + 5, + "1" + 2 + "3" + "4" + "5" + ); + } +} + +concat_6: { + options = {}; + input: { + console.log( + "1" + "2" + (3 + 4 + 5), + "1" + "2" + (3 + 4 + "5"), + "1" + "2" + (3 + "4" + 5), + "1" + "2" + (3 + "4" + "5"), + "1" + "2" + ("3" + 4 + 5), + "1" + "2" + ("3" + 4 + "5"), + "1" + "2" + ("3" + "4" + 5), + "1" + "2" + ("3" + "4" + "5") + ); + } + expect: { + console.log( + "1" + "2" + (3 + 4 + 5), + "1" + "2" + (3 + 4) + "5", + "1" + "2" + 3 + "4" + 5, + "1" + "2" + 3 + "4" + "5", + "1" + "2" + "3" + 4 + 5, + "1" + "2" + "3" + 4 + "5", + "1" + "2" + "3" + "4" + 5, + "1" + "2" + "3" + "4" + "5" + ); + } +} diff --git a/test/compress/const.js b/test/compress/const.js new file mode 100644 index 00000000..f1f13f49 --- /dev/null +++ b/test/compress/const.js @@ -0,0 +1,165 @@ +issue_1191: { + options = { + evaluate : true, + booleans : true, + comparisons : true, + dead_code : true, + conditionals : true, + side_effects : true, + unused : true, + hoist_funs : true, + if_return : true, + join_vars : true, + sequences : false, + collapse_vars : false, + reduce_vars : true, + } + input: { + function foo(rot) { + const rotTol = 5; + if (rot < -rotTol || rot > rotTol) + bar(); + baz(); + } + } + expect: { + function foo(rot) { + (rot < -5 || rot > 5) && bar(); + baz(); + } + } +} + +issue_1194: { + options = { + evaluate : true, + booleans : true, + comparisons : true, + dead_code : true, + conditionals : true, + side_effects : true, + unused : true, + hoist_funs : true, + if_return : true, + join_vars : true, + sequences : false, + collapse_vars : false, + reduce_vars : true, + } + input: { + function f1() {const a = "X"; return a + a;} + function f2() {const aa = "X"; return aa + aa;} + function f3() {const aaa = "X"; return aaa + aaa;} + } + expect: { + function f1(){return"XX"} + function f2(){return"XX"} + function f3(){return"XX"} + } +} + +issue_1396: { + options = { + evaluate : true, + booleans : true, + comparisons : true, + dead_code : true, + conditionals : true, + side_effects : true, + unused : true, + hoist_funs : true, + if_return : true, + join_vars : true, + sequences : false, + collapse_vars : false, + reduce_vars : true, + } + input: { + function foo(a) { + const VALUE = 1; + console.log(2 | VALUE); + console.log(VALUE + 1); + console.log(VALUE); + console.log(a & VALUE); + } + function bar() { + const s = "01234567890123456789"; + console.log(s + s + s + s + s); + + const CONSTANT = "abc"; + console.log(CONSTANT + CONSTANT + CONSTANT + CONSTANT + CONSTANT); + } + } + expect: { + function foo(a) { + console.log(3); + console.log(2); + console.log(1); + console.log(1 & a); + } + function bar() { + const s = "01234567890123456789"; + console.log(s + s + s + s + s); + + console.log("abcabcabcabcabc"); + } + } +} + +unused_regexp_literal: { + options = { + evaluate : true, + booleans : true, + comparisons : true, + dead_code : true, + conditionals : true, + side_effects : true, + unused : true, + hoist_funs : true, + if_return : true, + join_vars : true, + sequences : false, + collapse_vars : false, + } + input: { + function f(){ var a = /b/; } + } + expect: { + function f(){} + } +} + +regexp_literal_not_const: { + options = { + evaluate : true, + booleans : true, + comparisons : true, + dead_code : true, + conditionals : true, + side_effects : true, + unused : true, + hoist_funs : true, + if_return : true, + join_vars : true, + sequences : false, + collapse_vars : false, + reduce_vars : true, + } + input: { + (function(){ + var result; + const s = 'acdabcdeabbb'; + const REGEXP_LITERAL = /ab*/g; + while (result = REGEXP_LITERAL.exec(s)) { + console.log(result[0]); + } + })(); + } + expect: { + (function() { + var result; + const REGEXP_LITERAL = /ab*/g; + while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]); + })(); + } +} diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js index fa4b37d6..2596e80e 100644 --- a/test/compress/dead-code.js +++ b/test/compress/dead-code.js @@ -1,206 +1,208 @@ -dead_code_1: {
- options = {
- dead_code: true
- };
- input: {
- function f() {
- a();
- b();
- x = 10;
- return;
- if (x) {
- y();
- }
- }
- }
- expect: {
- function f() {
- a();
- b();
- x = 10;
- return;
- }
- }
-}
-
-dead_code_2_should_warn: {
- options = {
- dead_code: true
- };
- input: {
- function f() {
- g();
- x = 10;
- throw "foo";
- // completely discarding the `if` would introduce some
- // bugs. UglifyJS v1 doesn't deal with this issue; in v2
- // we copy any declarations to the upper scope.
- if (x) {
- y();
- var x;
- function g(){};
- // but nested declarations should not be kept.
- (function(){
- var q;
- function y(){};
- })();
- }
- }
- }
- expect: {
- function f() {
- g();
- x = 10;
- throw "foo";
- var x;
- function g(){};
- }
- }
-}
-
-dead_code_constant_boolean_should_warn_more: {
- options = {
- dead_code : true,
- loops : true,
- booleans : true,
- conditionals : true,
- evaluate : true
- };
- input: {
- while (!((foo && bar) || (x + "0"))) {
- console.log("unreachable");
- var foo;
- function bar() {}
- }
- for (var x = 10, y; x && (y || x) && (!typeof x); ++x) {
- asdf();
- foo();
- var moo;
- }
- }
- expect: {
- var foo;
- function bar() {}
- // nothing for the while
- // as for the for, it should keep:
- var x = 10, y;
- var moo;
- }
-}
-
-dead_code_const_declaration: {
- options = {
- dead_code : true,
- loops : true,
- booleans : true,
- conditionals : true,
- evaluate : true
- };
- input: {
- var unused;
- const CONST_FOO = false;
- if (CONST_FOO) {
- console.log("unreachable");
- var moo;
- function bar() {}
- }
- }
- expect: {
- var unused;
- const CONST_FOO = !1;
- var moo;
- function bar() {}
- }
-}
-
-dead_code_const_annotation: {
- options = {
- dead_code : true,
- loops : true,
- booleans : true,
- conditionals : true,
- evaluate : true
- };
- input: {
- var unused;
- /** @const */ var CONST_FOO_ANN = false;
- if (CONST_FOO_ANN) {
- console.log("unreachable");
- var moo;
- function bar() {}
- }
- }
- expect: {
- var unused;
- var CONST_FOO_ANN = !1;
- var moo;
- function bar() {}
- }
-}
-
-dead_code_const_annotation_regex: {
- options = {
- dead_code : true,
- loops : true,
- booleans : true,
- conditionals : true,
- evaluate : true
- };
- input: {
- var unused;
- // @constraint this shouldn't be a constant
- var CONST_FOO_ANN = false;
- if (CONST_FOO_ANN) {
- console.log("reachable");
- }
- }
- expect: {
- var unused;
- var CONST_FOO_ANN = !1;
- CONST_FOO_ANN && console.log('reachable');
- }
-}
-
-dead_code_const_annotation_complex_scope: {
- options = {
- dead_code : true,
- loops : true,
- booleans : true,
- conditionals : true,
- evaluate : true
- };
- input: {
- var unused_var;
- /** @const */ var test = 'test';
- // @const
- var CONST_FOO_ANN = false;
- var unused_var_2;
- if (CONST_FOO_ANN) {
- console.log("unreachable");
- var moo;
- function bar() {}
- }
- if (test === 'test') {
- var beef = 'good';
- /** @const */ var meat = 'beef';
- var pork = 'bad';
- if (meat === 'pork') {
- console.log('also unreachable');
- } else if (pork === 'good') {
- console.log('reached, not const');
- }
- }
- }
- expect: {
- var unused_var;
- var test = 'test';
- var CONST_FOO_ANN = !1;
- var unused_var_2;
- var moo;
- function bar() {}
- var beef = 'good';
- var meat = 'beef';
- var pork = 'bad';
- 'good' === pork && console.log('reached, not const');
- }
-}
+dead_code_1: { + options = { + dead_code: true + }; + input: { + function f() { + a(); + b(); + x = 10; + return; + if (x) { + y(); + } + } + } + expect: { + function f() { + a(); + b(); + x = 10; + return; + } + } +} + +dead_code_2_should_warn: { + options = { + dead_code: true + }; + input: { + function f() { + g(); + x = 10; + throw "foo"; + // completely discarding the `if` would introduce some + // bugs. UglifyJS v1 doesn't deal with this issue; in v2 + // we copy any declarations to the upper scope. + if (x) { + y(); + var x; + function g(){}; + // but nested declarations should not be kept. + (function(){ + var q; + function y(){}; + })(); + } + } + } + expect: { + function f() { + g(); + x = 10; + throw "foo"; + var x; + function g(){}; + } + } +} + +dead_code_constant_boolean_should_warn_more: { + options = { + dead_code : true, + loops : true, + booleans : true, + conditionals : true, + evaluate : true + }; + input: { + while (!((foo && bar) || (x + "0"))) { + console.log("unreachable"); + var foo; + function bar() {} + } + for (var x = 10, y; x && (y || x) && (!typeof x); ++x) { + asdf(); + foo(); + var moo; + } + } + expect: { + var foo; + function bar() {} + // nothing for the while + // as for the for, it should keep: + var x = 10, y; + var moo; + } +} + +dead_code_const_declaration: { + options = { + dead_code : true, + loops : true, + booleans : true, + conditionals : true, + evaluate : true, + reduce_vars : true, + }; + input: { + var unused; + const CONST_FOO = false; + if (CONST_FOO) { + console.log("unreachable"); + var moo; + function bar() {} + } + } + expect: { + var unused; + const CONST_FOO = !1; + var moo; + function bar() {} + } +} + +dead_code_const_annotation: { + options = { + dead_code : true, + loops : true, + booleans : true, + conditionals : true, + evaluate : true, + reduce_vars : true, + }; + input: { + var unused; + /** @const */ var CONST_FOO_ANN = false; + if (CONST_FOO_ANN) { + console.log("unreachable"); + var moo; + function bar() {} + } + } + expect: { + var unused; + var CONST_FOO_ANN = !1; + var moo; + function bar() {} + } +} + +dead_code_const_annotation_regex: { + options = { + dead_code : true, + loops : true, + booleans : true, + conditionals : true, + evaluate : true + }; + input: { + var unused; + // @constraint this shouldn't be a constant + var CONST_FOO_ANN = false; + if (CONST_FOO_ANN) { + console.log("reachable"); + } + } + expect: { + var unused; + var CONST_FOO_ANN = !1; + CONST_FOO_ANN && console.log('reachable'); + } +} + +dead_code_const_annotation_complex_scope: { + options = { + dead_code : true, + loops : true, + booleans : true, + conditionals : true, + evaluate : true, + reduce_vars : true, + }; + input: { + var unused_var; + /** @const */ var test = 'test'; + // @const + var CONST_FOO_ANN = false; + var unused_var_2; + if (CONST_FOO_ANN) { + console.log("unreachable"); + var moo; + function bar() {} + } + if (test === 'test') { + var beef = 'good'; + /** @const */ var meat = 'beef'; + var pork = 'bad'; + if (meat === 'pork') { + console.log('also unreachable'); + } else if (pork === 'good') { + console.log('reached, not const'); + } + } + } + expect: { + var unused_var; + var test = 'test'; + var CONST_FOO_ANN = !1; + var unused_var_2; + var moo; + function bar() {} + var beef = 'good'; + var meat = 'beef'; + var pork = 'bad'; + } +} diff --git a/test/compress/drop-console.js b/test/compress/drop-console.js index 162b339c..7df6d9dc 100644 --- a/test/compress/drop-console.js +++ b/test/compress/drop-console.js @@ -1,24 +1,24 @@ -drop_console_1: {
- options = {};
- input: {
- console.log('foo');
- console.log.apply(console, arguments);
- }
- expect: {
- console.log('foo');
- console.log.apply(console, arguments);
- }
-}
-
-drop_console_1: {
- options = { drop_console: true };
- input: {
- console.log('foo');
- console.log.apply(console, arguments);
- }
- expect: {
- // with regular compression these will be stripped out as well
- void 0;
- void 0;
- }
-}
+drop_console_1: { + options = {}; + input: { + console.log('foo'); + console.log.apply(console, arguments); + } + expect: { + console.log('foo'); + console.log.apply(console, arguments); + } +} + +drop_console_2: { + options = { drop_console: true }; + input: { + console.log('foo'); + console.log.apply(console, arguments); + } + expect: { + // with regular compression these will be stripped out as well + void 0; + void 0; + } +} diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index 035a428e..c1ca1b55 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -177,3 +177,505 @@ keep_fnames: { } } } + +drop_assign: { + options = { unused: true }; + input: { + function f1() { + var a; + a = 1; + } + function f2() { + var a = 1; + a = 2; + } + function f3(a) { + a = 1; + } + function f4() { + var a; + return a = 1; + } + function f5() { + var a; + return function() { + a = 1; + } + } + } + expect: { + function f1() { + 1; + } + function f2() { + 2; + } + function f3(a) { + 1; + } + function f4() { + return 1; + } + function f5() { + var a; + return function() { + a = 1; + } + } + } +} + +keep_assign: { + options = { unused: "keep_assign" }; + input: { + function f1() { + var a; + a = 1; + } + function f2() { + var a = 1; + a = 2; + } + function f3(a) { + a = 1; + } + function f4() { + var a; + return a = 1; + } + function f5() { + var a; + return function() { + a = 1; + } + } + } + expect: { + function f1() { + var a; + a = 1; + } + function f2() { + var a = 1; + a = 2; + } + function f3(a) { + a = 1; + } + function f4() { + var a; + return a = 1; + } + function f5() { + var a; + return function() { + a = 1; + } + } + } +} + +drop_toplevel_funcs: { + options = { toplevel: "funcs", unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, b = 1, c = g; + a = 2; + function g() {} + console.log(b = 3); + } +} + +drop_toplevel_vars: { + options = { toplevel: "vars", unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var c = g; + function f(d) { + return function() { + c = 2; + } + } + 2; + function g() {} + function h() {} + console.log(3); + } +} + +drop_toplevel_vars_fargs: { + options = { keep_fargs: false, toplevel: "vars", unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var c = g; + function f() { + return function() { + c = 2; + } + } + 2; + function g() {} + function h() {} + console.log(3); + } +} + +drop_toplevel_all: { + options = { toplevel: true, unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + 2; + console.log(3); + } +} + +drop_toplevel_retain: { + options = { top_retain: "f,a,o", unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + console.log(3); + } +} + +drop_toplevel_retain_array: { + options = { top_retain: [ "f", "a", "o" ], unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + console.log(3); + } +} + +drop_toplevel_retain_regex: { + options = { top_retain: /^[fao]$/, unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + console.log(3); + } +} + +drop_toplevel_all_retain: { + options = { toplevel: true, top_retain: "f,a,o", unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + console.log(3); + } +} + +drop_toplevel_funcs_retain: { + options = { toplevel: "funcs", top_retain: "f,a,o", unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + console.log(b = 3); + } +} + +drop_toplevel_vars_retain: { + options = { toplevel: "vars", top_retain: "f,a,o", unused: true }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(3); + } +} + +drop_toplevel_keep_assign: { + options = { toplevel: true, unused: "keep_assign" }; + input: { + var a, b = 1, c = g; + function f(d) { + return function() { + c = 2; + } + } + a = 2; + function g() {} + function h() {} + console.log(b = 3); + } + expect: { + var a, b = 1; + a = 2; + console.log(b = 3); + } +} + +drop_fargs: { + options = { + keep_fargs: false, + unused: true, + } + input: { + function f(a) { + var b = a; + } + } + expect: { + function f() {} + } +} + +drop_fnames: { + options = { + keep_fnames: false, + unused: true, + } + input: { + function f() { + return function g() { + var a = g; + }; + } + } + expect: { + function f() { + return function() {}; + } + } +} + +global_var: { + options = { + side_effects: true, + unused: true, + } + input: { + var a; + function foo(b) { + a; + b; + c; + typeof c === "undefined"; + c + b + a; + b && b.ar(); + return b; + } + } + expect: { + var a; + function foo(b) { + c; + c; + b && b.ar(); + return b; + } + } +} + +iife: { + options = { + side_effects: true, + unused: true, + } + input: { + function f() { + var a; + ~function() {}(b); + } + } + expect: { + function f() { + ~function() {}(b); + } + } +} + +drop_value: { + options = { + side_effects: true, + } + input: { + (1, [2, foo()], 3, {a:1, b:bar()}); + } + expect: { + foo(), bar(); + } +} + +const_assign: { + options = { + evaluate: true, + reduce_vars: true, + unused: true, + } + input: { + function f() { + const b = 2; + return 1 + b; + } + + function g() { + const b = 2; + b = 3; + return 1 + b; + } + } + expect: { + function f() { + return 3; + } + + function g() { + const b = 2; + b = 3; + return 1 + b; + } + } +} diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 0ff157dc..ae5e58d6 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -598,3 +598,51 @@ unsafe_prototype_function: { var h = "" + ({toString: 0}); } } + +call_args: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + const a = 1; + console.log(a); + +function(a) { + return a; + }(a); + } + expect: { + const a = 1; + console.log(1); + +function(a) { + return a; + }(1); + } +} + +in_boolean_context: { + options = { + booleans: true, + evaluate: true, + } + input: { + !42; + !"foo"; + ![1, 2]; + !/foo/; + !b(42); + !b("foo"); + !b([1, 2]); + !b(/foo/); + } + expect: { + !1; + !1; + !1; + !1; + !b(42); + !b("foo"); + !b([1, 2]); + !b(/foo/); + } +} diff --git a/test/compress/global_defs.js b/test/compress/global_defs.js new file mode 100644 index 00000000..a69d031e --- /dev/null +++ b/test/compress/global_defs.js @@ -0,0 +1,147 @@ +must_replace: { + options = { + global_defs: { + D: "foo bar", + } + } + input: { + console.log(D); + } + expect: { + console.log("foo bar"); + } +} + +keyword: { + options = { + global_defs: { + undefined: 0, + NaN: 1, + Infinity: 2, + }, + } + input: { + console.log(undefined, NaN, Infinity); + } + expect: { + console.log(0, 1, 2); + } +} + +object: { + options = { + evaluate: true, + global_defs: { + CONFIG: { + DEBUG: [ 0 ], + VALUE: 42, + }, + }, + unsafe: true, + } + input: { + function f(CONFIG) { + // CONFIG not global - do not replace + return CONFIG.VALUE; + } + function g() { + var CONFIG = { VALUE: 1 }; + // CONFIG not global - do not replace + return CONFIG.VALUE; + } + function h() { + return CONFIG.VALUE; + } + if (CONFIG.DEBUG[0]) + console.debug("foo"); + } + expect: { + function f(CONFIG) { + return CONFIG.VALUE; + } + function g() { + var CONFIG = { VALUE: 1 }; + return CONFIG.VALUE; + } + function h() { + return 42; + } + if (0) + console.debug("foo"); + } +} + +expanded: { + options = { + global_defs: { + "CONFIG.DEBUG": [ 0 ], + "CONFIG.VALUE": 42, + }, + } + input: { + function f(CONFIG) { + // CONFIG not global - do not replace + return CONFIG.VALUE; + } + function g() { + var CONFIG = { VALUE: 1 }; + // CONFIG not global - do not replace + return CONFIG.VALUE; + } + function h() { + return CONFIG.VALUE; + } + if (CONFIG.DEBUG[0]) + console.debug("foo"); + } + expect: { + function f(CONFIG) { + return CONFIG.VALUE; + } + function g() { + var CONFIG = { VALUE: 1 }; + return CONFIG.VALUE; + } + function h() { + return 42; + } + if ([0][0]) + console.debug("foo"); + } +} + +mixed: { + options = { + evaluate: true, + global_defs: { + "CONFIG.VALUE": 42, + "FOO.BAR": "moo", + }, + properties: true, + } + input: { + const FOO = { BAR: 0 }; + console.log(FOO.BAR); + console.log(++CONFIG.DEBUG); + console.log(++CONFIG.VALUE); + console.log(++CONFIG["VAL" + "UE"]); + console.log(++DEBUG[CONFIG.VALUE]); + CONFIG.VALUE.FOO = "bar"; + console.log(CONFIG); + } + expect: { + const FOO = { BAR: 0 }; + console.log("moo"); + console.log(++CONFIG.DEBUG); + console.log(++CONFIG.VALUE); + console.log(++CONFIG.VALUE); + console.log(++DEBUG[42]); + CONFIG.VALUE.FOO = "bar"; + console.log(CONFIG); + } + expect_warnings: [ + 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:126,22]', + 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]', + 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]', + ] +} diff --git a/test/compress/hoist_vars.js b/test/compress/hoist_vars.js new file mode 100644 index 00000000..6fe1c773 --- /dev/null +++ b/test/compress/hoist_vars.js @@ -0,0 +1,90 @@ +statements: { + options = { + hoist_funs: false, + hoist_vars: true, + } + input: { + function f() { + var a = 1; + var b = 2; + var c = 3; + function g() {} + return g(a, b, c); + } + } + expect: { + function f() { + var a = 1, b = 2, c = 3; + function g() {} + return g(a, b, c); + } + } +} + +statements_funs: { + options = { + hoist_funs: true, + hoist_vars: true, + } + input: { + function f() { + var a = 1; + var b = 2; + var c = 3; + function g() {} + return g(a, b, c); + } + } + expect: { + function f() { + function g() {} + var a = 1, b = 2, c = 3; + return g(a, b, c); + } + } +} + +sequences: { + options = { + hoist_funs: false, + hoist_vars: true, + } + input: { + function f() { + var a = 1, b = 2; + function g() {} + var c = 3; + return g(a, b, c); + } + } + expect: { + function f() { + var c, a = 1, b = 2; + function g() {} + c = 3; + return g(a, b, c); + } + } +} + +sequences_funs: { + options = { + hoist_funs: true, + hoist_vars: true, + } + input: { + function f() { + var a = 1, b = 2; + function g() {} + var c = 3; + return g(a, b, c); + } + } + expect: { + function f() { + function g() {} + var a = 1, b = 2, c = 3; + return g(a, b, c); + } + } +} diff --git a/test/compress/if_return.js b/test/compress/if_return.js index 78a6e818..0ac45c3c 100644 --- a/test/compress/if_return.js +++ b/test/compress/if_return.js @@ -170,8 +170,51 @@ if_return_7: { } } expect: { - // suboptimal - function f(x){return!!x||(foo(),void bar())} + function f(x){if(x)return!0;foo(),bar()} + } +} + +if_return_8: { + options = { + if_return: true, + sequences: true, + conditionals: true, + side_effects : true, + } + input: { + function f(e) { + if (2 == e) return foo(); + if (3 == e) return bar(); + if (4 == e) return baz(); + fail(e); + } + + function g(e) { + if (a(e)) return foo(); + if (b(e)) return bar(); + if (c(e)) return baz(); + fail(e); + } + + function h(e) { + if (a(e)) return foo(); + else if (b(e)) return bar(); + else if (c(e)) return baz(); + else fail(e); + } + + function i(e) { + if (a(e)) return foo(); + else if (b(e)) return bar(); + else if (c(e)) return baz(); + fail(e); + } + } + expect: { + function f(e){return 2==e?foo():3==e?bar():4==e?baz():void fail(e)} + function g(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)} + function h(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)} + function i(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)} } } @@ -205,3 +248,57 @@ issue_1089: { } } } + +issue_1437: { + options = { + if_return : true, + sequences : true, + conditionals : false + } + input: { + function x() { + if (a()) + return b(); + if (c()) + return d(); + else + e(); + f(); + } + } + expect: { + function x() { + if (a()) + return b(); + if (c()) + return d(); + else + e() + f(); + } + } +} + +issue_1437_conditionals: { + options = { + conditionals : true, + if_return : true, + sequences : true + } + input: { + function x() { + if (a()) + return b(); + if (c()) + return d(); + else + e(); + f(); + } + } + expect: { + function x() { + return a() ? b() : c() ? d() : (e(), f(), void 0); + } + } +} diff --git a/test/compress/issue-1041.js b/test/compress/issue-1041.js index 9dd176fd..cdbc22cc 100644 --- a/test/compress/issue-1041.js +++ b/test/compress/issue-1041.js @@ -13,7 +13,8 @@ const_declaration: { const_pragma: { options = { - evaluate: true + evaluate: true, + reduce_vars: true, }; input: { @@ -27,7 +28,8 @@ const_pragma: { // for completeness' sake not_const: { options = { - evaluate: true + evaluate: true, + reduce_vars: true, }; input: { diff --git a/test/compress/issue-105.js b/test/compress/issue-105.js deleted file mode 100644 index ca17adbf..00000000 --- a/test/compress/issue-105.js +++ /dev/null @@ -1,25 +0,0 @@ -typeof_eq_undefined: { - options = { - comparisons: true - }; - input: { a = typeof b.c != "undefined" } - expect: { a = "undefined" != typeof b.c } -} - -typeof_eq_undefined_unsafe: { - options = { - comparisons: true, - unsafe: true - }; - input: { a = typeof b.c != "undefined" } - expect: { a = void 0 !== b.c } -} - -typeof_eq_undefined_unsafe2: { - options = { - comparisons: true, - unsafe: true - }; - input: { a = "undefined" != typeof b.c } - expect: { a = void 0 !== b.c } -} diff --git a/test/compress/issue-1261.js b/test/compress/issue-1261.js new file mode 100644 index 00000000..dfbe2100 --- /dev/null +++ b/test/compress/issue-1261.js @@ -0,0 +1,118 @@ +pure_function_calls: { + options = { + evaluate : true, + conditionals : true, + comparisons : true, + side_effects : true, + booleans : true, + unused : true, + if_return : true, + join_vars : true, + cascade : true, + negate_iife : true, + } + input: { + // pure top-level IIFE will be dropped + // @__PURE__ - comment + (function() { + console.log("iife0"); + })(); + + // pure top-level IIFE assigned to unreferenced var will not be dropped + var iife1 = /*@__PURE__*/(function() { + console.log("iife1"); + function iife1() {} + return iife1; + })(); + + (function(){ + // pure IIFE in function scope assigned to unreferenced var will be dropped + var iife2 = /*#__PURE__*/(function() { + console.log("iife2"); + function iife2() {} + return iife2; + })(); + })(); + + // comment #__PURE__ comment + bar(), baz(), quux(); + a.b(), /* @__PURE__ */ c.d.e(), f.g(); + } + expect: { + var iife1 = function() { + console.log("iife1"); + function iife1() {} + return iife1; + }(); + + baz(), quux(); + a.b(), f.g(); + } + expect_warnings: [ + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:17,8]", + "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:17,8]", + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:30,37]", + "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:30,16]", + "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:28,8]", + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,8]", + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:39,31]", + ] +} + +pure_function_calls_toplevel: { + options = { + evaluate : true, + conditionals : true, + comparisons : true, + side_effects : true, + booleans : true, + unused : true, + if_return : true, + join_vars : true, + cascade : true, + negate_iife : true, + toplevel : true, + } + input: { + // pure top-level IIFE will be dropped + // @__PURE__ - comment + (function() { + console.log("iife0"); + })(); + + // pure top-level IIFE assigned to unreferenced var will be dropped + var iife1 = /*@__PURE__*/(function() { + console.log("iife1"); + function iife1() {} + return iife1; + })(); + + (function(){ + // pure IIFE in function scope assigned to unreferenced var will be dropped + var iife2 = /*#__PURE__*/(function() { + console.log("iife2"); + function iife2() {} + return iife2; + })(); + })(); + + // comment #__PURE__ comment + bar(), baz(), quux(); + a.b(), /* @__PURE__ */ c.d.e(), f.g(); + } + expect: { + baz(), quux(); + a.b(), f.g(); + } + expect_warnings: [ + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:79,8]", + "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:79,8]", + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]", + "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]", + "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]", + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]", + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]", + "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]", + "WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]", + ] +} diff --git a/test/compress/issue-1431.js b/test/compress/issue-1431.js index 731ebba8..9493fd37 100644 --- a/test/compress/issue-1431.js +++ b/test/compress/issue-1431.js @@ -1,3 +1,32 @@ +level_zero: { + options = { + keep_fnames: true + } + mangle = { + keep_fnames: true + } + input: { + function f(x) { + function n(a) { + return a * a; + } + return function() { + return x; + }; + } + } + expect: { + function f(r) { + function n(n) { + return n * n; + } + return function() { + return r; + }; + } + } +} + level_one: { options = { keep_fnames: true diff --git a/test/compress/issue-1443.js b/test/compress/issue-1443.js new file mode 100644 index 00000000..a2565872 --- /dev/null +++ b/test/compress/issue-1443.js @@ -0,0 +1,69 @@ +// tests assume that variable `undefined` not redefined and has `void 0` as value + +unsafe_undefined: { + options = { + if_return: true, + unsafe: true + } + mangle = {} + input: { + function f(undefined) { + return function() { + if (a) + return b; + if (c) + return d; + }; + } + } + expect: { + function f(n) { + return function() { + if (a) + return b; + if (c) + return d; + else + return n; + }; + } + } +} + +keep_fnames: { + options = { + if_return: true, + unsafe: true + } + mangle = { + keep_fnames: true + } + input: { + function f(undefined) { + return function() { + function n(a) { + return a * a; + } + if (a) + return b; + if (c) + return d; + }; + } + } + expect: { + function f(r) { + return function() { + function n(n) { + return n * n; + } + if (a) + return b; + if (c) + return d; + else + return r; + }; + } + } +} diff --git a/test/compress/issue-1446.js b/test/compress/issue-1446.js new file mode 100644 index 00000000..3d69aa09 --- /dev/null +++ b/test/compress/issue-1446.js @@ -0,0 +1,71 @@ +typeof_eq_undefined: { + options = { + comparisons: true + } + input: { + var a = typeof b != "undefined"; + b = typeof a != "undefined"; + var c = typeof d.e !== "undefined"; + var f = "undefined" === typeof g; + g = "undefined" === typeof f; + var h = "undefined" == typeof i.j; + } + expect: { + var a = "undefined" != typeof b; + b = void 0 !== a; + var c = void 0 !== d.e; + var f = "undefined" == typeof g; + g = void 0 === f; + var h = void 0 === i.j; + } +} + +typeof_eq_undefined_ie8: { + options = { + comparisons: true, + screw_ie8: false + } + input: { + var a = typeof b != "undefined"; + b = typeof a != "undefined"; + var c = typeof d.e !== "undefined"; + var f = "undefined" === typeof g; + g = "undefined" === typeof f; + var h = "undefined" == typeof i.j; + } + expect: { + var a = "undefined" != typeof b; + b = void 0 !== a; + var c = "undefined" != typeof d.e; + var f = "undefined" == typeof g; + g = void 0 === f; + var h = "undefined" == typeof i.j; + } +} + +undefined_redefined: { + options = { + comparisons: true + } + input: { + function f(undefined) { + var n = 1; + return typeof n == "undefined"; + } + } + expect_exact: "function f(undefined){var n=1;return void 0===n}" +} + +undefined_redefined_mangle: { + options = { + comparisons: true + } + mangle = {} + input: { + function f(undefined) { + var n = 1; + return typeof n == "undefined"; + } + } + expect_exact: "function f(n){var r=1;return void 0===r}" +} diff --git a/test/compress/issue-1447.js b/test/compress/issue-1447.js new file mode 100644 index 00000000..163acbc2 --- /dev/null +++ b/test/compress/issue-1447.js @@ -0,0 +1,45 @@ +else_with_empty_block: { + options = {} + input: { + if (x) + yes(); + else { + } + } + expect_exact: "if(x)yes();" +} + +else_with_empty_statement: { + options = {} + input: { + if (x) + yes(); + else + ; + } + expect_exact: "if(x)yes();" +} + +conditional_false_stray_else_in_loop: { + options = { + evaluate : true, + comparisons : true, + booleans : true, + unused : true, + loops : true, + side_effects : true, + dead_code : true, + hoist_vars : true, + join_vars : true, + if_return : true, + cascade : true, + conditionals : false, + } + input: { + for (var i = 1; i <= 4; ++i) { + if (i <= 2) continue; + console.log(i); + } + } + expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);" +} diff --git a/test/compress/issue-208.js b/test/compress/issue-208.js index 2f103786..fb9861f6 100644 --- a/test/compress/issue-208.js +++ b/test/compress/issue-208.js @@ -27,3 +27,44 @@ do_update_rhs: { MY_DEBUG += 0; } } + +mixed: { + options = { + evaluate: true, + global_defs: { + DEBUG: 0, + ENV: 1, + FOO: 2, + } + } + input: { + const ENV = 3; + var FOO = 4; + f(ENV * 10); + --FOO; + DEBUG = 1; + DEBUG++; + DEBUG += 1; + f(DEBUG); + x = DEBUG; + } + expect: { + const ENV = 3; + var FOO = 4; + f(10); + --FOO; + DEBUG = 1; + DEBUG++; + DEBUG += 1; + f(0); + x = 0; + } + expect_warnings: [ + 'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,14]', + 'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]', + 'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]', + 'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]', + 'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:46,8]', + 'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:47,8]', + ] +} diff --git a/test/compress/issue-979.js b/test/compress/issue-979.js index bae15db8..7ed5801d 100644 --- a/test/compress/issue-979.js +++ b/test/compress/issue-979.js @@ -82,7 +82,7 @@ issue979_test_negated_is_best: { 1!=a||2!=b||foo(); } function f7() { - return 1!=a&&2!=b?bar():void foo(); + if(1!=a&&2!=b)return bar();foo() } } } diff --git a/test/compress/loops.js b/test/compress/loops.js index 78f618aa..ca05461c 100644 --- a/test/compress/loops.js +++ b/test/compress/loops.js @@ -187,3 +187,32 @@ keep_collapse_const_in_own_block_scope_2: { console.log(c); } } + +evaluate: { + options = { + loops: true, + dead_code: true, + evaluate: true, + }; + input: { + while (true) { + a(); + } + while (false) { + b(); + } + do { + c(); + } while (true); + do { + d(); + } while (false); + } + expect: { + for(;;) + a(); + for(;;) + c(); + d(); + } +} diff --git a/test/compress/max_line_len.js b/test/compress/max_line_len.js new file mode 100644 index 00000000..b9e09178 --- /dev/null +++ b/test/compress/max_line_len.js @@ -0,0 +1,28 @@ +too_short: { + beautify = { + max_line_len: 10, + } + input: { + function f(a) { + return { c: 42, d: a(), e: "foo"}; + } + } + expect_exact: 'function f(a){\nreturn{\nc:42,\nd:a(),\ne:"foo"}}' + expect_warnings: [ + "WARN: Output exceeds 10 characters" + ] +} + +just_enough: { + beautify = { + max_line_len: 14, + } + input: { + function f(a) { + return { c: 42, d: a(), e: "foo"}; + } + } + expect_exact: 'function f(a){\nreturn{c:42,\nd:a(),e:"foo"}\n}' + expect_warnings: [ + ] +} diff --git a/test/compress/negate-iife.js b/test/compress/negate-iife.js index 0c111604..001795c5 100644 --- a/test/compress/negate-iife.js +++ b/test/compress/negate-iife.js @@ -10,6 +10,16 @@ negate_iife_1: { } } +negate_iife_1_off: { + options = { + negate_iife: false, + }; + input: { + (function(){ stuff() })(); + } + expect_exact: '(function(){stuff()})();' +} + negate_iife_2: { options = { negate_iife: true @@ -25,6 +35,7 @@ negate_iife_2: { negate_iife_3: { options = { negate_iife: true, + conditionals: true }; input: { (function(){ return true })() ? console.log(true) : console.log(false); @@ -34,9 +45,23 @@ negate_iife_3: { } } -negate_iife_3: { +negate_iife_3_off: { + options = { + negate_iife: false, + conditionals: true, + }; + input: { + (function(){ return true })() ? console.log(true) : console.log(false); + } + expect: { + !function(){ return true }() ? console.log(false) : console.log(true); + } +} + +negate_iife_4: { options = { negate_iife: true, + conditionals: true, sequences: true }; input: { @@ -52,7 +77,42 @@ negate_iife_3: { } } -negate_iife_4: { +sequence_off: { + options = { + negate_iife: false, + conditionals: true, + sequences: true, + passes: 2, + }; + input: { + function f() { + (function(){ return true })() ? console.log(true) : console.log(false); + (function(){ + console.log("something"); + })(); + } + function g() { + (function(){ + console.log("something"); + })(); + (function(){ return true })() ? console.log(true) : console.log(false); + } + } + expect: { + function f() { + !function(){ return true }() ? console.log(false) : console.log(true), function(){ + console.log("something"); + }(); + } + function g() { + (function(){ + console.log("something"); + })(), function(){ return true }() ? console.log(true) : console.log(false); + } + } +} + +negate_iife_5: { options = { negate_iife: true, sequences: true, @@ -75,6 +135,29 @@ negate_iife_4: { } } +negate_iife_5_off: { + options = { + negate_iife: false, + sequences: true, + conditionals: true, + }; + input: { + if ((function(){ return true })()) { + foo(true); + } else { + bar(false); + } + (function(){ + console.log("something"); + })(); + } + expect: { + !function(){ return true }() ? bar(false) : foo(true), function(){ + console.log("something"); + }(); + } +} + negate_iife_nested: { options = { negate_iife: true, @@ -107,6 +190,38 @@ negate_iife_nested: { } } +negate_iife_nested_off: { + options = { + negate_iife: false, + sequences: true, + conditionals: true, + }; + input: { + function Foo(f) { + this.f = f; + } + new Foo(function() { + (function(x) { + (function(y) { + console.log(y); + })(x); + })(7); + }).f(); + } + expect: { + function Foo(f) { + this.f = f; + } + new Foo(function() { + (function(x) { + (function(y) { + console.log(y); + })(x); + })(7); + }).f(); + } +} + negate_iife_issue_1073: { options = { negate_iife: true, @@ -172,3 +287,36 @@ issue_1254_negate_iife_nested: { } expect_exact: '!function(){return function(){console.log("test")}}()()()()();' } + +issue_1288: { + options = { + negate_iife: true, + conditionals: true, + }; + input: { + if (w) ; + else { + (function f() {})(); + } + if (!x) { + (function() { + x = {}; + })(); + } + if (y) + (function() {})(); + else + (function(z) { + return z; + })(0); + } + expect: { + w || function f() {}(); + x || function() { + x = {}; + }(); + y ? function() {}() : function(z) { + return z; + }(0); + } +} diff --git a/test/compress/properties.js b/test/compress/properties.js index 7ad54ebe..29bdfe2a 100644 --- a/test/compress/properties.js +++ b/test/compress/properties.js @@ -539,3 +539,19 @@ first_256_hex_chars_as_properties: { }; } } + +native_prototype: { + options = { + unsafe_proto: true, + } + input: { + Array.prototype.splice.apply(a, [1, 2, b, c]); + Object.prototype.hasOwnProperty.call(d, "foo"); + String.prototype.indexOf.call(e, "bar"); + } + expect: { + [].splice.apply(a, [1, 2, b, c]); + ({}).hasOwnProperty.call(d, "foo"); + "".indexOf.call(e, "bar"); + } +} diff --git a/test/compress/pure_funcs.js b/test/compress/pure_funcs.js new file mode 100644 index 00000000..3cc529a8 --- /dev/null +++ b/test/compress/pure_funcs.js @@ -0,0 +1,295 @@ +array: { + options = { + pure_funcs: [ "Math.floor" ], + side_effects: true, + } + input: { + var a; + function f(b) { + Math.floor(a / b); + Math.floor(c / b); + } + } + expect: { + var a; + function f(b) { + c; + } + } +} + +func: { + options = { + pure_funcs: function(node) { + return !~node.args[0].print_to_string().indexOf("a"); + }, + side_effects: true, + } + input: { + function f(a, b) { + Math.floor(a / b); + Math.floor(c / b); + } + } + expect: { + function f(a, b) { + Math.floor(c / b); + } + } +} + +side_effects: { + options = { + pure_funcs: [ "console.log" ], + side_effects: true, + } + input: { + function f(a, b) { + console.log(a()); + console.log(b); + } + } + expect: { + function f(a, b) { + a(); + } + } +} + +unused: { + options = { + pure_funcs: [ "pure" ], + side_effects: true, + unused: true, + } + input: { + function foo() { + var u = pure(1); + var x = pure(2); + var y = pure(x); + var z = pure(pure(side_effects())); + return pure(3); + } + } + expect: { + function foo() { + side_effects(); + return pure(3); + } + } +} + +babel: { + options = { + pure_funcs: [ "_classCallCheck" ], + side_effects: true, + unused: true, + } + input: { + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) + throw new TypeError("Cannot call a class as a function"); + } + var Foo = function Foo() { + _classCallCheck(this, Foo); + }; + } + expect: { + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) + throw new TypeError("Cannot call a class as a function"); + } + var Foo = function() { + }; + } +} + +conditional: { + options = { + pure_funcs: [ "pure" ], + side_effects: true, + } + input: { + pure(1 | a() ? 2 & b() : 7 ^ c()); + pure(1 | a() ? 2 & b() : 5); + pure(1 | a() ? 4 : 7 ^ c()); + pure(1 | a() ? 4 : 5); + pure(3 ? 2 & b() : 7 ^ c()); + pure(3 ? 2 & b() : 5); + pure(3 ? 4 : 7 ^ c()); + pure(3 ? 4 : 5); + } + expect: { + 1 | a() ? b() : c(); + 1 | a() && b(); + 1 | a() || c(); + a(); + 3 ? b() : c(); + 3 && b(); + 3 || c(); + } +} + +relational: { + options = { + pure_funcs: [ "foo" ], + side_effects :true, + } + input: { + foo() in foo(); + foo() instanceof bar(); + foo() < "bar"; + bar() > foo(); + bar() != bar(); + bar() !== "bar"; + "bar" == foo(); + "bar" === bar(); + "bar" >= "bar"; + } + expect: { + bar(); + bar(); + bar(), bar(); + bar(); + bar(); + } +} + +arithmetic: { + options = { + pure_funcs: [ "foo" ], + side_effects :true, + } + input: { + foo() + foo(); + foo() - bar(); + foo() * "bar"; + bar() / foo(); + bar() & bar(); + bar() | "bar"; + "bar" >> foo(); + "bar" << bar(); + "bar" >>> "bar"; + } + expect: { + bar(); + bar(); + bar(), bar(); + bar(); + bar(); + } +} + +boolean_and: { + options = { + pure_funcs: [ "foo" ], + side_effects :true, + } + input: { + foo() && foo(); + foo() && bar(); + foo() && "bar"; + bar() && foo(); + bar() && bar(); + bar() && "bar"; + "bar" && foo(); + "bar" && bar(); + "bar" && "bar"; + } + expect: { + foo() && bar(); + bar(); + bar() && bar(); + bar(); + "bar" && bar(); + } +} + +boolean_or: { + options = { + pure_funcs: [ "foo" ], + side_effects :true, + } + input: { + foo() || foo(); + foo() || bar(); + foo() || "bar"; + bar() || foo(); + bar() || bar(); + bar() || "bar"; + "bar" || foo(); + "bar" || bar(); + "bar" || "bar"; + } + expect: { + foo() || bar(); + bar(); + bar() || bar(); + bar(); + "bar" || bar(); + } +} + +assign: { + options = { + pure_funcs: [ "foo" ], + side_effects :true, + } + input: { + var a; + function f(b) { + a = foo(); + b *= 4 + foo(); + c >>= 0 | foo(); + } + } + expect: { + var a; + function f(b) { + a = foo(); + b *= 4 + foo(); + c >>= 0 | foo(); + } + } +} + +unary: { + options = { + pure_funcs: [ "foo" ], + side_effects :true, + } + input: { + typeof foo(); + typeof bar(); + typeof "bar"; + void foo(); + void bar(); + void "bar"; + delete a[foo()]; + delete a[bar()]; + delete a["bar"]; + a[foo()]++; + a[bar()]++; + a["bar"]++; + --a[foo()]; + --a[bar()]; + --a["bar"]; + ~foo(); + ~bar(); + ~"bar"; + } + expect: { + bar(); + bar(); + delete a[foo()]; + delete a[bar()]; + delete a["bar"]; + a[foo()]++; + a[bar()]++; + a["bar"]++; + --a[foo()]; + --a[bar()]; + --a["bar"]; + bar(); + } +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 2301a92a..d9d02efa 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -108,8 +108,6 @@ modified: { } console.log(a + b); console.log(b + c); - // TODO: as "modified" is determined in "figure_out_scope", - // even "passes" wouldn't improve this any further console.log(a + c); console.log(a + b + c); } @@ -350,3 +348,125 @@ unsafe_evaluate_equality: { } } } + +passes: { + options = { + conditionals: true, + evaluate: true, + passes: 2, + reduce_vars: true, + unused: true, + } + input: { + function f() { + var a = 1, b = 2, c = 3; + if (a) { + b = c; + } else { + c = b; + } + console.log(a + b); + console.log(b + c); + console.log(a + c); + console.log(a + b + c); + } + } + expect: { + function f() { + var b = 2, c = 3; + b = c; + console.log(1 + b); + console.log(b + 3); + console.log(4); + console.log(1 + b + 3); + } + } +} + +iife: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + !function(a, b, c) { + b++; + console.log(a - 1, b * 1, c + 2); + }(1, 2, 3); + } + expect: { + !function(a, b, c) { + b++; + console.log(0, 1 * b, 5); + }(1, 2, 3); + } +} + +iife_new: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + var A = new function(a, b, c) { + b++; + console.log(a - 1, b * 1, c + 2); + }(1, 2, 3); + } + expect: { + var A = new function(a, b, c) { + b++; + console.log(0, 1 * b, 5); + }(1, 2, 3); + } +} + +multi_def: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + function f(a) { + if (a) + var b = 1; + else + var b = 2 + console.log(b + 1); + } + } + expect: { + function f(a) { + if (a) + var b = 1; + else + var b = 2 + console.log(b + 1); + } + } +} + +multi_def_2: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + if (code == 16) + var bitsLength = 2, bitsOffset = 3, what = len; + else if (code == 17) + var bitsLength = 3, bitsOffset = 3, what = (len = 0); + else if (code == 18) + var bitsLength = 7, bitsOffset = 11, what = (len = 0); + var repeatLength = this.getBits(bitsLength) + bitsOffset; + } + expect: { + if (16 == code) + var bitsLength = 2, bitsOffset = 3, what = len; + else if (17 == code) + var bitsLength = 3, bitsOffset = 3, what = (len = 0); + else if (18 == code) + var bitsLength = 7, bitsOffset = 11, what = (len = 0); + var repeatLength = this.getBits(bitsLength) + bitsOffset; + } +} diff --git a/test/compress/sequences.js b/test/compress/sequences.js index 0e3319ab..d93f5237 100644 --- a/test/compress/sequences.js +++ b/test/compress/sequences.js @@ -169,3 +169,85 @@ for_sequences: { for (y = 5; false;); } } + +limit_1: { + options = { + sequences: 3, + }; + input: { + a; + b; + c; + d; + e; + f; + g; + h; + i; + j; + k; + } + expect: { + a, b, c; + d, e, f; + g, h, i; + j, k; + } +} + +limit_2: { + options = { + sequences: 3, + }; + input: { + a, b; + c, d; + e, f; + g, h; + i, j; + k; + } + expect: { + a, b, c, d; + e, f, g, h; + i, j, k; + } +} + +negate_iife_for: { + options = { + sequences: true, + negate_iife: true, + }; + input: { + (function() {})(); + for (i = 0; i < 5; i++) console.log(i); + + (function() {})(); + for (; i < 5; i++) console.log(i); + } + expect: { + for (!function() {}(), i = 0; i < 5; i++) console.log(i); + for (function() {}(); i < 5; i++) console.log(i); + } +} + +iife: { + options = { + sequences: true, + }; + input: { + x = 42; + (function a() {})(); + !function b() {}(); + ~function c() {}(); + +function d() {}(); + -function e() {}(); + void function f() {}(); + typeof function g() {}(); + } + expect: { + x = 42, function a() {}(), function b() {}(), function c() {}(), + function d() {}(), function e() {}(), function f() {}(), function g() {}() + } +} diff --git a/test/input/global_defs/nested.js b/test/input/global_defs/nested.js new file mode 100644 index 00000000..dbf57909 --- /dev/null +++ b/test/input/global_defs/nested.js @@ -0,0 +1 @@ +console.log(C.V, C.D); diff --git a/test/input/global_defs/simple.js b/test/input/global_defs/simple.js new file mode 100644 index 00000000..44d515e3 --- /dev/null +++ b/test/input/global_defs/simple.js @@ -0,0 +1 @@ +console.log(D); diff --git a/test/input/issue-1482/bracketize.js b/test/input/issue-1482/bracketize.js new file mode 100644 index 00000000..2c2b103c --- /dev/null +++ b/test/input/issue-1482/bracketize.js @@ -0,0 +1,73 @@ +if (x) { + foo(); +} + +if (x) { + foo(); +} else { + baz(); +} + +if (x) { + foo(); +} else if (y) { + bar(); +} else { + baz(); +} + +if (x) { + if (y) { + foo(); + } else { + bar(); + } +} else { + baz(); +} + +if (x) { + foo(); +} else if (y) { + bar(); +} else if (z) { + baz(); +} else { + moo(); +} + +function f() { + if (x) { + foo(); + } + if (x) { + foo(); + } else { + baz(); + } + if (x) { + foo(); + } else if (y) { + bar(); + } else { + baz(); + } + if (x) { + if (y) { + foo(); + } else { + bar(); + } + } else { + baz(); + } + if (x) { + foo(); + } else if (y) { + bar(); + } else if (z) { + baz(); + } else { + moo(); + } +} diff --git a/test/input/issue-1482/default.js b/test/input/issue-1482/default.js new file mode 100644 index 00000000..14054e98 --- /dev/null +++ b/test/input/issue-1482/default.js @@ -0,0 +1,17 @@ +if (x) foo(); + +if (x) foo(); else baz(); + +if (x) foo(); else if (y) bar(); else baz(); + +if (x) if (y) foo(); else bar(); else baz(); + +if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); + +function f() { + if (x) foo(); + if (x) foo(); else baz(); + if (x) foo(); else if (y) bar(); else baz(); + if (x) if (y) foo(); else bar(); else baz(); + if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); +} diff --git a/test/input/issue-1482/input.js b/test/input/issue-1482/input.js new file mode 100644 index 00000000..0186e82c --- /dev/null +++ b/test/input/issue-1482/input.js @@ -0,0 +1,12 @@ +if (x) foo(); +if (x) foo(); else baz(); +if (x) foo(); else if (y) bar(); else baz(); +if (x) if (y) foo(); else bar(); else baz(); +if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); +function f() { +if (x) foo(); +if (x) foo(); else baz(); +if (x) foo(); else if (y) bar(); else baz(); +if (x) if (y) foo(); else bar(); else baz(); +if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); +} diff --git a/test/jetstream.js b/test/jetstream.js new file mode 100644 index 00000000..a8195389 --- /dev/null +++ b/test/jetstream.js @@ -0,0 +1,87 @@ +#! /usr/bin/env node +// -*- js -*- + +"use strict"; + +var site = "http://browserbench.org/JetStream/"; +if (typeof phantom == "undefined") { + // workaround for tty output truncation upon process.exit() + [process.stdout, process.stderr].forEach(function(stream){ + if (stream._handle && stream._handle.setBlocking) + stream._handle.setBlocking(true); + }); + var args = process.argv.slice(2); + if (!args.length) { + args.push("-mc", "warnings=false"); + } + args.push("--stats"); + var child_process = require("child_process"); + try { + require("phantomjs-prebuilt"); + } catch(e) { + child_process.execSync("npm install phantomjs-prebuilt@2.1.14"); + } + var http = require("http"); + var server = http.createServer(function(request, response) { + request.resume(); + var url = decodeURIComponent(request.url.slice(1)); + var stderr = ""; + var uglifyjs = child_process.fork("bin/uglifyjs", args, { + silent: true + }).on("exit", function(code) { + console.log("uglifyjs", url.indexOf(site) == 0 ? url.slice(site.length) : url, args.join(" ")); + console.log(stderr); + if (code) throw new Error("uglifyjs failed with code " + code); + }); + uglifyjs.stderr.on("data", function(data) { + stderr += data; + }).setEncoding("utf8"); + uglifyjs.stdout.pipe(response); + http.get(url, function(res) { + res.pipe(uglifyjs.stdin); + }); + }).listen().on("listening", function() { + var phantomjs = require("phantomjs-prebuilt"); + var program = phantomjs.exec(process.argv[1], server.address().port); + program.stdout.pipe(process.stdout); + program.stderr.pipe(process.stderr); + program.on("exit", function(code) { + server.close(); + if (code) throw new Error("JetStream failed!"); + console.log("JetStream completed successfully."); + }); + }); + server.timeout = 0; +} else { + var page = require("webpage").create(); + page.onError = function(msg, trace) { + var body = [ msg ]; + if (trace) trace.forEach(function(t) { + body.push(" " + (t.function || "Anonymous function") + " (" + t.file + ":" + t.line + ")"); + }); + console.error(body.join("\n")); + phantom.exit(1); + }; + var url = "http://localhost:" + require("system").args[1] + "/"; + page.onResourceRequested = function(requestData, networkRequest) { + if (/\.js$/.test(requestData.url)) + networkRequest.changeUrl(url + encodeURIComponent(requestData.url)); + } + page.onConsoleMessage = function(msg) { + if (/Error:/i.test(msg)) { + console.error(msg); + phantom.exit(1); + } + console.log(msg); + if (~msg.indexOf("Raw results:")) { + phantom.exit(); + } + }; + page.open(site, function(status) { + if (status != "success") phantomjs.exit(1); + page.evaluate(function() { + JetStream.switchToQuick(); + JetStream.start(); + }); + }); +} diff --git a/test/mocha/accessorTokens-1492.js b/test/mocha/accessorTokens-1492.js new file mode 100644 index 00000000..861414ee --- /dev/null +++ b/test/mocha/accessorTokens-1492.js @@ -0,0 +1,32 @@ +var UglifyJS = require('../../'); +var assert = require("assert"); + +describe("Accessor tokens", function() { + it("Should fill the token information for accessors (issue #1492)", function() { + // location 0 1 2 3 4 + // 01234567890123456789012345678901234567890123456789 + var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }"); + + // test all AST_ObjectProperty tokens are set as expected + var checkedAST_ObjectProperty = false; + var checkWalker = new UglifyJS.TreeWalker(function(node, descend) { + if (node instanceof UglifyJS.AST_ObjectProperty) { + checkedAST_ObjectProperty = true; + + assert.equal(node.start.pos, 12); + assert.equal(node.end.endpos, 46); + + assert(node.key instanceof UglifyJS.AST_SymbolRef); + assert.equal(node.key.start.pos, 16); + assert.equal(node.key.end.endpos, 22); + + assert(node.value instanceof UglifyJS.AST_Accessor); + assert.equal(node.value.start.pos, 22); + assert.equal(node.value.end.endpos, 46); + + } + }); + ast.walk(checkWalker); + assert(checkedAST_ObjectProperty, "AST_ObjectProperty not found"); + }); +});
\ No newline at end of file diff --git a/test/mocha/cli.js b/test/mocha/cli.js index a8de05c5..450df1fd 100644 --- a/test/mocha/cli.js +++ b/test/mocha/cli.js @@ -1,10 +1,11 @@ var assert = require("assert"); var exec = require("child_process").exec; +var readFileSync = require("fs").readFileSync; describe("bin/uglifyjs", function () { var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs'; it("should produce a functional build when using --self", function (done) { - this.timeout(5000); + this.timeout(15000); var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS'; @@ -100,4 +101,54 @@ describe("bin/uglifyjs", function () { done(); }); }); + it("Should work with --define (simple)", function (done) { + var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c'; + + exec(command, function (err, stdout) { + if (err) throw err; + + assert.strictEqual(stdout, "console.log(5);\n"); + done(); + }); + }); + it("Should work with --define (nested)", function (done) { + var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c'; + + exec(command, function (err, stdout) { + if (err) throw err; + + assert.strictEqual(stdout, "console.log(3,5);\n"); + done(); + }); + }); + it("Should work with --define (AST_Node)", function (done) { + var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c'; + + exec(command, function (err, stdout) { + if (err) throw err; + + assert.strictEqual(stdout, "stdout.println(D);\n"); + done(); + }); + }); + it("Should work with `--beautify`", function (done) { + var command = uglifyjscmd + ' test/input/issue-1482/input.js -b'; + + exec(command, function (err, stdout) { + if (err) throw err; + + assert.strictEqual(stdout, readFileSync("test/input/issue-1482/default.js", "utf8")); + done(); + }); + }); + it("Should work with `--beautify bracketize`", function (done) { + var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize'; + + exec(command, function (err, stdout) { + if (err) throw err; + + assert.strictEqual(stdout, readFileSync("test/input/issue-1482/bracketize.js", "utf8")); + done(); + }); + }); }); diff --git a/test/mocha/minify.js b/test/mocha/minify.js index 70cf73ae..8fe1565f 100644 --- a/test/mocha/minify.js +++ b/test/mocha/minify.js @@ -95,4 +95,19 @@ describe("minify", function() { assert.strictEqual(code, "var a=function(n){return n};"); }); }); + + describe("#__PURE__", function() { + it("should drop #__PURE__ hint after use", function() { + var result = Uglify.minify('//@__PURE__ comment1 #__PURE__ comment2\n foo(), bar();', { + fromString: true, + output: { + comments: "all", + beautify: false, + } + }); + var code = result.code; + assert.strictEqual(code, "// comment1 comment2\nbar();"); + }); + }); + }); diff --git a/test/mocha/operator.js b/test/mocha/operator.js new file mode 100644 index 00000000..adef3abd --- /dev/null +++ b/test/mocha/operator.js @@ -0,0 +1,489 @@ +var UglifyJS = require("../../"); +var assert = require("assert"); + +describe("operator", function() { + it("Should handle mixing of ++/+/--/- correctly", function() { + function evaluate(exp) { + return new Function("var a=1,b=2,c=" + exp + ";return{a:a,b:b,c:c}")(); + } + + [ "", "+", "-" ].forEach(function(p) { + [ "++a", "--a", "a", "a--", "a++" ].forEach(function(a) { + [ "+", "-" ].forEach(function(o) { + [ "", "+", "-" ].forEach(function(q) { + [ "++b", "--b", "b", "b--", "b++" ].forEach(function(b) { + var exp = [p, a, o, q, b].join(" "); + var orig = evaluate(exp); + var uglify = evaluate(UglifyJS.parse(exp).print_to_string()); + assert.strictEqual(orig.a, uglify.a); + assert.strictEqual(orig.b, uglify.b); + assert.strictEqual(orig.c, uglify.c); + var beautify = evaluate(UglifyJS.parse(exp).print_to_string({ + beautify: true + })); + assert.strictEqual(orig.a, beautify.a); + assert.strictEqual(orig.b, beautify.b); + assert.strictEqual(orig.c, beautify.c); + }); + }); + }); + }); + }); + }); + it("Should remove extraneous spaces", function() { + [ + [ "++a + ++b", "++a+ ++b" ], + [ "++a + --b", "++a+--b" ], + [ "++a + b", "++a+b" ], + [ "++a + b--", "++a+b--" ], + [ "++a + b++", "++a+b++" ], + [ "++a + + ++b", "++a+ + ++b" ], + [ "++a + + --b", "++a+ +--b" ], + [ "++a + + b", "++a+ +b" ], + [ "++a + + b--", "++a+ +b--" ], + [ "++a + + b++", "++a+ +b++" ], + [ "++a + - ++b", "++a+-++b" ], + [ "++a + - --b", "++a+- --b" ], + [ "++a + - b", "++a+-b" ], + [ "++a + - b--", "++a+-b--" ], + [ "++a + - b++", "++a+-b++" ], + [ "++a - ++b", "++a-++b" ], + [ "++a - --b", "++a- --b" ], + [ "++a - b", "++a-b" ], + [ "++a - b--", "++a-b--" ], + [ "++a - b++", "++a-b++" ], + [ "++a - + ++b", "++a-+ ++b" ], + [ "++a - + --b", "++a-+--b" ], + [ "++a - + b", "++a-+b" ], + [ "++a - + b--", "++a-+b--" ], + [ "++a - + b++", "++a-+b++" ], + [ "++a - - ++b", "++a- -++b" ], + [ "++a - - --b", "++a- - --b" ], + [ "++a - - b", "++a- -b" ], + [ "++a - - b--", "++a- -b--" ], + [ "++a - - b++", "++a- -b++" ], + [ "--a + ++b", "--a+ ++b" ], + [ "--a + --b", "--a+--b" ], + [ "--a + b", "--a+b" ], + [ "--a + b--", "--a+b--" ], + [ "--a + b++", "--a+b++" ], + [ "--a + + ++b", "--a+ + ++b" ], + [ "--a + + --b", "--a+ +--b" ], + [ "--a + + b", "--a+ +b" ], + [ "--a + + b--", "--a+ +b--" ], + [ "--a + + b++", "--a+ +b++" ], + [ "--a + - ++b", "--a+-++b" ], + [ "--a + - --b", "--a+- --b" ], + [ "--a + - b", "--a+-b" ], + [ "--a + - b--", "--a+-b--" ], + [ "--a + - b++", "--a+-b++" ], + [ "--a - ++b", "--a-++b" ], + [ "--a - --b", "--a- --b" ], + [ "--a - b", "--a-b" ], + [ "--a - b--", "--a-b--" ], + [ "--a - b++", "--a-b++" ], + [ "--a - + ++b", "--a-+ ++b" ], + [ "--a - + --b", "--a-+--b" ], + [ "--a - + b", "--a-+b" ], + [ "--a - + b--", "--a-+b--" ], + [ "--a - + b++", "--a-+b++" ], + [ "--a - - ++b", "--a- -++b" ], + [ "--a - - --b", "--a- - --b" ], + [ "--a - - b", "--a- -b" ], + [ "--a - - b--", "--a- -b--" ], + [ "--a - - b++", "--a- -b++" ], + [ "a + ++b", "a+ ++b" ], + [ "a + --b", "a+--b" ], + [ "a + b", "a+b" ], + [ "a + b--", "a+b--" ], + [ "a + b++", "a+b++" ], + [ "a + + ++b", "a+ + ++b" ], + [ "a + + --b", "a+ +--b" ], + [ "a + + b", "a+ +b" ], + [ "a + + b--", "a+ +b--" ], + [ "a + + b++", "a+ +b++" ], + [ "a + - ++b", "a+-++b" ], + [ "a + - --b", "a+- --b" ], + [ "a + - b", "a+-b" ], + [ "a + - b--", "a+-b--" ], + [ "a + - b++", "a+-b++" ], + [ "a - ++b", "a-++b" ], + [ "a - --b", "a- --b" ], + [ "a - b", "a-b" ], + [ "a - b--", "a-b--" ], + [ "a - b++", "a-b++" ], + [ "a - + ++b", "a-+ ++b" ], + [ "a - + --b", "a-+--b" ], + [ "a - + b", "a-+b" ], + [ "a - + b--", "a-+b--" ], + [ "a - + b++", "a-+b++" ], + [ "a - - ++b", "a- -++b" ], + [ "a - - --b", "a- - --b" ], + [ "a - - b", "a- -b" ], + [ "a - - b--", "a- -b--" ], + [ "a - - b++", "a- -b++" ], + [ "a-- + ++b", "a--+ ++b" ], + [ "a-- + --b", "a--+--b" ], + [ "a-- + b", "a--+b" ], + [ "a-- + b--", "a--+b--" ], + [ "a-- + b++", "a--+b++" ], + [ "a-- + + ++b", "a--+ + ++b" ], + [ "a-- + + --b", "a--+ +--b" ], + [ "a-- + + b", "a--+ +b" ], + [ "a-- + + b--", "a--+ +b--" ], + [ "a-- + + b++", "a--+ +b++" ], + [ "a-- + - ++b", "a--+-++b" ], + [ "a-- + - --b", "a--+- --b" ], + [ "a-- + - b", "a--+-b" ], + [ "a-- + - b--", "a--+-b--" ], + [ "a-- + - b++", "a--+-b++" ], + [ "a-- - ++b", "a---++b" ], + [ "a-- - --b", "a--- --b" ], + [ "a-- - b", "a---b" ], + [ "a-- - b--", "a---b--" ], + [ "a-- - b++", "a---b++" ], + [ "a-- - + ++b", "a---+ ++b" ], + [ "a-- - + --b", "a---+--b" ], + [ "a-- - + b", "a---+b" ], + [ "a-- - + b--", "a---+b--" ], + [ "a-- - + b++", "a---+b++" ], + [ "a-- - - ++b", "a--- -++b" ], + [ "a-- - - --b", "a--- - --b" ], + [ "a-- - - b", "a--- -b" ], + [ "a-- - - b--", "a--- -b--" ], + [ "a-- - - b++", "a--- -b++" ], + [ "a++ + ++b", "a+++ ++b" ], + [ "a++ + --b", "a+++--b" ], + [ "a++ + b", "a+++b" ], + [ "a++ + b--", "a+++b--" ], + [ "a++ + b++", "a+++b++" ], + [ "a++ + + ++b", "a+++ + ++b" ], + [ "a++ + + --b", "a+++ +--b" ], + [ "a++ + + b", "a+++ +b" ], + [ "a++ + + b--", "a+++ +b--" ], + [ "a++ + + b++", "a+++ +b++" ], + [ "a++ + - ++b", "a+++-++b" ], + [ "a++ + - --b", "a+++- --b" ], + [ "a++ + - b", "a+++-b" ], + [ "a++ + - b--", "a+++-b--" ], + [ "a++ + - b++", "a+++-b++" ], + [ "a++ - ++b", "a++-++b" ], + [ "a++ - --b", "a++- --b" ], + [ "a++ - b", "a++-b" ], + [ "a++ - b--", "a++-b--" ], + [ "a++ - b++", "a++-b++" ], + [ "a++ - + ++b", "a++-+ ++b" ], + [ "a++ - + --b", "a++-+--b" ], + [ "a++ - + b", "a++-+b" ], + [ "a++ - + b--", "a++-+b--" ], + [ "a++ - + b++", "a++-+b++" ], + [ "a++ - - ++b", "a++- -++b" ], + [ "a++ - - --b", "a++- - --b" ], + [ "a++ - - b", "a++- -b" ], + [ "a++ - - b--", "a++- -b--" ], + [ "a++ - - b++", "a++- -b++" ], + [ "+ ++a + ++b", "+ ++a+ ++b" ], + [ "+ ++a + --b", "+ ++a+--b" ], + [ "+ ++a + b", "+ ++a+b" ], + [ "+ ++a + b--", "+ ++a+b--" ], + [ "+ ++a + b++", "+ ++a+b++" ], + [ "+ ++a + + ++b", "+ ++a+ + ++b" ], + [ "+ ++a + + --b", "+ ++a+ +--b" ], + [ "+ ++a + + b", "+ ++a+ +b" ], + [ "+ ++a + + b--", "+ ++a+ +b--" ], + [ "+ ++a + + b++", "+ ++a+ +b++" ], + [ "+ ++a + - ++b", "+ ++a+-++b" ], + [ "+ ++a + - --b", "+ ++a+- --b" ], + [ "+ ++a + - b", "+ ++a+-b" ], + [ "+ ++a + - b--", "+ ++a+-b--" ], + [ "+ ++a + - b++", "+ ++a+-b++" ], + [ "+ ++a - ++b", "+ ++a-++b" ], + [ "+ ++a - --b", "+ ++a- --b" ], + [ "+ ++a - b", "+ ++a-b" ], + [ "+ ++a - b--", "+ ++a-b--" ], + [ "+ ++a - b++", "+ ++a-b++" ], + [ "+ ++a - + ++b", "+ ++a-+ ++b" ], + [ "+ ++a - + --b", "+ ++a-+--b" ], + [ "+ ++a - + b", "+ ++a-+b" ], + [ "+ ++a - + b--", "+ ++a-+b--" ], + [ "+ ++a - + b++", "+ ++a-+b++" ], + [ "+ ++a - - ++b", "+ ++a- -++b" ], + [ "+ ++a - - --b", "+ ++a- - --b" ], + [ "+ ++a - - b", "+ ++a- -b" ], + [ "+ ++a - - b--", "+ ++a- -b--" ], + [ "+ ++a - - b++", "+ ++a- -b++" ], + [ "+ --a + ++b", "+--a+ ++b" ], + [ "+ --a + --b", "+--a+--b" ], + [ "+ --a + b", "+--a+b" ], + [ "+ --a + b--", "+--a+b--" ], + [ "+ --a + b++", "+--a+b++" ], + [ "+ --a + + ++b", "+--a+ + ++b" ], + [ "+ --a + + --b", "+--a+ +--b" ], + [ "+ --a + + b", "+--a+ +b" ], + [ "+ --a + + b--", "+--a+ +b--" ], + [ "+ --a + + b++", "+--a+ +b++" ], + [ "+ --a + - ++b", "+--a+-++b" ], + [ "+ --a + - --b", "+--a+- --b" ], + [ "+ --a + - b", "+--a+-b" ], + [ "+ --a + - b--", "+--a+-b--" ], + [ "+ --a + - b++", "+--a+-b++" ], + [ "+ --a - ++b", "+--a-++b" ], + [ "+ --a - --b", "+--a- --b" ], + [ "+ --a - b", "+--a-b" ], + [ "+ --a - b--", "+--a-b--" ], + [ "+ --a - b++", "+--a-b++" ], + [ "+ --a - + ++b", "+--a-+ ++b" ], + [ "+ --a - + --b", "+--a-+--b" ], + [ "+ --a - + b", "+--a-+b" ], + [ "+ --a - + b--", "+--a-+b--" ], + [ "+ --a - + b++", "+--a-+b++" ], + [ "+ --a - - ++b", "+--a- -++b" ], + [ "+ --a - - --b", "+--a- - --b" ], + [ "+ --a - - b", "+--a- -b" ], + [ "+ --a - - b--", "+--a- -b--" ], + [ "+ --a - - b++", "+--a- -b++" ], + [ "+ a + ++b", "+a+ ++b" ], + [ "+ a + --b", "+a+--b" ], + [ "+ a + b", "+a+b" ], + [ "+ a + b--", "+a+b--" ], + [ "+ a + b++", "+a+b++" ], + [ "+ a + + ++b", "+a+ + ++b" ], + [ "+ a + + --b", "+a+ +--b" ], + [ "+ a + + b", "+a+ +b" ], + [ "+ a + + b--", "+a+ +b--" ], + [ "+ a + + b++", "+a+ +b++" ], + [ "+ a + - ++b", "+a+-++b" ], + [ "+ a + - --b", "+a+- --b" ], + [ "+ a + - b", "+a+-b" ], + [ "+ a + - b--", "+a+-b--" ], + [ "+ a + - b++", "+a+-b++" ], + [ "+ a - ++b", "+a-++b" ], + [ "+ a - --b", "+a- --b" ], + [ "+ a - b", "+a-b" ], + [ "+ a - b--", "+a-b--" ], + [ "+ a - b++", "+a-b++" ], + [ "+ a - + ++b", "+a-+ ++b" ], + [ "+ a - + --b", "+a-+--b" ], + [ "+ a - + b", "+a-+b" ], + [ "+ a - + b--", "+a-+b--" ], + [ "+ a - + b++", "+a-+b++" ], + [ "+ a - - ++b", "+a- -++b" ], + [ "+ a - - --b", "+a- - --b" ], + [ "+ a - - b", "+a- -b" ], + [ "+ a - - b--", "+a- -b--" ], + [ "+ a - - b++", "+a- -b++" ], + [ "+ a-- + ++b", "+a--+ ++b" ], + [ "+ a-- + --b", "+a--+--b" ], + [ "+ a-- + b", "+a--+b" ], + [ "+ a-- + b--", "+a--+b--" ], + [ "+ a-- + b++", "+a--+b++" ], + [ "+ a-- + + ++b", "+a--+ + ++b" ], + [ "+ a-- + + --b", "+a--+ +--b" ], + [ "+ a-- + + b", "+a--+ +b" ], + [ "+ a-- + + b--", "+a--+ +b--" ], + [ "+ a-- + + b++", "+a--+ +b++" ], + [ "+ a-- + - ++b", "+a--+-++b" ], + [ "+ a-- + - --b", "+a--+- --b" ], + [ "+ a-- + - b", "+a--+-b" ], + [ "+ a-- + - b--", "+a--+-b--" ], + [ "+ a-- + - b++", "+a--+-b++" ], + [ "+ a-- - ++b", "+a---++b" ], + [ "+ a-- - --b", "+a--- --b" ], + [ "+ a-- - b", "+a---b" ], + [ "+ a-- - b--", "+a---b--" ], + [ "+ a-- - b++", "+a---b++" ], + [ "+ a-- - + ++b", "+a---+ ++b" ], + [ "+ a-- - + --b", "+a---+--b" ], + [ "+ a-- - + b", "+a---+b" ], + [ "+ a-- - + b--", "+a---+b--" ], + [ "+ a-- - + b++", "+a---+b++" ], + [ "+ a-- - - ++b", "+a--- -++b" ], + [ "+ a-- - - --b", "+a--- - --b" ], + [ "+ a-- - - b", "+a--- -b" ], + [ "+ a-- - - b--", "+a--- -b--" ], + [ "+ a-- - - b++", "+a--- -b++" ], + [ "+ a++ + ++b", "+a+++ ++b" ], + [ "+ a++ + --b", "+a+++--b" ], + [ "+ a++ + b", "+a+++b" ], + [ "+ a++ + b--", "+a+++b--" ], + [ "+ a++ + b++", "+a+++b++" ], + [ "+ a++ + + ++b", "+a+++ + ++b" ], + [ "+ a++ + + --b", "+a+++ +--b" ], + [ "+ a++ + + b", "+a+++ +b" ], + [ "+ a++ + + b--", "+a+++ +b--" ], + [ "+ a++ + + b++", "+a+++ +b++" ], + [ "+ a++ + - ++b", "+a+++-++b" ], + [ "+ a++ + - --b", "+a+++- --b" ], + [ "+ a++ + - b", "+a+++-b" ], + [ "+ a++ + - b--", "+a+++-b--" ], + [ "+ a++ + - b++", "+a+++-b++" ], + [ "+ a++ - ++b", "+a++-++b" ], + [ "+ a++ - --b", "+a++- --b" ], + [ "+ a++ - b", "+a++-b" ], + [ "+ a++ - b--", "+a++-b--" ], + [ "+ a++ - b++", "+a++-b++" ], + [ "+ a++ - + ++b", "+a++-+ ++b" ], + [ "+ a++ - + --b", "+a++-+--b" ], + [ "+ a++ - + b", "+a++-+b" ], + [ "+ a++ - + b--", "+a++-+b--" ], + [ "+ a++ - + b++", "+a++-+b++" ], + [ "+ a++ - - ++b", "+a++- -++b" ], + [ "+ a++ - - --b", "+a++- - --b" ], + [ "+ a++ - - b", "+a++- -b" ], + [ "+ a++ - - b--", "+a++- -b--" ], + [ "+ a++ - - b++", "+a++- -b++" ], + [ "- ++a + ++b", "-++a+ ++b" ], + [ "- ++a + --b", "-++a+--b" ], + [ "- ++a + b", "-++a+b" ], + [ "- ++a + b--", "-++a+b--" ], + [ "- ++a + b++", "-++a+b++" ], + [ "- ++a + + ++b", "-++a+ + ++b" ], + [ "- ++a + + --b", "-++a+ +--b" ], + [ "- ++a + + b", "-++a+ +b" ], + [ "- ++a + + b--", "-++a+ +b--" ], + [ "- ++a + + b++", "-++a+ +b++" ], + [ "- ++a + - ++b", "-++a+-++b" ], + [ "- ++a + - --b", "-++a+- --b" ], + [ "- ++a + - b", "-++a+-b" ], + [ "- ++a + - b--", "-++a+-b--" ], + [ "- ++a + - b++", "-++a+-b++" ], + [ "- ++a - ++b", "-++a-++b" ], + [ "- ++a - --b", "-++a- --b" ], + [ "- ++a - b", "-++a-b" ], + [ "- ++a - b--", "-++a-b--" ], + [ "- ++a - b++", "-++a-b++" ], + [ "- ++a - + ++b", "-++a-+ ++b" ], + [ "- ++a - + --b", "-++a-+--b" ], + [ "- ++a - + b", "-++a-+b" ], + [ "- ++a - + b--", "-++a-+b--" ], + [ "- ++a - + b++", "-++a-+b++" ], + [ "- ++a - - ++b", "-++a- -++b" ], + [ "- ++a - - --b", "-++a- - --b" ], + [ "- ++a - - b", "-++a- -b" ], + [ "- ++a - - b--", "-++a- -b--" ], + [ "- ++a - - b++", "-++a- -b++" ], + [ "- --a + ++b", "- --a+ ++b" ], + [ "- --a + --b", "- --a+--b" ], + [ "- --a + b", "- --a+b" ], + [ "- --a + b--", "- --a+b--" ], + [ "- --a + b++", "- --a+b++" ], + [ "- --a + + ++b", "- --a+ + ++b" ], + [ "- --a + + --b", "- --a+ +--b" ], + [ "- --a + + b", "- --a+ +b" ], + [ "- --a + + b--", "- --a+ +b--" ], + [ "- --a + + b++", "- --a+ +b++" ], + [ "- --a + - ++b", "- --a+-++b" ], + [ "- --a + - --b", "- --a+- --b" ], + [ "- --a + - b", "- --a+-b" ], + [ "- --a + - b--", "- --a+-b--" ], + [ "- --a + - b++", "- --a+-b++" ], + [ "- --a - ++b", "- --a-++b" ], + [ "- --a - --b", "- --a- --b" ], + [ "- --a - b", "- --a-b" ], + [ "- --a - b--", "- --a-b--" ], + [ "- --a - b++", "- --a-b++" ], + [ "- --a - + ++b", "- --a-+ ++b" ], + [ "- --a - + --b", "- --a-+--b" ], + [ "- --a - + b", "- --a-+b" ], + [ "- --a - + b--", "- --a-+b--" ], + [ "- --a - + b++", "- --a-+b++" ], + [ "- --a - - ++b", "- --a- -++b" ], + [ "- --a - - --b", "- --a- - --b" ], + [ "- --a - - b", "- --a- -b" ], + [ "- --a - - b--", "- --a- -b--" ], + [ "- --a - - b++", "- --a- -b++" ], + [ "- a + ++b", "-a+ ++b" ], + [ "- a + --b", "-a+--b" ], + [ "- a + b", "-a+b" ], + [ "- a + b--", "-a+b--" ], + [ "- a + b++", "-a+b++" ], + [ "- a + + ++b", "-a+ + ++b" ], + [ "- a + + --b", "-a+ +--b" ], + [ "- a + + b", "-a+ +b" ], + [ "- a + + b--", "-a+ +b--" ], + [ "- a + + b++", "-a+ +b++" ], + [ "- a + - ++b", "-a+-++b" ], + [ "- a + - --b", "-a+- --b" ], + [ "- a + - b", "-a+-b" ], + [ "- a + - b--", "-a+-b--" ], + [ "- a + - b++", "-a+-b++" ], + [ "- a - ++b", "-a-++b" ], + [ "- a - --b", "-a- --b" ], + [ "- a - b", "-a-b" ], + [ "- a - b--", "-a-b--" ], + [ "- a - b++", "-a-b++" ], + [ "- a - + ++b", "-a-+ ++b" ], + [ "- a - + --b", "-a-+--b" ], + [ "- a - + b", "-a-+b" ], + [ "- a - + b--", "-a-+b--" ], + [ "- a - + b++", "-a-+b++" ], + [ "- a - - ++b", "-a- -++b" ], + [ "- a - - --b", "-a- - --b" ], + [ "- a - - b", "-a- -b" ], + [ "- a - - b--", "-a- -b--" ], + [ "- a - - b++", "-a- -b++" ], + [ "- a-- + ++b", "-a--+ ++b" ], + [ "- a-- + --b", "-a--+--b" ], + [ "- a-- + b", "-a--+b" ], + [ "- a-- + b--", "-a--+b--" ], + [ "- a-- + b++", "-a--+b++" ], + [ "- a-- + + ++b", "-a--+ + ++b" ], + [ "- a-- + + --b", "-a--+ +--b" ], + [ "- a-- + + b", "-a--+ +b" ], + [ "- a-- + + b--", "-a--+ +b--" ], + [ "- a-- + + b++", "-a--+ +b++" ], + [ "- a-- + - ++b", "-a--+-++b" ], + [ "- a-- + - --b", "-a--+- --b" ], + [ "- a-- + - b", "-a--+-b" ], + [ "- a-- + - b--", "-a--+-b--" ], + [ "- a-- + - b++", "-a--+-b++" ], + [ "- a-- - ++b", "-a---++b" ], + [ "- a-- - --b", "-a--- --b" ], + [ "- a-- - b", "-a---b" ], + [ "- a-- - b--", "-a---b--" ], + [ "- a-- - b++", "-a---b++" ], + [ "- a-- - + ++b", "-a---+ ++b" ], + [ "- a-- - + --b", "-a---+--b" ], + [ "- a-- - + b", "-a---+b" ], + [ "- a-- - + b--", "-a---+b--" ], + [ "- a-- - + b++", "-a---+b++" ], + [ "- a-- - - ++b", "-a--- -++b" ], + [ "- a-- - - --b", "-a--- - --b" ], + [ "- a-- - - b", "-a--- -b" ], + [ "- a-- - - b--", "-a--- -b--" ], + [ "- a-- - - b++", "-a--- -b++" ], + [ "- a++ + ++b", "-a+++ ++b" ], + [ "- a++ + --b", "-a+++--b" ], + [ "- a++ + b", "-a+++b" ], + [ "- a++ + b--", "-a+++b--" ], + [ "- a++ + b++", "-a+++b++" ], + [ "- a++ + + ++b", "-a+++ + ++b" ], + [ "- a++ + + --b", "-a+++ +--b" ], + [ "- a++ + + b", "-a+++ +b" ], + [ "- a++ + + b--", "-a+++ +b--" ], + [ "- a++ + + b++", "-a+++ +b++" ], + [ "- a++ + - ++b", "-a+++-++b" ], + [ "- a++ + - --b", "-a+++- --b" ], + [ "- a++ + - b", "-a+++-b" ], + [ "- a++ + - b--", "-a+++-b--" ], + [ "- a++ + - b++", "-a+++-b++" ], + [ "- a++ - ++b", "-a++-++b" ], + [ "- a++ - --b", "-a++- --b" ], + [ "- a++ - b", "-a++-b" ], + [ "- a++ - b--", "-a++-b--" ], + [ "- a++ - b++", "-a++-b++" ], + [ "- a++ - + ++b", "-a++-+ ++b" ], + [ "- a++ - + --b", "-a++-+--b" ], + [ "- a++ - + b", "-a++-+b" ], + [ "- a++ - + b--", "-a++-+b--" ], + [ "- a++ - + b++", "-a++-+b++" ], + [ "- a++ - - ++b", "-a++- -++b" ], + [ "- a++ - - --b", "-a++- - --b" ], + [ "- a++ - - b", "-a++- -b" ], + [ "- a++ - - b--", "-a++- -b--" ], + [ "- a++ - - b++", "-a++- -b++" ], + ].forEach(function(exp) { + assert.strictEqual(UglifyJS.parse(exp[0]).print_to_string(), exp[1] + ";"); + }); + }); +}); diff --git a/test/run-tests.js b/test/run-tests.js index a4721399..15a12c6b 100755 --- a/test/run-tests.js +++ b/test/run-tests.js @@ -194,6 +194,9 @@ function parse_test(file) { if (node instanceof U.AST_LabeledStatement && tw.parent() instanceof U.AST_Toplevel) { var name = node.label.name; + if (name in tests) { + throw new Error('Duplicated test name "' + name + '" in ' + file); + } tests[name] = get_one_test(name, node.body); return true; } |