jsbin/test/loop_detection_test.js

178 lines
6.1 KiB
JavaScript

var assert = require('assert');
var sinon = require('sinon');
var loopProtect = require('../public/js/runner/loop-protect');
// expose a window object for loopProtect compatibility
global.window = {
runnerWindow: loopProtect
};
var code = {
simple: 'return "remy";',
simplefor: 'var mul = 1; for (var i = 0; i < 10; i++) {\nmul = i;\n}\nreturn i',
simplefor2: 'for (var i = 0; i < 10; i++) {\nmul = i;\n}\nreturn i',
onelinefor: 'var i = 0, j = 0;\nfor (; i < 10; i++) j = i * 10;\nreturn i;',
onelinefor2: 'var i=0;\nfor(i=0; i<10; ++i){ break; }\nreturn i;',
simplewhile: 'var i = 0; while (i < 100) {\ni += 10;\n}\nreturn i;',
onelinewhile: 'var i = 0; while (i < 100) i += 10;\nreturn i;',
onelinewhile2: 'function noop(){}; while (1) noop("Ha.");',
whiletrue: 'var i = 0;\nwhile(true) {\ni++;\n}\nreturn true;',
irl1: 'var nums = [0,1];\n var total = 8;\n for(var i = 0; i <= total; i++){\n var newest = nums[i--]\n nums.push(newest);\n }\n return i;',
irl2: 'var a = 0;\n for(var j=1;j<=2;j++){\n for(var i=1;i<=60000;i++) {\n a += 1;\n }\n }\n return a;',
notloops: 'console.log("do");\nconsole.log("while");\nconsole.log(" foo do bar ");\nconsole.log(" foo while bar ");\nreturn true;',
notprops: "var foo = { 'do': 'bar' }; if (foo['do'] && foo.do) {}\nreturn true;",
notcomments: "var foo = {}; // do the awesome-ness!\nreturn true;",
dirtybraces: "var a = 0; for(var i=1;i<=120000; i++)\n {\n a += 1;\n }\nreturn a;",
onelinenewliner: "var b=0;\n function f(){b+=1;}\n for(var j=1;j<120000; j++)\n f();\nreturn j;",
irl3: "Todos.Todo = DS.Model.extend({\n title: DS.attr('string'),\n isCompleted: DS.attr('boolean')\n });",
brackets: 'var NUM=103, i, sqrt;\nfor(i=2; i<=Math.sqrt(NUM); i+=1){\n if(NUM % i === 0){\n console.log(NUM + " can be divided by " + i + ".");\n break;\n }\n}\nreturn i;',
lotolines: 'var LIMIT = 10;\nvar num, lastNum, tmp;\nfor(num = 1, lastNum = 0;\n num < LIMIT;\n lastNum = num, num = tmp){\n\n tmp = num + lastNum;\n}\nreturn lastNum;',
ignorecomments: '\n/**\n * This function handles the click for every button.\n *\n * Using the same function reduces code duplication and makes the\n */\nreturn true;',
};
describe('loop', function () {
var spy;
function run(code) {
var r = (new Function(code))();
return r;
}
beforeEach(function () {
spy = sinon.spy(run);
});
it('should ignore comments', function () {
var c = code.ignorecomments;
var compiled = loopProtect.rewriteLoops(c);
// console.log('\n---------\n' + c + '\n---------\n' + compiled);
assert(compiled === c);
var result = run(compiled);
assert(result === true);
});
it('should leave none loop code alone', function () {
assert(loopProtect.rewriteLoops(code.simple) === code.simple);
});
it('should rewrite for loops', function () {
var c = code.simplefor;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
var result = run(compiled);
assert(result === 10);
var c = code.simplefor2;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
var result = run(compiled);
assert(result === 10);
});
it('should rewrite one line for loops', function () {
var c = code.onelinefor;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
var result = run(compiled);
assert(result === 10);
c = code.onelinefor2;
compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
// console.log('\n---------\n' + c + '\n---------\n' + compiled);
result = run(compiled);
assert(result === 0);
});
it('should rewrite one line while loops', function () {
var c = code.onelinewhile2;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
// console.log('\n---------\n' + c + '\n---------\n' + compiled);
var result = run(compiled);
assert(result === undefined);
});
it('should protect infinite while', function () {
var c = code.whiletrue;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
assert(spy(compiled) === true);
});
it('should protect infinite for', function () {
var c = code.irl1;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
assert(spy(compiled) === 0);
});
it('should allow nested loops to run', function () {
var c = code.irl2;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
assert(run(compiled) === 120000);
});
it('should not rewrite "do" in strings', function () {
var c = code.notloops;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled === c);
});
it('should not rewrite "do" in object properties', function () {
var c = code.notprops;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled === c);
var c = code.irl3;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled === c);
});
it('should not rewrite "do" in comments', function () {
var c = code.notcomments;
var compiled = loopProtect.rewriteLoops(c);
// console.log(compiled);
assert(compiled === c);
assert(spy(compiled) === true);
});
it('should rewrite loops when curlies are on the next line', function () {
var c = code.dirtybraces;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
assert(spy(compiled) === 120000);
});
it('should find one liners on multiple lines', function () {
var c = code.onelinenewliner;
var compiled = loopProtect.rewriteLoops(c);
// console.log('\n----------');
// console.log(c);
// console.log('\n----------');
// console.log(compiled);
assert(compiled !== c);
assert(spy(compiled) === 120000);
});
it('should handle brackets inside of loop conditionals', function () {
var c = code.brackets;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
assert(spy(compiled) === 11);
});
it('should not corrupt multi-line (on more than one line) loops', function () {
var c = code.lotolines;
var compiled = loopProtect.rewriteLoops(c);
assert(compiled !== c);
assert(spy(compiled) === 8);
});
});