// getLineOffsets identifies multiple ways to land on a line. var g = newGlobal(); g.line0 = null; var dbg = Debugger(g); var where; dbg.onDebuggerStatement = function (frame) { var s = frame.script, lineno, offs; lineno = g.line0 + where; offs = s.getLineOffsets(lineno); for (var i = 0; i < offs.length; i++) { assertEq(s.getOffsetLocation(offs[i]).lineNumber, lineno); s.setBreakpoint(offs[i], {hit: function () { g.log += 'B'; }}); } lineno++; offs = s.getLineOffsets(lineno); for (var i = 0; i < offs.length; i++) { assertEq(s.getOffsetLocation(offs[i]).lineNumber, lineno); s.setBreakpoint(offs[i], {hit: function () { g.log += 'C'; }}); } g.log += 'A'; }; function test(s) { assertEq(s.charAt(s.length - 1), '\n'); var count = (s.split(/\n/).length - 1); // number of lines in s g.log = ''; where = 1 + count; g.eval("line0 = Error().lineNumber;\n" + "debugger;\n" + // line0 + 1 s + // line0 + 2 ... line0 + where "log += 'D';\n"); assertEq(g.log, 'AB!CD'); } // if-statement with yes and no paths on a single line g.i = 0; test("if (i === 0)\n" + " log += '!'; else log += 'X';\n"); test("if (i === 2)\n" + " log += 'X'; else log += '!';\n"); // break to a line that has code inside and outside the loop g.i = 2; test("while (1) {\n" + " if (i === 2) break;\n" + " log += 'X'; } log += '!';\n"); // leaving a while loop by failing the test, when the last line has stuff both inside and outside the loop g.i = 0; test("while (i > 0) {\n" + " if (i === 70) log += 'X';\n" + " --i; } log += '!';\n"); // multiple case-labels on the same line g.i = 0; test("switch (i) {\n" + " case 0: case 1: log += '!'; break; }\n"); test("switch ('' + i) {\n" + " case '0': case '1': log += '!'; break; }\n"); test("switch (i) {\n" + " case 'ok' + i: case i - i: log += '!'; break; }\n");