Compare commits

...

36 Commits

Author SHA1 Message Date
Alex Lam S.L
b2b8a0d386 v2.8.13 2017-03-17 02:01:33 +08:00
Alex Lam S.L
ac40301813 fix chained evaluation (#1610)
`reduce_vars` enables substitution of variables but did not clone the value's `AST_Node`.

This confuses `collapse_vars` and result in invalid AST and subsequent crash.

fixes #1609
2017-03-17 00:26:48 +08:00
Alex Lam S.L
3563d8c09e extend test/run-tests.js to optionally execute uglified output (#1604)
fixes #1588
2017-03-16 23:20:06 +08:00
Alex Lam S.L
5ae04b3545 make collapse_vars consistent with toplevel (#1608)
fixes #1605
2017-03-16 13:22:26 +08:00
Alex Lam S.L
a80b228d8b fix hoist_vars on reduce_vars (#1607)
`hoist_vars` converts variable declarations into plain assignments, which then confuses `reduce_vars`

fixes #1606
2017-03-16 12:03:30 +08:00
Alex Lam S.L
cf4bf4ceb1 fix stack issues with AST_Node.evaluate() (#1603)
As patched in #1597, `make_node_from_constant()` makes inconsistent and sometimes incorrect calls to `optimize()` and `transform()`.

Fix those issues properly by changing the semantics of `evaluate()` and `make_node_from_constant()`, with the side effect that `evaluate()` no longer eagerly converts constant to `AST_Node`.
2017-03-16 01:02:59 +08:00
Alex Lam S.L
8223b2e0db fix AST_Node.optimize() (#1602)
Liberal use of `Compressor.transform()` and `AST_Node.optimize()` presents an issue for look-up operations like `TreeWalker.in_boolean_context()` and `TreeWalker.parent()`.

This is an incremental fix such that `AST_Node.optimize()` would now contain the correct stack information when called correctly.
2017-03-15 18:44:13 +08:00
Alex Lam S.L
381bd3836e minor clean-ups (#1600)
- remove obsolete optimisation in `AST_Binary` after #1477
- improve `TreeWalker.has_directive()` readability and resilience against multiple visits
2017-03-14 13:19:05 +08:00
Alex Lam S.L
919d5e3482 v2.8.12 2017-03-11 05:00:55 +08:00
Alex Lam S.L
e3a3db73ae temporary fix for boolean bug (#1597)
fixes #1592
2017-03-11 04:59:55 +08:00
Alex Lam S.L
d9344f30b8 disallow parameter substitution for named IIFEs (#1596)
Self-referenced function has non-fixed values assigned to its parameters.

Let `unused` & `!keep_fnames` do the scanning, then apply `reduce_vars` only to unnamed functions.

fixes #1595
2017-03-11 03:34:55 +08:00
Alex Lam S.L
be80f7e706 support multi-line string in tests (#1590)
`expect_exact` sometimes have multiple lines and `\n` are hard to read.

Use array of strings to emulate line breaks and improve readability.
2017-03-10 11:27:30 +08:00
Alex Lam S.L
cf45e2f79b fixup for #1585 (#1589)
As patched on `harmony`, `statement()` is the only user of `embed_tokens()` with a missing error branch.

Updated test case and match up with `harmony` to facilitate future merging.
2017-03-10 10:49:41 +08:00
Alex Lam S.L
8354758f30 v2.8.11 2017-03-10 04:17:21 +08:00
Alex Lam S.L
9e6b128374 fix catch variable reference in IE8 (#1587)
`AST_Scope.def_variable()` will overwrite `AST_Symbol.thedef`, so save a copy before calling.

fixes #1586
2017-03-10 03:15:21 +08:00
Michael Mior
93cdb194f4 Correctly raise a parse exception with a missing loop body (#1585) 2017-03-10 03:08:43 +08:00
Alex Lam S.L
b633706ce4 fix & improve function argument compression (#1584)
- one-use function call => IIFE should take `eval()` & `arguments` into account
- if unused parameter cannot be eliminated, replace it with `0`

fixes #1583
2017-03-09 19:11:05 +08:00
Alex Lam S.L
e9920f7ca1 v2.8.10 2017-03-09 05:48:06 +08:00
Alex Lam S.L
7e465d4a01 scan RHS of dropped assignments (#1581)
- similar case as #1578 but against #1450 instead
- fix `this` binding in #1450 as well

closes #1580
2017-03-09 05:22:27 +08:00
Alex Lam S.L
aa80ee349d remove checkboxes from Issues template 2017-03-08 19:19:54 +08:00
Alex Lam S.L
80e81765cf explain how to make a proper bug report (#1579)
fixes #1574
2017-03-08 18:56:01 +08:00
Alex Lam S.L
711f88dcb4 scan assignment value in drop_unused() (#1578)
those were not optimised for `unused` before, which made it necessary for `reduce_vars` to have separate steps for `keep_fnames`

docs update by @kzc

closes #1577
2017-03-08 18:37:32 +08:00
Alex Lam S.L
344d11d591 v2.8.9 2017-03-08 12:41:22 +08:00
Alex Lam S.L
c7cdcf06a6 fix function name eliminiation (#1576)
Function expression can be assigned to a variable and be given a name. Ensure function name is the reduced variable before clearing it out.

fixes #1573
fixes #1575
2017-03-08 12:39:57 +08:00
Alex Lam S.L
3ee55748d4 only run benchmark & jetstream on CI (#1571) 2017-03-08 06:00:51 +08:00
Alex Lam S.L
dedbeeff15 plan B for IE8 do-while semi-colon fix (#1572)
- omitting trailing semi-colon in do-while breaks non-browser parser, e.g. uglify-js 1.x
- trailing semi-colon only breaks IE8 if followed by `else` or `while`
- always use braces in do-while body to workaround 2nd case with no size loss in compression

fixes #1568
2017-03-08 05:07:05 +08:00
Alex Lam S.L
bd6dee52ab fix return from recursive IIFE (#1570)
`side-effects` did not account for IIFEs being able to reference itself thus making its return value potentially significant
2017-03-08 03:31:51 +08:00
Alex Lam S.L
144052ca49 v2.8.8 2017-03-07 19:58:41 +08:00
Alex Lam S.L
65c848cc6f include benchmark.js in test suite (#1564)
- report file sizes and overall run time
- exit with non-zero code upon error
2017-03-07 19:25:12 +08:00
Alex Lam S.L
8a8a94a596 fix deep cloning of labels (#1565)
`AST_Label.references` get `.initialize()` to `[]` every time after `.clone()`

So walk down the tree to pick up the cloned `AST_LoopControl` pieces and put it back together.
2017-03-07 18:38:27 +08:00
Alex Lam S.L
8153b7bd8a transform function calls to IIFEs (#1560)
- expose function body to call sites for potential optimisations
- suppress substitution of variable used within `AST_Defun`
2017-03-07 15:37:52 +08:00
Alex Lam S.L
d787d70127 avoid substitution of global variables (#1557)
- unless `toplevel` is enabled
- global `const` works as before
2017-03-07 03:11:03 +08:00
kzc
3ac2421932 collapse_vars: do not replace a constant in loop condition or init (#1562) 2017-03-07 01:42:33 +08:00
Alex Lam S.L
a9fc9ddc33 suppress semicolons after do/while (#1556)
- unless both `beautify` & `screw-ie8` are enabled
- deprecate workaround for if-do-while-else

fixes #186
2017-03-06 17:31:35 +08:00
Alex Lam S.L
a5d62a3fc6 v2.8.7 2017-03-05 17:17:08 +08:00
Alex Lam S.L
067e5a5762 fixup for #1553 (#1555)
- `++a` is the one that is foldable
- transform `a++` into `++a` for better optimisation
2017-03-05 17:15:37 +08:00
30 changed files with 2062 additions and 392 deletions

7
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,7 @@
- Bug report or feature request?
- `uglify-js` version (`uglifyjs -V`)
- JavaScript input - ideally as small as possible.
- The `uglifyjs` CLI command executed or `minify()` options used.
- An example of JavaScript output produced and/or the error or warning.
Note: the release version of `uglify-js` only supports ES5. Those wishing to minify ES6 should use the experimental [`harmony`](https://github.com/mishoo/UglifyJS2#harmony) branch.

View File

@@ -1,10 +1,13 @@
language: node_js
before_install: "npm install -g npm"
node_js:
- "0.12"
- "0.10"
- "0.12"
- "4"
- "6"
- "7"
env:
- UGLIFYJS_TEST_ALL=1
matrix:
fast_finish: true
sudo: false

View File

@@ -391,11 +391,11 @@ to set `true`; it's effectively a shortcut for `foo=true`).
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
and `x = something(), x` into `x = something()`
- `collapse_vars` -- default `false`. Collapse single-use `var` and `const`
definitions when possible.
- `collapse_vars` -- Collapse single-use `var` and `const` definitions
when possible.
- `reduce_vars` -- default `false`. Improve optimization on variables assigned
with and used as constant values.
- `reduce_vars` -- Improve optimization on variables assigned with and
used as constant values.
- `warnings` -- display warnings when dropping unreachable code or unused
declarations etc.

View File

@@ -91,9 +91,20 @@ var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos
}, null);
var AST_Node = DEFNODE("Node", "start end", {
clone: function() {
_clone: function(deep) {
if (deep) {
var self = this.clone();
return self.transform(new TreeTransformer(function(node) {
if (node !== self) {
return node.clone(true);
}
}));
}
return new this.CTOR(this);
},
clone: function(deep) {
return this._clone(deep);
},
$documentation: "Base class of all AST nodes",
$propdoc: {
start: "[AST_Token] The first token of this node",
@@ -199,6 +210,20 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
this.label._walk(visitor);
this.body._walk(visitor);
});
},
clone: function(deep) {
var node = this._clone(deep);
if (deep) {
var refs = node.label.references;
var label = this.label;
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl
&& node.label && node.label.thedef === label) {
refs.push(node);
}
}));
}
return node;
}
}, AST_StatementWithBody);
@@ -959,8 +984,8 @@ TreeWalker.prototype = {
push: function (node) {
if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive) {
this.directives[node.value] = this.directives[node.value] ? "up" : true;
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
this.directives[node.value] = node;
}
this.stack.push(node);
},
@@ -988,7 +1013,7 @@ TreeWalker.prototype = {
for (var i = 0; i < node.body.length; ++i) {
var st = node.body[i];
if (!(st instanceof AST_Directive)) break;
if (st.value == type) return true;
if (st.value == type) return st;
}
}
},

File diff suppressed because it is too large Load Diff

View File

@@ -777,7 +777,7 @@ function OutputStream(options) {
DEFPRINT(AST_Do, function(self, output){
output.print("do");
output.space();
self._do_print_body(output);
make_block(self.body, output);
output.space();
output.print("while");
output.space();
@@ -904,10 +904,10 @@ function OutputStream(options) {
/* -----[ if ]----- */
function make_then(self, output) {
if (output.option("bracketize")) {
make_block(self.body, output);
return;
}
var b = self.body;
if (output.option("bracketize")
|| !output.option("screw_ie8") && b instanceof AST_Do)
return make_block(b, output);
// The squeezer replaces "block"-s that contain only a single
// statement with the statement itself; technically, the AST
// is correct, but this can create problems when we output an
@@ -915,18 +915,7 @@ function OutputStream(options) {
// IF *without* an ELSE block (then the outer ELSE would refer
// to the inner IF). This function checks for this case and
// adds the block brackets if needed.
if (!self.body)
return output.force_semicolon();
if (self.body instanceof AST_Do) {
// Unconditionally use the if/do-while workaround for all browsers.
// https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
// croaks with "syntax error" on code like this: if (foo)
// do ... while(cond); else ... we need block brackets
// around do/while
make_block(self.body, output);
return;
}
var b = self.body;
if (!b) return output.force_semicolon();
while (true) {
if (b instanceof AST_If) {
if (!b.alternative) {
@@ -1335,15 +1324,7 @@ function OutputStream(options) {
function force_statement(stat, output) {
if (output.option("bracketize")) {
if (!stat || stat instanceof AST_EmptyStatement)
output.print("{}");
else if (stat instanceof AST_BlockStatement)
stat.print(output);
else output.with_block(function(){
output.indent();
stat.print(output);
output.newline();
});
make_block(stat, output);
} else {
if (!stat || stat instanceof AST_EmptyStatement)
output.force_semicolon();
@@ -1392,11 +1373,11 @@ function OutputStream(options) {
};
function make_block(stmt, output) {
if (stmt instanceof AST_BlockStatement) {
if (!stmt || stmt instanceof AST_EmptyStatement)
output.print("{}");
else if (stmt instanceof AST_BlockStatement)
stmt.print(output);
return;
}
output.with_block(function(){
else output.with_block(function(){
output.indent();
stmt.print(output);
output.newline();

View File

@@ -928,11 +928,9 @@ function parse($TEXT, options) {
expression : parenthesised(),
body : statement()
});
default:
unexpected();
}
}
unexpected();
});
function labeled_statement() {

View File

@@ -212,9 +212,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
self.walk(new TreeWalker(function(node, descend) {
if (node instanceof AST_SymbolCatch) {
var name = node.name;
var refs = node.thedef.references;
var scope = node.thedef.scope.parent_scope;
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
node.thedef.references.forEach(function(ref) {
refs.forEach(function(ref) {
ref.thedef = def;
ref.reference(options);
});

View File

@@ -126,9 +126,11 @@ function merge(obj, ext) {
return count;
};
function noop() {};
function noop() {}
function return_false() { return false; }
function return_true() { return true; }
function return_this() { return this; }
function return_null() { return null; }
var MAP = (function(){
function MAP(a, f, backwards) {

View File

@@ -4,7 +4,7 @@
"homepage": "http://lisperator.net/uglifyjs",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "2.8.6",
"version": "2.8.13",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -24,26 +24,57 @@ var results = {};
var remaining = 2 * urls.length;
function done() {
if (!--remaining) {
var failures = [];
urls.forEach(function(url) {
var info = results[url];
console.log();
console.log(url);
console.log(results[url].time);
console.log("SHA1:", results[url].sha1);
console.log(info.log);
var elapsed = 0;
info.log.replace(/: ([0-9]+\.[0-9]{3})s/g, function(match, time) {
elapsed += parseFloat(time);
});
console.log("Run-time:", elapsed.toFixed(3), "s");
console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes");
console.log("SHA1 sum:", info.sha1);
if (info.code) {
failures.push(url);
}
});
if (failures.length) {
console.error("Benchmark failed:");
failures.forEach(function(url) {
console.error(url);
});
process.exit(1);
}
}
}
urls.forEach(function(url) {
results[url] = { time: "" };
results[url] = {
input: 0,
output: 0,
log: ""
};
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) {
res.on("data", function(data) {
results[url].input += data.length;
}).pipe(uglifyjs.stdin);
uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length;
}).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)
results[url].log += data;
});
uglifyjs.on("exit", function(code) {
results[url].code = code;
done();
});
});
});

View File

@@ -344,9 +344,9 @@ collapse_vars_do_while: {
}
input: {
function f1(y) {
// The constant do-while condition `c` will be replaced.
// The constant do-while condition `c` will not be replaced.
var c = 9;
do { } while (c === 77);
do {} while (c === 77);
}
function f2(y) {
// The non-constant do-while condition `c` will not be replaced.
@@ -381,7 +381,8 @@ collapse_vars_do_while: {
}
expect: {
function f1(y) {
do ; while (false);
var c = 9;
do ; while (77 === c);
}
function f2(y) {
var c = 5 - y;
@@ -418,9 +419,9 @@ collapse_vars_do_while_drop_assign: {
}
input: {
function f1(y) {
// The constant do-while condition `c` will be replaced.
// The constant do-while condition `c` will be not replaced.
var c = 9;
do { } while (c === 77);
do {} while (c === 77);
}
function f2(y) {
// The non-constant do-while condition `c` will not be replaced.
@@ -455,7 +456,8 @@ collapse_vars_do_while_drop_assign: {
}
expect: {
function f1(y) {
do ; while (false);
var c = 9;
do ; while (77 === c);
}
function f2(y) {
var c = 5 - y;
@@ -1150,7 +1152,8 @@ collapse_vars_arguments: {
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
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
toplevel:true
}
input: {
var outer = function() {
@@ -1309,8 +1312,8 @@ collapse_vars_regexp: {
};
}
(function(){
var result, rx = /ab*/g;
while (result = rx.exec('acdabcdeabbb'))
var result, s = "acdabcdeabbb", rx = /ab*/g;
while (result = rx.exec(s))
console.log(result[0]);
})();
}
@@ -1329,3 +1332,79 @@ issue_1537: {
for (k in {prop: 'val'});
}
}
issue_1562: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var v = 1, B = 2;
for (v in objs) f(B);
var x = 3, C = 10;
while(x + 2) bar(C);
var y = 4, D = 20;
do bar(D); while(y + 2);
var z = 5, E = 30;
for (; f(z + 2) ;) bar(E);
}
expect: {
var v = 1;
for (v in objs) f(2);
var x = 3;
while(x + 2) bar(10);
var y = 4;
do bar(20); while(y + 2);
var z = 5;
for (; f(z + 2) ;) bar(30);
}
}
issue_1605_1: {
options = {
collapse_vars: true,
toplevel: false,
}
input: {
function foo(x) {
var y = x;
return y;
}
var o = new Object;
o.p = 1;
}
expect: {
function foo(x) {
return x;
}
var o = new Object;
o.p = 1;
}
}
issue_1605_2: {
options = {
collapse_vars: true,
toplevel: "vars",
}
input: {
function foo(x) {
var y = x;
return y;
}
var o = new Object;
o.p = 1;
}
expect: {
function foo(x) {
return x;
}
(new Object).p = 1;
}
}

View File

@@ -123,6 +123,7 @@ dead_code_const_annotation: {
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused;
@@ -172,6 +173,7 @@ dead_code_const_annotation_complex_scope: {
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused_var;

View File

@@ -700,3 +700,94 @@ issue_1539: {
}
}
}
vardef_value: {
options = {
keep_fnames: false,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g(){
return x();
}
var a = g();
return a(42);
}
}
expect: {
function f() {
var a = function(){
return x();
}();
return a(42);
}
}
}
assign_binding: {
options = {
cascade: true,
side_effects: true,
unused: true,
}
input: {
function f() {
var a;
a = f.g, a();
}
}
expect: {
function f() {
(0, f.g)();
}
}
}
assign_chain: {
options = {
unused: true,
}
input: {
function f() {
var a, b;
x = a = y = b = 42;
}
}
expect: {
function f() {
x = y = 42;
}
}
}
issue_1583: {
options = {
keep_fargs: true,
reduce_vars: true,
unused: true,
}
input: {
function m(t) {
(function(e) {
t = e();
})(function() {
return (function(a) {
return a;
})(function(a) {});
});
}
}
expect: {
function m(t) {
(function(e) {
t = (function() {
return (function(a) {
return a;
})(function(a) {});
})();
})();
}
}
}

View File

@@ -0,0 +1,19 @@
inner_reference: {
options = {
side_effects: true,
}
input: {
!function f(a) {
return a && f(a - 1) + a;
}(42);
!function g(a) {
return a;
}(42);
}
expect: {
!function f(a) {
return a && f(a - 1) + a;
}(42);
!void 0;
}
}

View File

@@ -0,0 +1,87 @@
screw_ie8: {
options = {
screw_ie8: true,
}
mangle = {
screw_ie8: true,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }
}
expect_exact: 'try{throw"foo"}catch(o){console.log(o)}'
expect_stdout: [
"foo"
]
}
support_ie8: {
options = {
screw_ie8: false,
}
mangle = {
screw_ie8: false,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }
}
expect_exact: 'try{throw"foo"}catch(x){console.log(x)}'
expect_stdout: "foo"
}
safe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: false,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}(1)());
}
expect: {
var a, c;
console.log(function(n) {
return function() {
return a ? b : c ? d : void 0;
};
}(1)());
}
expect_stdout: true
}
unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: true,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}()());
}
expect: {
var a, c;
console.log(function(n) {
return function() {
return a ? b : c ? d : n;
};
}()());
}
expect_stdout: true
}

View File

@@ -0,0 +1,56 @@
chained_evaluation_1: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = 1;
(function() {
var b = a, c;
c = f(b);
c.bar = b;
})();
})();
}
expect: {
(function() {
(function() {
var c;
c = f(1);
c.bar = 1;
})();
})();
}
}
chained_evaluation_2: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = "long piece of string";
(function() {
var b = a, c;
c = f(b);
c.bar = b;
})();
})();
}
expect: {
(function() {
var a = "long piece of string";
(function() {
var c;
c = f(a);
c.bar = a;
})();
})();
}
}

View File

@@ -21,6 +21,16 @@ collapse: {
var a;
a = b(a / 2);
if (a < 0) {
a++;
++c;
return c / 2;
}
}
function f4(c) {
var a;
a = b(a / 2);
if (a < 0) {
a++;
c++;
return c / 2;
}
@@ -35,7 +45,11 @@ collapse: {
}
function f3(c) {
var a;
if ((a = b(a / 2)) < 0) return c++ / 2;
if ((a = b(a / 2)) < 0) return a++, ++c / 2;
}
function f4(c) {
var a;
if ((a = b(a / 2)) < 0) return a++, ++c / 2;
}
}
}

View File

@@ -50,6 +50,7 @@ this_binding_conditionals: {
this_binding_collapse_vars: {
options = {
collapse_vars: true,
toplevel: true,
};
input: {
var c = a; c();

View File

@@ -240,3 +240,201 @@ issue_1532: {
}
}
}
issue_186: {
beautify = {
beautify: false,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo())do{do{alert(x)}while(--x)}while(x);else bar();'
}
issue_186_ie8: {
beautify = {
beautify: false,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else bar();'
}
issue_186_beautify: {
beautify = {
beautify: true,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) do {',
' do {',
' alert(x);',
' } while (--x);',
'} while (x); else bar();',
]
}
issue_186_beautify_ie8: {
beautify = {
beautify: true,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else bar();',
]
}
issue_186_bracketize: {
beautify = {
beautify: false,
bracketize: true,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_bracketize_ie8: {
beautify = {
beautify: false,
bracketize: true,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_beautify_bracketize: {
beautify = {
beautify: true,
bracketize: true,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else {',
' bar();',
'}',
]
}
issue_186_beautify_bracketize_ie8: {
beautify = {
beautify: true,
bracketize: true,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else {',
' bar();',
'}',
]
}

View File

@@ -7,7 +7,13 @@ too_short: {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{\nc:42,\nd:a(),\ne:"foo"}}'
expect_exact: [
'function f(a){',
'return{',
'c:42,',
'd:a(),',
'e:"foo"}}',
]
expect_warnings: [
"WARN: Output exceeds 10 characters"
]
@@ -22,7 +28,12 @@ just_enough: {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{c:42,\nd:a(),e:"foo"}\n}'
expect_exact: [
'function f(a){',
'return{c:42,',
'd:a(),e:"foo"}',
'}',
]
expect_warnings: [
]
}

View File

@@ -6,6 +6,7 @@ reduce_vars: {
C : 0
},
reduce_vars : true,
toplevel : true,
unused : true
}
input: {
@@ -452,22 +453,26 @@ multi_def_2: {
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;
function f(){
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;
function f(){
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;
}
}
}
@@ -477,12 +482,16 @@ use_before_var: {
reduce_vars: true,
}
input: {
console.log(t);
var t = 1;
function f(){
console.log(t);
var t = 1;
}
}
expect: {
console.log(t);
var t = 1;
function f(){
console.log(t);
var t = 1;
}
}
}
@@ -492,22 +501,20 @@ inner_var_if: {
reduce_vars: true,
}
input: {
function f(){
return 0;
function f(a){
if (a)
var t = 1;
if (!t)
console.log(t);
}
if (f())
var t = 1;
if (!t)
console.log(t);
}
expect: {
function f(){
return 0;
function f(a){
if (a)
var t = 1;
if (!t)
console.log(t);
}
if (f())
var t = 1;
if (!t)
console.log(t);
}
}
@@ -517,24 +524,22 @@ inner_var_label: {
reduce_vars: true,
}
input: {
function f(){
return 1;
function f(a){
l: {
if (a) break l;
var t = 1;
}
console.log(t);
}
l: {
if (f()) break l;
var t = 1;
}
console.log(t);
}
expect: {
function f(){
return 1;
function f(a){
l: {
if (a) break l;
var t = 1;
}
console.log(t);
}
l: {
if (f()) break l;
var t = 1;
}
console.log(t);
}
}
@@ -544,22 +549,26 @@ inner_var_for: {
reduce_vars: true,
}
input: {
var a = 1;
x(a, b, d);
for (var b = 2, c = 3; x(a, b, c, d); x(a, b, c, d)) {
var d = 4, e = 5;
function f() {
var a = 1;
x(a, b, d);
for (var b = 2, c = 3; x(a, b, c, d); x(a, b, c, d)) {
var d = 4, e = 5;
x(a, b, c, d, e);
}
x(a, b, c, d, e);
}
x(a, b, c, d, e)
}
expect: {
var a = 1;
x(1, b, d);
for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) {
var d = 4, e = 5;
function f() {
var a = 1;
x(1, b, d);
for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) {
var d = 4, e = 5;
x(1, b, 3, d, e);
}
x(1, b, 3, d, e);
}
x(1, b, 3, d, e);
}
}
@@ -569,24 +578,28 @@ inner_var_for_in_1: {
reduce_vars: true,
}
input: {
var a = 1, b = 2;
for (b in (function() {
return x(a, b, c);
})()) {
var c = 3, d = 4;
function f() {
var a = 1, b = 2;
for (b in (function() {
return x(a, b, c);
})()) {
var c = 3, d = 4;
x(a, b, c, d);
}
x(a, b, c, d);
}
x(a, b, c, d);
}
expect: {
var a = 1, b = 2;
for (b in (function() {
return x(1, b, c);
})()) {
var c = 3, d = 4;
function f() {
var a = 1, b = 2;
for (b in (function() {
return x(1, b, c);
})()) {
var c = 3, d = 4;
x(1, b, c, d);
}
x(1, b, c, d);
}
x(1, b, c, d);
}
}
@@ -596,12 +609,16 @@ inner_var_for_in_2: {
reduce_vars: true,
}
input: {
for (var long_name in {})
console.log(long_name);
function f() {
for (var long_name in {})
console.log(long_name);
}
}
expect: {
for (var long_name in {})
console.log(long_name);
function f() {
for (var long_name in {})
console.log(long_name);
}
}
}
@@ -611,20 +628,24 @@ inner_var_catch: {
reduce_vars: true,
}
input: {
try {
a();
} catch (e) {
var b = 1;
function f() {
try {
a();
} catch (e) {
var b = 1;
}
console.log(b);
}
console.log(b);
}
expect: {
try {
a();
} catch (e) {
var b = 1;
function f() {
try {
a();
} catch (e) {
var b = 1;
}
console.log(b);
}
console.log(b);
}
}
@@ -634,14 +655,18 @@ issue_1533_1: {
reduce_vars: true,
}
input: {
var id = "";
for (id in {break: "me"})
console.log(id);
function f() {
var id = "";
for (id in {break: "me"})
console.log(id);
}
}
expect: {
var id = "";
for (id in {break: "me"})
console.log(id);
function f() {
var id = "";
for (id in {break: "me"})
console.log(id);
}
}
}
@@ -651,15 +676,678 @@ issue_1533_2: {
reduce_vars: true,
}
input: {
var id = "";
for (var id in {break: "me"})
function f() {
var id = "";
for (var id in {break: "me"})
console.log(id);
console.log(id);
console.log(id);
}
}
expect: {
var id = "";
for (var id in {break: "me"})
function f() {
var id = "";
for (var id in {break: "me"})
console.log(id);
console.log(id);
console.log(id);
}
}
}
toplevel_on: {
options = {
evaluate: true,
reduce_vars: true,
toplevel:true,
unused: true,
}
input: {
var x = 3;
console.log(x);
}
expect: {
console.log(3);
}
}
toplevel_off: {
options = {
evaluate: true,
reduce_vars: true,
toplevel:false,
unused: true,
}
input: {
var x = 3;
console.log(x);
}
expect: {
var x = 3;
console.log(x);
}
}
toplevel_on_loops_1: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel:true,
unused: true,
}
input: {
function bar() {
console.log("bar:", --x);
}
var x = 3;
do
bar();
while (x);
}
expect: {
var x = 3;
do
(function() {
console.log("bar:", --x);
})();
while (x);
}
}
toplevel_off_loops_1: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel:false,
unused: true,
}
input: {
function bar() {
console.log("bar:", --x);
}
var x = 3;
do
bar();
while (x);
}
expect: {
function bar() {
console.log("bar:", --x);
}
var x = 3;
do
bar();
while (x);
}
}
toplevel_on_loops_2: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel:true,
unused: true,
}
input: {
function bar() {
console.log("bar:");
}
var x = 3;
do
bar();
while (x);
}
expect: {
for (;;) (function() {
console.log("bar:");
})();
}
}
toplevel_off_loops_2: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel:false,
unused: true,
}
input: {
function bar() {
console.log("bar:");
}
var x = 3;
do
bar();
while (x);
}
expect: {
function bar() {
console.log("bar:");
}
var x = 3;
do
bar();
while (x);
}
}
toplevel_on_loops_3: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel:true,
unused: true,
}
input: {
var x = 3;
while (x) bar();
}
expect: {
for (;;) bar();
}
}
toplevel_off_loops_3: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel:false,
unused: true,
}
input: {
var x = 3;
while (x) bar();
}
expect: {
var x = 3;
for (;x;) bar();
}
}
defun_reference: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
function f() {
function g() {
x();
return a;
}
var a = h();
var b = 2;
return a + b;
function h() {
y();
return b;
}
}
}
expect: {
function f() {
function g() {
x();
return a;
}
var a = h();
var b = 2;
return a + b;
function h() {
y();
return b;
}
}
}
}
defun_inline_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f() {
return g(2) + h();
function g(b) {
return b;
}
function h() {
return h();
}
}
}
expect: {
function f() {
return function(b) {
return b;
}(2) + h();
function h() {
return h();
}
}
}
}
defun_inline_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g(b) {
return b;
}
function h() {
return h();
}
return g(2) + h();
}
}
expect: {
function f() {
function h() {
return h();
}
return function(b) {
return b;
}(2) + h();
}
}
}
defun_inline_3: {
options = {
evaluate: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f() {
return g(2);
function g(b) {
return b;
}
}
}
expect: {
function f() {
return 2;
}
}
}
defun_call: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f() {
return g() + h(1) - h(g(), 2, 3);
function g() {
return 4;
}
function h(a) {
return a;
}
}
}
expect: {
function f() {
return 4 + h(1) - h(4);
function h(a) {
return a;
}
}
}
}
defun_redefine: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g() {
return 1;
}
function h() {
return 2;
}
g = function() {
return 3;
};
return g() + h();
}
}
expect: {
function f() {
function g() {
return 1;
}
g = function() {
return 3;
};
return g() + 2;
}
}
}
func_inline: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f() {
var g = function() {
return 1;
};
console.log(g() + h());
var h = function() {
return 2;
};
}
}
expect: {
function f() {
console.log(1 + h());
var h = function() {
return 2;
};
}
}
}
func_modified: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
function a() { return 1; }
function b() { return 2; }
function c() { return 3; }
b.inject = [];
c = function() { return 4; };
return a() + b() + c();
}
}
expect: {
function f(a) {
function b() { return 2; }
function c() { return 3; }
b.inject = [];
c = function() { return 4; };
return 1 + 2 + c();
}
}
}
defun_label: {
options = {
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
!function() {
function f(a) {
L: {
if (a) break L;
return 1;
}
}
console.log(f(2));
}();
}
expect: {
!function() {
console.log(function(a) {
L: {
if (a) break L;
return 1;
}
}(2));
}();
}
}
double_reference: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f() {
var g = function g() {
g();
};
g();
}
}
expect: {
function f() {
(function g() {
g();
})();
}
}
}
iife_arguments_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(x) {
console.log(x() === arguments[0]);
})(function f() {
return f;
});
}
expect: {
(function(x) {
console.log(x() === arguments[0]);
})(function f() {
return f;
});
}
}
iife_arguments_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var x = function f() {
return f;
};
console.log(x() === arguments[0]);
})();
}
expect: {
(function() {
console.log(function f() {
return f;
}() === arguments[0]);
})();
}
}
iife_eval_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(x) {
console.log(x() === eval("x"));
})(function f() {
return f;
});
}
expect: {
(function(x) {
console.log(x() === eval("x"));
})(function f() {
return f;
});
}
}
iife_eval_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var x = function f() {
return f;
};
console.log(x() === eval("x"));
})();
}
expect: {
(function() {
var x = function f() {
return f;
};
console.log(x() === eval("x"));
})();
}
}
iife_func_side_effects: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(a, b, c) {
return b();
})(x(), function() {
return y();
}, z());
}
expect: {
(function(a, b, c) {
return function() {
return y();
}();
})(x(), 0, z());
}
}
issue_1595_1: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
return f(a + 1);
})(2);
}
expect: {
(function f(a) {
return f(a + 1);
})(2);
}
}
issue_1595_2: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
return g(a + 1);
})(2);
}
expect: {
(function(a) {
return g(a + 1);
})(2);
}
}
issue_1595_3: {
options = {
evaluate: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
return g(a + 1);
})(2);
}
expect: {
(function(a) {
return g(3);
})();
}
}
issue_1595_4: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function iife(a, b, c) {
console.log(a, b, c);
if (a) iife(a - 1, b, c);
})(3, 4, 5);
}
expect: {
(function iife(a, b, c) {
console.log(a, b, c);
if (a) iife(a - 1, b, c);
})(3, 4, 5);
}
}
issue_1606: {
options = {
evaluate: true,
hoist_vars: true,
reduce_vars: true,
}
input: {
function f() {
var a;
function g(){};
var b = 2;
x(b);
}
}
expect: {
function f() {
var a, b;
function g(){};
b = 2;
x(b);
}
}
}

