implement test/sandbox.js (#1749)

- `test/run-tests.js` and `test/ufuzz.js` now shares the same `run_code()` and `same_stdout()`
- re-enable fuzzer to generate top-level `NaN`, `Infinity` & `undefined`
- attempt to show beautified output only when `run_code()` output is preserved
This commit is contained in:
Alex Lam S.L
2017-04-01 05:47:11 +08:00
committed by GitHub
parent 257ddc3bdb
commit c934fc8142
3 changed files with 344 additions and 377 deletions

View File

@@ -4,22 +4,11 @@ var U = require("../tools/node");
var path = require("path");
var fs = require("fs");
var assert = require("assert");
var vm = require("vm");
var sandbox = require("./sandbox");
var tests_dir = path.dirname(module.filename);
var failures = 0;
var failed_files = {};
var same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) {
if (typeof expected != typeof actual) return false;
if (typeof expected != "string") {
if (expected.name != actual.name) return false;
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
}
return expected == actual;
} : function(expected, actual) {
return typeof expected == typeof actual && expected.toString() == actual.toString();
};
run_compress_tests();
if (failures) {
@@ -182,11 +171,11 @@ function run_compress_tests() {
}
}
if (test.expect_stdout) {
var stdout = run_code(input_code);
var stdout = sandbox.run_code(input_code);
if (test.expect_stdout === true) {
test.expect_stdout = stdout;
}
if (!same_stdout(test.expect_stdout, stdout)) {
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
@@ -197,8 +186,8 @@ function run_compress_tests() {
failures++;
failed_files[file] = 1;
} else {
stdout = run_code(output);
if (!same_stdout(test.expect_stdout, stdout)) {
stdout = sandbox.run_code(output);
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
@@ -330,19 +319,3 @@ 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;
} catch (ex) {
return ex;
} finally {
process.stdout.write = original_write;
}
}

50
test/sandbox.js Normal file
View File

@@ -0,0 +1,50 @@
var vm = require("vm");
var FUNC_TOSTRING = [
"Function.prototype.toString = Function.prototype.valueOf = function() {",
" var ids = [];",
" return function() {",
" var i = ids.indexOf(this);",
" if (i < 0) {",
" i = ids.length;",
" ids.push(this);",
" }",
' return "[Function: __func_" + i + "__]";',
" }",
"}();",
""
].join("\n");
exports.run_code = function(code) {
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
new vm.Script(FUNC_TOSTRING + code).runInNewContext({
console: {
log: function() {
return console.log.apply(console, [].map.call(arguments, function(arg) {
return typeof arg == "function" ? arg.toString() : arg;
}));
}
}
}, { timeout: 30000 });
return stdout;
} catch (ex) {
return ex;
} finally {
process.stdout.write = original_write;
}
};
exports.same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) {
if (typeof expected != typeof actual) return false;
if (typeof expected != "string") {
if (expected.name != actual.name) return false;
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
}
return expected == actual;
} : function(expected, actual) {
return typeof expected == typeof actual && expected.toString() == actual.toString();
};

View File

