// // Copyright (C) 2008 Loic Dachary // Copyright (C) 2008 Johan Euphrosine // Copyright (C) 2010 Eric Wendelin // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // module("printstacktrace"); test("printStackTrace", function() { expect(1); var r = printStackTrace(); equals(typeof r, 'object', 'printStackTrace returns an array'); }); test("printStackTrace options", function() { expect(1); var guessFunctions = printStackTrace.implementation.prototype.guessFunctions; printStackTrace.implementation.prototype.guessFunctions = function() { printStackTrace.implementation.prototype.guessFunctions = guessFunctions; ok(true, 'guessFunctions called'); }; var r = printStackTrace({guess: true}); }); test("mode", function() { expect(1); equals("chrome firefox other opera".indexOf(printStackTrace.implementation.prototype.mode()) >= 0,true); }); test("run mode", function() { expect(1); var p = new printStackTrace.implementation(); p.other = p.firefox = p.chrome = p.opera = function() { equals(1,1,'called'); }; p.run(); }); test("run firefox", function() { expect(1); var p = new printStackTrace.implementation(); p._mode = 'firefox'; p.other = p.opera = function() { equals(1,0,'must not be called'); }; p.firefox = function() { equals(1,1,'called'); }; p.run(); }); test("run other", function() { expect(1); var p = new printStackTrace.implementation(); p._mode = 'other'; p.opera = p.firefox = function() { equals(1,0,'must not be called'); }; p.other = function() { equals(1,1,'called'); }; p.run(); }); test("firefox", function() { var mode = printStackTrace.implementation.prototype.mode(); var e = []; e.push({ stack: 'discarded()...\nf1(1,"abc")@file.js:40\n()@file.js:41\n@:0 \nf44()@file.js:494'}); if(mode == 'firefox') { function discarded() { try {(0)();} catch (exception) { e.push(exception); } } function f1(arg1, arg2) { discarded(); } var f2 = function() { f1(1, "abc"); }; f2(); } expect(4 * e.length); for(var i = 0; i < e.length; i++) { var message = printStackTrace.implementation.prototype.firefox(e[i]); var message_string = message.join("\n"); //equals(message_string, '', 'debug'); equals(message_string.indexOf('discarded'), -1, 'discarded'); equals(message[0].indexOf('f1(1,"abc")') >= 0, true, 'f1'); equals(message[1].indexOf('{anonymous}()@') >= 0, true, 'f2 anonymous'); equals(message[2].indexOf('@:0'), -1, '@:0 discarded'); } }); test("chrome", function() { var mode = printStackTrace.implementation.prototype.mode(); var e = []; e.push({ stack: 'ignored\nignored\n at discarded (file.js:132:3)\n at file.js:135:3\n at f1 (file.js:132:13)\n at file.js:135:23\n at Object. (file.js:137:9)\n at file.js:137:32 at process (file.js:594:22)'}); if(mode == 'chrome') { function discarded() { try {(0)();} catch (exception) { e.push(exception); } } function f1(arg1, arg2) { discarded(); } var f2 = function() { f1(1, "abc"); }; f2(); } expect(4 * e.length); for(var i = 0; i < e.length; i++) { var message = printStackTrace.implementation.prototype.chrome(e[i]); var message_string = message.join("\n"); //equals(message_string, '', 'debug'); equals(message_string.indexOf('discarded'), -1, 'discarded'); equals(message[0].indexOf('f1') >= 0, true, 'f1'); equals(message[1].indexOf('anonymous') >= 0, true, 'f2 anonymous'); equals(message[2].indexOf('unknown source'), -1, 'unknown source discarded'); } }); test("opera", function() { var mode = printStackTrace.implementation.prototype.mode(); var e = []; e.push({ message: 'ignored\nignored\nignored\nignored\nLine 40 of linked script http://site.com: in function f1\n discarded()\nLine 44 of linked script http://site.com\n f1(1, "abc")\nignored\nignored'}); if(mode == 'opera') { function discarded() { try {(0)();} catch (exception) { e.push(exception); } } function f1(arg1, arg2) { discarded(); } var f2 = function() { f1(1, "abc"); }; f2(); } expect(5 * e.length); for(var i = 0; i < e.length; i++) { var message = printStackTrace.implementation.prototype.opera(e[i]); var message_string = message.join("\n"); //equals(message_string, '', 'debug'); equals(message_string.indexOf('ignored'), -1, 'ignored'); equals(message[0].indexOf('f1()') >= 0, true, 'f1 function name'); equals(message[0].indexOf('discarded()') >= 0, true, 'f1 statement'); equals(message[1].indexOf('{anonymous}()@') >= 0, true, 'f2 is anonymous'); equals(message[1].indexOf('f1(1, "abc")') >= 0, true, 'f2 statement'); } }); test("other", function() { var mode = printStackTrace.implementation.prototype.mode(); var frame = function(args, fun, caller) { this['arguments'] = args; this.caller = caller; this.fun = fun; }; frame.prototype.toString = function() { return 'function '+this.fun+'() {}'; }; function f10() {} var frame_f2 = new frame([], '', undefined); var frame_f1 = new frame([1, 'abc', f10, {1: {2: {3: 4} } }], 'FUNCTION f1 (a,b,c)', frame_f2); expect(mode == 'other' ? 4 : 2); var message = printStackTrace.implementation.prototype.other(frame_f1); var message_string = message.join("\n"); equals(message[0].indexOf('f1(1,"abc",#function,#object)') >= 0, true, 'f1'); equals(message[1].indexOf('{anonymous}()') >= 0, true, 'f2 anonymous'); if(mode == 'other') { function f1(arg1, arg2) { var message = printStackTrace.implementation.prototype.other(arguments.callee); var message_string = message.join("\n"); //equals(message_string, '', 'debug'); equals(message[0].indexOf('f1(1,"abc",#function,#object)') >= 0, true, 'f1'); equals(message[1].indexOf('{anonymous}()') >= 0, true, 'f2 anonymous'); } var f2 = function() { f1(1, 'abc', f10, {1: {2: {3: 4} } }); }; f2(); } }); test("recursion other", function() { var mode = printStackTrace.implementation.prototype.mode(); expect(mode == 'other' ? 2 : 0); if (mode == 'other') { function recurse(b) { if (!b) { var message = printStackTrace.implementation.prototype.other(arguments.callee); var message_string = message.join("\n"); //equals(message_string, '', 'debug'); equals(message[0].indexOf('recurse(false)') >= 0, true, 'first recurse false'); equals(message[1].indexOf('recurse(true)') >= 0, true, 'second recurse true'); } else { recurse(true); } } recurse(false); } }); test("stringify", function() { expect(3); equals(printStackTrace.implementation.prototype.stringifyArguments(["a", 1, {}, function() {}]), '"a",1,#object,#function'); equals(printStackTrace.implementation.prototype.stringifyArguments([1, 2, 3]), '1,2,3'); equals(printStackTrace.implementation.prototype.stringifyArguments([]), ''); }); test("guessFunctionNameFromLines", function() { expect(3); equals(printStackTrace.implementation.prototype.guessFunctionNameFromLines(2, ['var a = function() {', 'var b = 2;', '};']), 'a'); equals(printStackTrace.implementation.prototype.guessFunctionNameFromLines(2, ['function a() {', 'var b = 2;', '};']), 'a'); equals(printStackTrace.implementation.prototype.guessFunctionNameFromLines(2, ['var a = 1;', 'var b = 2;', 'var c = 3;']), '(?)'); }); test("getSource cache miss", function() { expect(3); var p = new printStackTrace.implementation(); var file = 'file:///test'; p.ajax = function(fileArg, callback) { equals(fileArg, file, 'cache miss'); return 'line0\nline1\n'; }; var lines = p.getSource(file); equals(lines[0], 'line0'); equals(lines[1], 'line1'); }); test("getSource cache hit", function() { expect(2); var p = new printStackTrace.implementation(); var file = 'file:///test'; p.ajax = function(fileArg, callback) { ok(false, 'not called'); }; p.sourceCache[file] = ['line0', 'line1']; var lines = p.getSource(file); equals(lines[0], 'line0'); equals(lines[1], 'line1'); }); test("sync ajax", function() { expect(1); var p = new printStackTrace.implementation(); var data = p.ajax(document.location.href); ok(data.indexOf('stacktrace') >= 0, 'synchronous get'); }); test("guessFunctionName", function() { expect(1); var p = new printStackTrace.implementation(); var file = 'file:///test'; p.sourceCache[file] = ['var a = function() {', 'var b = 2;', '};']; equals(p.guessFunctionName(file, 2), 'a'); }); test("guessFunctionName exception", function() { expect(1); var p = new printStackTrace.implementation(); p.getSource = function() { throw 'permission denied'; }; var file = 'file:///test'; equals(p.guessFunctionName(file, 2), 'getSource failed with url: file:///test, exception: permission denied'); }); test("guessFunctions firefox", function() { var results = []; var mode = printStackTrace.implementation.prototype.mode(); var p = new printStackTrace.implementation(); p._mode = 'firefox'; var file = 'file:///test'; p.sourceCache[file] = ['var f2 = function() {', 'var b = 2;', '};']; results.push(['run() ('+file+':1)', 'f2()@'+file+':1']); if (mode == 'firefox') { var f2 = function() { try { (0)(); } catch(e) { results.push(p.run()); } }; f2(); } expect(results.length * 1); for (var i = 0; i < results.length; ++i) { //equals(p.guessFunctions(results[i]), '', 'debug'); equals(p.guessFunctions(results[i])[1].indexOf('f2'), 0, 'f2'); } }); test("guessFunctions chrome", function() { var results = []; var mode = printStackTrace.implementation.prototype.mode(); var p = new printStackTrace.implementation(); p._mode = 'chrome'; var file = 'file:///test'; p.sourceCache[file] = ['var f2 = function() {', 'var b = 2;', '};']; results.push(['run() ('+file+':1:1)', 'f2() ('+file+':1:1)']); if (mode == 'chrome') { var f2 = function() { try { (0)(); } catch(e) { results.push(p.run()); } }; f2(); } expect(results.length); for (var i = 0; i < results.length; ++i) { //equals((results[i]), '', 'debug'); equals(p.guessFunctions(results[i])[1].indexOf('f2()'), 0, 'f2'); } }); test("guessFunctions opera", function() { var results = []; var mode = printStackTrace.implementation.prototype.mode(); var p = new printStackTrace.implementation(); p._mode = 'opera'; var file = 'file:///test'; p.sourceCache[file] = ['var f2 = function() {', 'var b = 2;', '};']; results.push(['f2()@'+file+':2 -- code']); if (mode == 'opera') { var f2 = function() { try { (0)(); } catch(e) { results.push(p.run()); } }; f2(); } expect(results.length * 1); for (var i = 0; i < results.length; ++i) { //equals(p.guessFunctions(results[i]), '', 'debug'); equals(p.guessFunctions(results[i])[0].indexOf('f2'), 0, 'f2'); } }); test("guessFunctions other", function() { var results = []; var mode = printStackTrace.implementation.prototype.mode(); var p = new printStackTrace.implementation(); p.mode = function() { return 'other'; }; var file = 'file:///test'; p.sourceCache[file] = ['var f2 = function() {', 'var b = 2;', '};']; results.push(['{anonymous}()']); if (mode == 'other') { var f2 = function() { try { (0)(); } catch(e) { results.push(p.run()); } }; f2(); } expect(results.length * 1); for (var i = 0; i < results.length; ++i) { //equals((results[i]), '', 'debug'); equals(p.guessFunctions(results[i])[0].indexOf('{anonymous}'), 0, 'no file and line number on other'); } });