summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/unit/test_dbgactor.js
blob: b22b8446ba48bac1d8f721dd1024d3e376bff5ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* 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();
}