@@ -12,8 +12,8 @@
stream._handle.setBlocking(true);
});
var vm = require("vm");
var minify = require("..").minify;
var sandbox = require("./sandbox");
var MAX_GENERATED_TOPLEVELS_PER_RUN = 3;
var MAX_GENERATION_RECURSION_DEPTH = 12;
@@ -70,7 +70,6 @@ var STMT_COUNT_FROM_GLOBAL = true; // count statement depth from nearest functio
var num_iterations = +process.argv[2] || 1/0;
var verbose = false; // log every generated test
var verbose_interval = false; // log every 100 generated tests
var enable_beautifier = false; // run beautifier as well?
for (var i = 2; i < process.argv.length; ++i) {
switch (process.argv[i]) {
case '-v':
@@ -79,9 +78,6 @@ for (var i = 2; i < process.argv.length; ++i) {
case '-V':
verbose_interval = true;
break;
case '-b':
enable_beautifier = true;
break;
case '-t':
MAX_GENERATED_TOPLEVELS_PER_RUN = +process.argv[++i];
if (!MAX_GENERATED_TOPLEVELS_PER_RUN) throw new Error('Must generate at least one toplevel per run');
@@ -271,47 +267,9 @@ var TYPEOF_OUTCOMES = [
'symbol',
'crap' ];
var FUNC_TOSTRING = [
"Function.prototype.toString = Function.prototype.valueOf = function() {",
" var ids = [];",
" return function() {",
" var i = ids.indexOf(this);",
" if (i < 0) {",
" i = ids.length;",
" ids.push(this);",
" }",
' return "[Function: __func_" + i + "__]";',
" }",
"}();",
""
].join("\n");
var loops = 0;
var funcs = 0;
function run_code(code) {
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
new vm.Script(FUNC_TOSTRING + code).runInNewContext({
console: {
log: function() {
return console.log.apply(console, [].map.call(arguments, function(arg) {
return typeof arg == "function" ? arg.toString() : arg;
}));
}
}
}, { timeout: 30000 });
return stdout;
} catch (ex) {
return ex;
} finally {
process.stdout.write = original_write;
}
}
function rng(max) {
return Math.floor(max * Math.random());
}
@@ -327,7 +285,7 @@ function createTopLevelCodes(n) {
function createTopLevelCode() {
var r = rng(3);
if (r > 0) return createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, IN_GLOBAL, ANY_TYPE, CANNOT_THROW, 0);
return createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0, IN_GLOBAL);
return createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0);
}
function createFunctions(n, recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
@@ -344,15 +302,15 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
var func = funcs++;
var namesLenBefore = VAR_NAMES.length;
var name = (inGlobal || rng(5) > 0) ? 'f' + func : createVarName(MANDATORY, inGlobal, noDecl);
var name = (inGlobal || rng(5) > 0) ? 'f' + func : createVarName(MANDATORY, noDecl);
if (name === 'a' || name === 'b' || name === 'c') name = 'f' + func; // quick hack to prevent assignment to func names of being called
var s = '';
if (rng(5) === 1) {
// functions with functions. lower the recursion to prevent a mess.
s = 'function ' + name + '(' + createVarName(MANDATORY, inGlobal) + '){' + createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth) + '}\n';
s = 'function ' + name + '(' + createVarName(MANDATORY) + '){' + createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth) + '}\n';
} else {
// functions with statements
s = 'function ' + name + '(' + createVarName(MANDATORY, inGlobal) + '){' + createStatements(3, recurmax, canThrow, CANNOT_THROW, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, inGlobal, NOT_GLOBAL) + '}\n';
s = 'function ' + name + '(' + createVarName(MANDATORY) + '){' + createStatements(3, recurmax, canThrow, CANNOT_THROW, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}\n';
}
VAR_NAMES.length = namesLenBefore;
@@ -365,16 +323,16 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
return s;
}
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) {
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
if (--recurmax < 0) { return ';'; }
var s = '';
while (--n > 0) {
s += createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) + '\n';
s += createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '\n';
}
return s;
}
function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) {
function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
++stmtDepth;
var loop = ++loops;
if (--recurmax < 0) {
@@ -389,15 +347,15 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
switch (target) {
case STMT_BLOCK:
return '{' + createStatements(rng(5) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) + '}';
return '{' + createStatements(rng(5) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '}';
case STMT_IF_ELSE:
return 'if (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) + (rng(2) === 1 ? ' else ' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) : '');
return 'if (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + (rng(2) === 1 ? ' else ' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) : '');
case STMT_DO_WHILE:
return '{var brake' + loop + ' = 5; do {' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth, inGlobal) + '} while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0);}';
return '{var brake' + loop + ' = 5; do {' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth) + '} while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0);}';
case STMT_WHILE:
return '{var brake' + loop + ' = 5; while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0)' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth, inGlobal) + '}';
return '{var brake' + loop + ' = 5; while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0)' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth) + '}';
case STMT_FOR_LOOP:
return 'for (var brake' + loop + ' = 5; (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && brake' + loop + ' > 0; --brake' + loop + ')' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth, inGlobal);
return 'for (var brake' + loop + ' = 5; (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && brake' + loop + ' > 0; --brake' + loop + ')' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth);
case STMT_SEMI:
return ';';
case STMT_EXPR:
@@ -405,23 +363,23 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
case STMT_SWITCH:
// note: case args are actual expressions
// note: default does not _need_ to be last
return 'switch (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') { ' + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) + '}';
return 'switch (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') { ' + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '}';
case STMT_VAR:
switch (rng(3)) {
case 0:
var name = createVarName(MANDATORY, inGlobal);
var name = createVarName(MANDATORY);
if (name === 'c') name = 'a';
return 'var ' + name + ';';
case 1:
// initializer can only have one expression
var name = createVarName(MANDATORY, inGlobal);
var name = createVarName(MANDATORY);
if (name === 'c') name = 'b';
return 'var ' + name + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
default:
// initializer can only have one expression
var n1 = createVarName(MANDATORY, inGlobal);
var n1 = createVarName(MANDATORY);
if (n1 === 'c') n1 = 'b';
var n2 = createVarName(MANDATORY, inGlobal);
var n2 = createVarName(MANDATORY);
if (n2 === 'c') n2 = 'b';
return 'var ' + n1 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ', ' + n2 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
}
@@ -452,17 +410,17 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
// catch var could cause some problems
// note: the "blocks" are syntactically mandatory for try/catch/finally
var n = rng(3); // 0=only catch, 1=only finally, 2=catch+finally
var s = 'try {' + createStatement(recurmax, n === 1 ? CANNOT_THROW : CAN_THROW, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) + ' }';
var s = 'try {' + createStatement(recurmax, n === 1 ? CANNOT_THROW : CAN_THROW, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
if (n !== 1) {
// the catch var should only be accessible in the catch clause...
// we have to do go through some trouble here to prevent leaking it
var nameLenBefore = VAR_NAMES.length;
var catchName = createVarName(MANDATORY);
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
s += ' catch (' + catchName + ') { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) + ' }';
s += ' catch (' + catchName + ') { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1); // remove catch name
}
if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) + ' }';
if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
return s;
case STMT_C:
return 'c = c + 1;';
@@ -471,7 +429,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
}
}
function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, inGlobal) {
function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
var hadDefault = false;
var s = '';
while (n-- > 0) {
@@ -479,7 +437,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
if (hadDefault || rng(5) > 0) {
s += '' +
'case ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ':\n' +
createStatements(rng(3) + 1, recurmax, canThrow, CAN_BREAK, canContinue, cannotReturn, stmtDepth, inGlobal) +
createStatements(rng(3) + 1, recurmax, canThrow, CAN_BREAK, canContinue, cannotReturn, stmtDepth) +
'\n' +
(rng(10) > 0 ? ' break;' : '/* fall-through */') +
'\n';
@@ -487,7 +445,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
hadDefault = true;
s += '' +
'default:\n' +
createStatements(rng(3) + 1, recurmax, canThrow, CAN_BREAK, canContinue, cannotReturn, stmtDepth, inGlobal) +
createStatements(rng(3) + 1, recurmax, canThrow, CAN_BREAK, canContinue, cannotReturn, stmtDepth) +
'\n';
}
}
@@ -527,21 +485,21 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
return createExpression(recurmax, noComma, stmtDepth, canThrow) + '?' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ':' + createExpression(recurmax, noComma, stmtDepth, canThrow);
case 8:
var nameLenBefore = VAR_NAMES.length;
var name = createVarName(MAYBE, NOT_GLOBAL); // note: this name is only accessible from _within_ the function. and immutable at that.
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
if (name === 'c') name = 'a';
var s = '';
switch(rng(4)) {
case 0:
s = '(function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, NOT_GLOBAL) + '})()';
s = '(function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '})()';
break;
case 1:
s = '+function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, NOT_GLOBAL) + '}()';
s = '+function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}()';
break;
case 2:
s = '!function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, NOT_GLOBAL) + '}()';
s = '!function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}()';
break;
default:
s = 'void function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, NOT_GLOBAL) + '}()';
s = 'void function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}()';
break;
}
VAR_NAMES.length = nameLenBefore;
@@ -605,15 +563,15 @@ function _createSimpleBinaryExpr(recurmax, noComma) {
function createTypeofExpr() {
switch (rng(5)) {
case 0:
return 'typeof ' + createVarName(MANDATORY, NOT_GLOBAL, DONT_STORE) + ' === "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' === "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
case 1:
return 'typeof ' + createVarName(MANDATORY, NOT_GLOBAL, DONT_STORE) + ' !== "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' !== "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
case 2:
return 'typeof ' + createVarName(MANDATORY, NOT_GLOBAL, DONT_STORE) + ' == "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' == "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
case 3:
return 'typeof ' + createVarName(MANDATORY, NOT_GLOBAL, DONT_STORE) + ' != "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' != "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
case 4:
return 'typeof ' + createVarName(MANDATORY, NOT_GLOBAL, DONT_STORE);
return 'typeof ' + createVarName(MANDATORY, DONT_STORE);
}
}
@@ -634,55 +592,67 @@ function createUnaryOp() {
return UNARY_OPS[rng(UNARY_OPS.length)];
}
function createVarName(maybe, inGlobal, dontStore) {
function createVarName(maybe, dontStore) {
if (!maybe || rng(2) === 1) {
do {
var r = rng(VAR_NAMES.length);
var suffixed = rng(5) > 0;
var name = VAR_NAMES[r] + (suffixed ? '_' + (++loops) : '');
} while (inGlobal && (name === 'NaN' || name === 'undefined' || name === 'Infinity')); // prevent nodejs module strict mode problems
if (!dontStore && suffixed) VAR_NAMES.push(name);
return name;
}
return '';
}
function log(ok) {
function try_beautify(code, result) {
try {
var beautified = minify(code, {
fromString: true,
compress: false,
mangle: false,
output: {
beautify: true,
bracketize: true,
},
}).code;
if (sandbox.same_stdout(sandbox.run_code(beautified), result)) {
console.log("// (beautified)");
console.log(beautified);
return;
}
} catch (e) {
console.log("// !!! beautify failed !!!");
console.log(e.stack);
}
console.log("//");
console.log(code);
}
function log() {
if (!ok) console.log('\n\n\n\n\n\n!!!!!!!!!!\n\n\n');
console.log("//=============================================================");
if (!ok) console.log("// !!!!!! Failed... round", round);
console.log("// original code");
console.log("//");
console.log(original_code);
try_beautify(original_code, original_result);
console.log();
console.log();
if (enable_beautifier) {
console.log("//-------------------------------------------------------------");
console.log("// original code (beautify'd)");
console.log("//");
console.log(beautify_code);
console.log();
console.log();
}
console.log("//-------------------------------------------------------------");
if (typeof uglify_code == "string") {
console.log("// uglified code");
console.log("//");
console.log(uglify_code);
try_beautify(uglify_code, uglify_result);
console.log();
console.log();
console.log("original result:");
console.log(original_result);
if (enable_beautifier) {
console.log("beautified result:");
console.log(beautify_result);
}
console.log("uglified result:");
console.log(uglify_result);
} else {
console.log("// !!! uglify failed !!!");
console.log(uglify_code.stack);
}
if (!ok) console.log("!!!!!! Failed... round", round);
}
for (var round = 0; round < num_iterations; round++) {
var parse_error = false;
process.stdout.write(round + " of " + num_iterations + "\r");
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
@@ -691,51 +661,25 @@ for (var round = 0; round < num_iterations; round++) {
var original_code = [
"var a = 100, b = 10, c = 0;",
createTopLevelCodes(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1) +
"console.log(null, a, b, c);" // the array makes for a cleaner output (empty string still shows up etc)
createTopLevelCodes(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1),
"console.log(null, a, b, c);" // preceding `null` makes for a cleaner output (empty string still shows up etc)
].join("\n");
var original_result = run_code(original_code);
if (enable_beautifier) {
var uglify_code;
try {
var beautify_code = minify(original_code, {
uglify_code = minify(original_code, {
fromString: true,
mangle: false,
compress: false,
output: {
beautify: true,
bracketize: true,
},
}).code;
} catch (e) {
parse_error = 1;
}
var beautify_result = run_code(beautify_code);
} else {
var beautify_result = original_result;
uglify_code = e;
}
try {
var uglify_code = minify(original_code, {
fromString: true,
mangle: true,
compress: {
passes: 3,
},
output: {
//beautify: true,
//bracketize: true,
},
}).code;
} catch(e) {
parse_error = 2;
var ok = typeof uglify_code == "string";
if (ok) {
var original_result = sandbox.run_code(original_code);
var uglify_result = sandbox.run_code(uglify_code);
ok = sandbox.same_stdout(original_result, uglify_result);
}
var uglify_result = run_code(uglify_code);
var ok = !parse_error && original_result == beautify_result && original_result == uglify_result;
//if (!ok && typeof original_result === 'string' && original_result.indexOf('[Function:') >= 0) ok = true;
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(ok);
if (parse_error === 1) console.log('Parse error while beautifying');
if (parse_error === 2) console.log('Parse error while uglifying');
if (!ok) break;
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log();
if (!ok) process.exit(1);
}