/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ var gClient; var gDebuggee; const xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector); function run_test() { initTestDebuggerServer(); gDebuggee = testGlobal("test-1"); DebuggerServer.addTestGlobal(gDebuggee); let transport = DebuggerServer.connectPipe(); gClient = new DebuggerClient(transport); gClient.addListener("connected", function (aEvent, aType, aTraits) { gClient.listTabs((aResponse) => { do_check_true("tabs" in aResponse); for (let tab of aResponse.tabs) { if (tab.title == "test-1") { test_attach_tab(tab.actor); return false; } } do_check_true(false); // We should have found our tab in the list. return undefined; }); }); gClient.connect(); do_test_pending(); } // Attach to |aTabActor|, and check the response. function test_attach_tab(aTabActor) { gClient.request({ to: aTabActor, type: "attach" }, function (aResponse) { do_check_false("error" in aResponse); do_check_eq(aResponse.from, aTabActor); do_check_eq(aResponse.type, "tabAttached"); do_check_true(typeof aResponse.threadActor === "string"); test_attach_thread(aResponse.threadActor); }); } // Attach to |aThreadActor|, check the response, and resume it. function test_attach_thread(aThreadActor) { gClient.request({ to: aThreadActor, type: "attach" }, function (aResponse) { do_check_false("error" in aResponse); do_check_eq(aResponse.from, aThreadActor); do_check_eq(aResponse.type, "paused"); do_check_true("why" in aResponse); do_check_eq(aResponse.why.type, "attached"); test_resume_thread(aThreadActor); }); } // Resume |aThreadActor|, and see that it stops at the 'debugger' // statement. function test_resume_thread(aThreadActor) { // Allow the client to resume execution. gClient.request({ to: aThreadActor, type: "resume" }, function (aResponse) { do_check_false("error" in aResponse); do_check_eq(aResponse.from, aThreadActor); do_check_eq(aResponse.type, "resumed"); do_check_eq(xpcInspector.eventLoopNestLevel, 0); // Now that we know we're resumed, we can make the debuggee do something. Cu.evalInSandbox("var a = true; var b = false; debugger; var b = true;", gDebuggee); // Now make sure that we've run the code after the debugger statement... do_check_true(gDebuggee.b); }); gClient.addListener("paused", function (aName, aPacket) { do_check_eq(aName, "paused"); do_check_false("error" in aPacket); do_check_eq(aPacket.from, aThreadActor); do_check_eq(aPacket.type, "paused"); do_check_true("actor" in aPacket); do_check_true("why" in aPacket); do_check_eq(aPacket.why.type, "debuggerStatement"); // Reach around the protocol to check that the debuggee is in the state // we expect. do_check_true(gDebuggee.a); do_check_false(gDebuggee.b); do_check_eq(xpcInspector.eventLoopNestLevel, 1); // Let the debuggee continue execution. gClient.request({ to: aThreadActor, type: "resume" }, cleanup); }); } function cleanup() { gClient.addListener("closed", function (aEvent, aResult) { do_test_finished(); }); try { let xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector); do_check_eq(xpcInspector.eventLoopNestLevel, 0); } catch (e) { dump(e); } gClient.close(); }