View File

@@ -182,3 +182,39 @@ reduce_vars: {
}
}
}
issue_1586_1: {
options = {
screw_ie8: false,
}
mangle = {
screw_ie8: false,
}
input: {
function f() {
try {
} catch (err) {
console.log(err.message);
}
}
}
expect_exact: "function f(){try{}catch(c){console.log(c.message)}}"
}
issue_1586_2: {
options = {
screw_ie8: true,
}
mangle = {
screw_ie8: true,
}
input: {
function f() {
try {
} catch (err) {
console.log(err.message);
}
}
}
expect_exact: "function f(){try{}catch(c){console.log(c.message)}}"
}

129
test/compress/transform.js Normal file
View File

@@ -0,0 +1,129 @@
booleans_evaluate: {
options = {
booleans: true,
evaluate: true,
}
input: {
console.log(typeof void 0 != "undefined");
console.log(1 == 1, 1 === 1)
console.log(1 != 1, 1 !== 1)
}
expect: {
console.log(!1);
console.log(!0, !0);
console.log(!1, !1);
}
}
booleans_global_defs: {
options = {
booleans: true,
evaluate: true,
global_defs: {
A: true,
},
}
input: {
console.log(A == 1);
}
expect: {
console.log(!0);
}
}
condition_evaluate: {
options = {
booleans: true,
dead_code: false,
evaluate: true,
loops: false,
}
input: {
while (1 === 2);
for (; 1 == true;);
if (void 0 == null);
}
expect: {
while (!1);
for (; !0;);
if (!0);
}
}
if_else_empty: {
options = {
conditionals: true,
}
input: {
if ({} ? a : b); else {}
}
expect: {
!{} ? b : a;
}
}
label_if_break: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
L: if (true) {
a;
break L;
}
}
expect: {
a;
}
}
while_if_break: {
options = {
conditionals: true,
loops: true,
sequences: true,
}
input: {
while (a) {
if (b) if(c) d;
if (e) break;
}
}
expect: {
for(; a && (b && c && d, !e););
}
}
if_return: {
options = {
booleans: true,
conditionals: true,
if_return: true,
sequences: true,
}
input: {
function f(w, x, y, z) {
if (x) return;
if (w) {
if (y) return;
} else if (z) return;
if (x == y) return true;
if (x) w();
if (y) z();
return true;
}
}
expect: {
function f(w, x, y, z) {
if (!x) {
if (w) {
if (y) return;
} else if (z) return;
return x == y || (x && w(), y && z(), !0);
}
}
}
}

