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;', dowhile: 'var x=0;\ndo\n {\n x++;\n } while (x < 3);\nreturn x;', dowhilenested: 'var x=0;\n do\n {\n x++;\n var b = 0;\n do {\n b++; \n } while (b < 3);\n } while (x < 3);\nreturn x;', disabled: '// noprotect\nvar x=0;\ndo\n {\n x++;\n } while (x < 3);\nreturn x;', }; 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); }); it('should ignore when loop protect is disabled', function () { var c = code.disabled; var compiled = loopProtect.rewriteLoops(c); assert(compiled === c); assert(spy(compiled) === 3); }); it('should protect do loops', function () { var c = code.dowhile; var compiled = loopProtect.rewriteLoops(c); assert(compiled !== c); assert(spy(compiled) === 3); var c = code.dowhilenested; var compiled = loopProtect.rewriteLoops(c); // console.log('\n----------'); // console.log(c); // console.log('\n----------'); // console.log(compiled); assert(compiled !== c); assert(spy(compiled) === 3); }); });