michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: /** michael@0: * Check setting breakpoints in source mapped sources. michael@0: */ michael@0: michael@0: var gDebuggee; michael@0: var gClient; michael@0: var gThreadClient; michael@0: michael@0: Components.utils.import('resource:///modules/devtools/SourceMap.jsm'); michael@0: michael@0: function run_test() michael@0: { michael@0: initTestDebuggerServer(); michael@0: gDebuggee = addTestGlobal("test-source-map"); michael@0: gClient = new DebuggerClient(DebuggerServer.connectPipe()); michael@0: gClient.connect(function() { michael@0: attachTestTabAndResume(gClient, "test-source-map", function(aResponse, aTabClient, aThreadClient) { michael@0: gThreadClient = aThreadClient; michael@0: test_simple_source_map(); michael@0: }); michael@0: }); michael@0: do_test_pending(); michael@0: } michael@0: michael@0: function testBreakpointMapping(aName, aCallback) michael@0: { michael@0: // Pause so we can set a breakpoint. michael@0: gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) { michael@0: do_check_true(!aPacket.error); michael@0: do_check_eq(aPacket.why.type, "debuggerStatement"); michael@0: michael@0: gThreadClient.setBreakpoint({ michael@0: url: "http://example.com/www/js/" + aName + ".js", michael@0: // Setting the breakpoint on an empty line so that it is pushed down one michael@0: // line and we can check the source mapped actualLocation later. michael@0: line: 3, michael@0: column: 0 michael@0: }, function (aResponse) { michael@0: do_check_true(!aResponse.error); michael@0: michael@0: // Actual location should come back source mapped still so that michael@0: // breakpoints are displayed in the UI correctly, etc. michael@0: do_check_eq(aResponse.actualLocation.line, 4); michael@0: do_check_eq(aResponse.actualLocation.url, michael@0: "http://example.com/www/js/" + aName + ".js"); michael@0: michael@0: // The eval will cause us to resume, then we get an unsolicited pause michael@0: // because of our breakpoint, we resume again to finish the eval, and michael@0: // finally receive our last pause which has the result of the client michael@0: // evaluation. michael@0: gThreadClient.eval(null, aName + "()", function (aResponse) { michael@0: do_check_true(!aResponse.error, "Shouldn't be an error resuming to eval"); michael@0: do_check_eq(aResponse.type, "resumed"); michael@0: michael@0: gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) { michael@0: do_check_eq(aPacket.why.type, "breakpoint"); michael@0: // Assert that we paused because of the breakpoint at the correct michael@0: // location in the code by testing that the value of `ret` is still michael@0: // undefined. michael@0: do_check_eq(aPacket.frame.environment.bindings.variables.ret.value.type, michael@0: "undefined"); michael@0: michael@0: gThreadClient.resume(function (aResponse) { michael@0: do_check_true(!aResponse.error); michael@0: michael@0: gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) { michael@0: do_check_eq(aPacket.why.type, "clientEvaluated"); michael@0: do_check_eq(aPacket.why.frameFinished.return, aName); michael@0: michael@0: gThreadClient.resume(function (aResponse) { michael@0: do_check_true(!aResponse.error); michael@0: aCallback(); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: gDebuggee.eval("(" + function () { michael@0: debugger; michael@0: } + "());"); michael@0: } michael@0: michael@0: function test_simple_source_map() michael@0: { michael@0: let expectedSources = new Set([ michael@0: "http://example.com/www/js/a.js", michael@0: "http://example.com/www/js/b.js", michael@0: "http://example.com/www/js/c.js" michael@0: ]); michael@0: michael@0: gClient.addListener("newSource", function _onNewSource(aEvent, aPacket) { michael@0: expectedSources.delete(aPacket.source.url); michael@0: if (expectedSources.size > 0) { michael@0: return; michael@0: } michael@0: gClient.removeListener("newSource", _onNewSource); michael@0: michael@0: testBreakpointMapping("a", function () { michael@0: testBreakpointMapping("b", function () { michael@0: testBreakpointMapping("c", function () { michael@0: finishClient(gClient); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: let a = new SourceNode(null, null, null, [ michael@0: new SourceNode(1, 0, "a.js", "function a() {\n"), michael@0: new SourceNode(2, 0, "a.js", " var ret;\n"), michael@0: new SourceNode(3, 0, "a.js", " // Empty line\n"), michael@0: new SourceNode(4, 0, "a.js", " ret = 'a';\n"), michael@0: new SourceNode(5, 0, "a.js", " return ret;\n"), michael@0: new SourceNode(6, 0, "a.js", "}\n") michael@0: ]); michael@0: let b = new SourceNode(null, null, null, [ michael@0: new SourceNode(1, 0, "b.js", "function b() {\n"), michael@0: new SourceNode(2, 0, "b.js", " var ret;\n"), michael@0: new SourceNode(3, 0, "b.js", " // Empty line\n"), michael@0: new SourceNode(4, 0, "b.js", " ret = 'b';\n"), michael@0: new SourceNode(5, 0, "b.js", " return ret;\n"), michael@0: new SourceNode(6, 0, "b.js", "}\n") michael@0: ]); michael@0: let c = new SourceNode(null, null, null, [ michael@0: new SourceNode(1, 0, "c.js", "function c() {\n"), michael@0: new SourceNode(2, 0, "c.js", " var ret;\n"), michael@0: new SourceNode(3, 0, "c.js", " // Empty line\n"), michael@0: new SourceNode(4, 0, "c.js", " ret = 'c';\n"), michael@0: new SourceNode(5, 0, "c.js", " return ret;\n"), michael@0: new SourceNode(6, 0, "c.js", "}\n") michael@0: ]); michael@0: michael@0: let { code, map } = (new SourceNode(null, null, null, [ michael@0: a, b, c michael@0: ])).toStringWithSourceMap({ michael@0: file: "http://example.com/www/js/abc.js", michael@0: sourceRoot: "http://example.com/www/js/" michael@0: }); michael@0: michael@0: code += "//# sourceMappingURL=data:text/json;base64," + btoa(map.toString()); michael@0: michael@0: Components.utils.evalInSandbox(code, gDebuggee, "1.8", michael@0: "http://example.com/www/js/abc.js", 1); michael@0: }