View File

@@ -0,0 +1 @@
for (var i = 0; i < 1; i++)

View File

@@ -82,7 +82,7 @@ describe("bin/uglifyjs", function () {
});
});
it("Should work with --keep-fnames (mangle & compress)", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c';
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
exec(command, function (err, stdout) {
if (err) throw err;
@@ -152,7 +152,7 @@ describe("bin/uglifyjs", function () {
});
});
it("Should process inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js -cm toplevel --in-source-map inline --source-map-inline';
var command = uglifyjscmd + ' test/input/issue-520/input.js -mc toplevel --in-source-map inline --source-map-inline';
exec(command, function (err, stdout) {
if (err) throw err;
@@ -238,4 +238,17 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should fail with a missing loop body", function(done) {
var command = uglifyjscmd + ' test/input/invalid/loop-no-body.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/loop-no-body.js:2,0");
assert.strictEqual(lines[1], "for (var i = 0; i < 1; i++) ");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)");
done();
});
});
});

View File

@@ -3,17 +3,13 @@ var assert = require("assert");
describe("minify() with input file globs", function() {
it("minify() with one input file glob string.", function() {
var result = Uglify.minify("test/input/issue-1242/foo.*", {
compress: { collapse_vars: true }
});
var result = Uglify.minify("test/input/issue-1242/foo.*");
assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);');
});
it("minify() with an array of one input file glob.", function() {
var result = Uglify.minify([
"test/input/issue-1242/b*.es5",
], {
compress: { collapse_vars: true }
});
]);
assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}');
});
it("minify() with an array of multiple input file globs.", function() {
@@ -21,8 +17,8 @@ describe("minify() with input file globs", function() {
"test/input/issue-1242/???.es5",
"test/input/issue-1242/*.js",
], {
compress: { collapse_vars: true }
compress: { toplevel: true }
});
assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}function foo(n){print("Foo:",2*n)}var print=console.log.bind(console);print("qux",bar(3),baz(12)),foo(11);');
assert.strictEqual(result.code, 'var print=console.log.bind(console);print("qux",function(n){return 3*n}(3),function(n){return n/2}(12)),function(n){print("Foo:",2*n)}(11);');
});
});

View File

@@ -78,6 +78,7 @@ describe("minify", function() {
});
it("Should process inline source map", function() {
var code = Uglify.minify("./test/input/issue-520/input.js", {
compress: { toplevel: true },
inSourceMap: "inline",
sourceMapInline: true
}).code + "\n";

54
test/mocha/release.js Normal file
View File

@@ -0,0 +1,54 @@
var assert = require("assert");
var spawn = require("child_process").spawn;
if (!process.env.UGLIFYJS_TEST_ALL) return;
function run(command, args, done) {
var id = setInterval(function() {
process.stdout.write("\0");
}, 5 * 60 * 1000);
spawn(command, args, {
stdio: "ignore"
}).on("exit", function(code) {
clearInterval(id);
assert.strictEqual(code, 0);
done();
});
}
describe("test/benchmark.js", function() {
this.timeout(5 * 60 * 1000);
[
"-b",
"-b bracketize",
"-m",
"-mc passes=3",
"-mc passes=3,toplevel",
"-mc passes=3,unsafe",
"-mc keep_fargs=false,passes=3",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
].forEach(function(options) {
it("Should pass with options " + options, function(done) {
var args = options.split(/ /);
args.unshift("test/benchmark.js");
run(process.argv[0], args, done);
});
});
});
describe("test/jetstream.js", function() {
this.timeout(20 * 60 * 1000);
it("Should install phantomjs-prebuilt", function(done) {
run("npm", ["install", "phantomjs-prebuilt@2.1.14"], done);
});
[
"-mc warnings=false",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto,warnings=false",
].forEach(function(options) {
it("Should pass with options " + options, function(done) {
var args = options.split(/ /);
args.unshift("test/jetstream.js");
run(process.argv[0], args, done);
});
});
});

View File

@@ -6,6 +6,7 @@ var U = require("../tools/node");
var path = require("path");
var fs = require("fs");
var assert = require("assert");
var vm = require("vm");
var tests_dir = path.dirname(module.filename);
var failures = 0;
@@ -165,6 +166,51 @@ function run_compress_tests() {
failed_files[file] = 1;
}
}
if (test.expect_stdout) {
try {
var stdout = run_code(input_code);
if (test.expect_stdout === true) {
test.expect_stdout = stdout;
}
if (test.expect_stdout != stdout) {
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED STDOUT---\n{expected}\n---ACTUAL STDOUT---\n{actual}\n\n", {
input: input_code,
expected: test.expect_stdout,
actual: stdout,
});
failures++;
failed_files[file] = 1;
} else {
try {
stdout = run_code(output);
if (test.expect_stdout != stdout) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED STDOUT---\n{expected}\n---ACTUAL STDOUT---\n{actual}\n\n", {
input: input_code,
expected: test.expect_stdout,
actual: stdout,
});
failures++;
failed_files[file] = 1;
}
} catch (ex) {
log("!!! Execution of output failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--ERROR--\n{error}\n\n", {
input: input_code,
output: output,
error: ex.toString(),
});
failures++;
failed_files[file] = 1;
}
}
} catch (ex) {
log("!!! Execution of input failed\n---INPUT---\n{input}\n--ERROR--\n{error}\n\n", {
input: input_code,
error: ex.toString(),
});
failures++;
failed_files[file] = 1;
}
}
}
}
var tests = parse_test(path.resolve(dir, file));
@@ -214,6 +260,23 @@ function parse_test(file) {
}));
}
function read_string(stat) {
if (stat.TYPE == "SimpleStatement") {
var body = stat.body;
switch(body.TYPE) {
case "String":
return body.value;
case "Array":
return body.elements.map(function(element) {
if (element.TYPE !== "String")
throw new Error("Should be array of strings");
return element.value;
}).join("\n");
}
}
throw new Error("Should be string or array of strings");
}
function get_one_test(name, block) {
var test = { name: name, options: {} };
var tw = new U.TreeWalker(function(node, descend){
@@ -226,12 +289,13 @@ function parse_test(file) {
return true;
}
if (node instanceof U.AST_LabeledStatement) {
var label = node.label;
assert.ok(
["input", "expect", "expect_exact", "expect_warnings"].indexOf(node.label.name) >= 0,
["input", "expect", "expect_exact", "expect_warnings", "expect_stdout"].indexOf(label.name) >= 0,
tmpl("Unsupported label {name} [{line},{col}]", {
name: node.label.name,
line: node.label.start.line,
col: node.label.start.col
name: label.name,
line: label.start.line,
col: label.start.col
})
);
var stat = node.body;
@@ -239,15 +303,16 @@ function parse_test(file) {
if (stat.body.length == 1) stat = stat.body[0];
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
}
if (node.label.name === "expect_exact") {
if (!(stat.TYPE === "SimpleStatement" && stat.body.TYPE === "String")) {
throw new Error(
"The value of the expect_exact clause should be a string, " +
"like `expect_exact: \"some.exact.javascript;\"`");
if (label.name == "expect_exact") {
test[label.name] = read_string(stat);
} else if (label.name == "expect_stdout") {
if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) {
test[label.name] = stat.body.value;
} else {
test[label.name] = read_string(stat) + "\n";
}
test[node.label.name] = stat.body.start.value
} else {
test[node.label.name] = stat;
test[label.name] = stat;
}
return true;
}
@@ -269,3 +334,17 @@ function evaluate(code) {
code = make_code(code, { beautify: true });
return new Function("return(" + code + ")")();
}
function run_code(code) {
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
new vm.Script(code).runInNewContext({ console: console }, { timeout: 5000 });
return stdout;
} finally {
process.stdout.write = original_write;
}
}