toolkit/devtools/server/tests/unit/head_dbg.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 3
michael@0 4 "use strict";
michael@0 5 const Cc = Components.classes;
michael@0 6 const Ci = Components.interfaces;
michael@0 7 const Cu = Components.utils;
michael@0 8 const Cr = Components.results;
michael@0 9
michael@0 10 const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
michael@0 11 const Services = devtools.require("Services");
michael@0 12 const { ActorPool, createExtraActors, appendExtraActors } = devtools.require("devtools/server/actors/common");
michael@0 13 const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js");
michael@0 14 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
michael@0 15
michael@0 16 // Always log packets when running tests. runxpcshelltests.py will throw
michael@0 17 // the output away anyway, unless you give it the --verbose flag.
michael@0 18 Services.prefs.setBoolPref("devtools.debugger.log", true);
michael@0 19 // Enable remote debugging for the relevant tests.
michael@0 20 Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
michael@0 21
michael@0 22 function tryImport(url) {
michael@0 23 try {
michael@0 24 Cu.import(url);
michael@0 25 } catch (e) {
michael@0 26 dump("Error importing " + url + "\n");
michael@0 27 dump(DevToolsUtils.safeErrorString(e) + "\n");
michael@0 28 throw e;
michael@0 29 }
michael@0 30 }
michael@0 31
michael@0 32 tryImport("resource://gre/modules/devtools/dbg-server.jsm");
michael@0 33 tryImport("resource://gre/modules/devtools/dbg-client.jsm");
michael@0 34 tryImport("resource://gre/modules/devtools/Loader.jsm");
michael@0 35 tryImport("resource://gre/modules/devtools/Console.jsm");
michael@0 36
michael@0 37 function testExceptionHook(ex) {
michael@0 38 try {
michael@0 39 do_report_unexpected_exception(ex);
michael@0 40 } catch(ex) {
michael@0 41 return {throw: ex}
michael@0 42 }
michael@0 43 return undefined;
michael@0 44 }
michael@0 45
michael@0 46 // Convert an nsIScriptError 'aFlags' value into an appropriate string.
michael@0 47 function scriptErrorFlagsToKind(aFlags) {
michael@0 48 var kind;
michael@0 49 if (aFlags & Ci.nsIScriptError.warningFlag)
michael@0 50 kind = "warning";
michael@0 51 if (aFlags & Ci.nsIScriptError.exceptionFlag)
michael@0 52 kind = "exception";
michael@0 53 else
michael@0 54 kind = "error";
michael@0 55
michael@0 56 if (aFlags & Ci.nsIScriptError.strictFlag)
michael@0 57 kind = "strict " + kind;
michael@0 58
michael@0 59 return kind;
michael@0 60 }
michael@0 61
michael@0 62 // Redeclare dbg_assert with a fatal behavior.
michael@0 63 function dbg_assert(cond, e) {
michael@0 64 if (!cond) {
michael@0 65 throw e;
michael@0 66 }
michael@0 67 }
michael@0 68
michael@0 69 // Register a console listener, so console messages don't just disappear
michael@0 70 // into the ether.
michael@0 71 let errorCount = 0;
michael@0 72 let listener = {
michael@0 73 observe: function (aMessage) {
michael@0 74 errorCount++;
michael@0 75 try {
michael@0 76 // If we've been given an nsIScriptError, then we can print out
michael@0 77 // something nicely formatted, for tools like Emacs to pick up.
michael@0 78 var scriptError = aMessage.QueryInterface(Ci.nsIScriptError);
michael@0 79 dump(aMessage.sourceName + ":" + aMessage.lineNumber + ": " +
michael@0 80 scriptErrorFlagsToKind(aMessage.flags) + ": " +
michael@0 81 aMessage.errorMessage + "\n");
michael@0 82 var string = aMessage.errorMessage;
michael@0 83 } catch (x) {
michael@0 84 // Be a little paranoid with message, as the whole goal here is to lose
michael@0 85 // no information.
michael@0 86 try {
michael@0 87 var string = "" + aMessage.message;
michael@0 88 } catch (x) {
michael@0 89 var string = "<error converting error message to string>";
michael@0 90 }
michael@0 91 }
michael@0 92
michael@0 93 // Make sure we exit all nested event loops so that the test can finish.
michael@0 94 while (DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
michael@0 95 DebuggerServer.xpcInspector.exitNestedEventLoop();
michael@0 96 }
michael@0 97 do_throw("head_dbg.js got console message: " + string + "\n");
michael@0 98 }
michael@0 99 };
michael@0 100
michael@0 101 let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
michael@0 102 consoleService.registerListener(listener);
michael@0 103
michael@0 104 function check_except(func)
michael@0 105 {
michael@0 106 try {
michael@0 107 func();
michael@0 108 } catch (e) {
michael@0 109 do_check_true(true);
michael@0 110 return;
michael@0 111 }
michael@0 112 dump("Should have thrown an exception: " + func.toString());
michael@0 113 do_check_true(false);
michael@0 114 }
michael@0 115
michael@0 116 function testGlobal(aName) {
michael@0 117 let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
michael@0 118 .createInstance(Ci.nsIPrincipal);
michael@0 119
michael@0 120 let sandbox = Cu.Sandbox(systemPrincipal);
michael@0 121 sandbox.__name = aName;
michael@0 122 return sandbox;
michael@0 123 }
michael@0 124
michael@0 125 function addTestGlobal(aName)
michael@0 126 {
michael@0 127 let global = testGlobal(aName);
michael@0 128 DebuggerServer.addTestGlobal(global);
michael@0 129 return global;
michael@0 130 }
michael@0 131
michael@0 132 // List the DebuggerClient |aClient|'s tabs, look for one whose title is
michael@0 133 // |aTitle|, and apply |aCallback| to the packet's entry for that tab.
michael@0 134 function getTestTab(aClient, aTitle, aCallback) {
michael@0 135 aClient.listTabs(function (aResponse) {
michael@0 136 for (let tab of aResponse.tabs) {
michael@0 137 if (tab.title === aTitle) {
michael@0 138 aCallback(tab);
michael@0 139 return;
michael@0 140 }
michael@0 141 }
michael@0 142 aCallback(null);
michael@0 143 });
michael@0 144 }
michael@0 145
michael@0 146 // Attach to |aClient|'s tab whose title is |aTitle|; pass |aCallback| the
michael@0 147 // response packet and a TabClient instance referring to that tab.
michael@0 148 function attachTestTab(aClient, aTitle, aCallback) {
michael@0 149 getTestTab(aClient, aTitle, function (aTab) {
michael@0 150 aClient.attachTab(aTab.actor, aCallback);
michael@0 151 });
michael@0 152 }
michael@0 153
michael@0 154 // Attach to |aClient|'s tab whose title is |aTitle|, and then attach to
michael@0 155 // that tab's thread. Pass |aCallback| the thread attach response packet, a
michael@0 156 // TabClient referring to the tab, and a ThreadClient referring to the
michael@0 157 // thread.
michael@0 158 function attachTestThread(aClient, aTitle, aCallback) {
michael@0 159 attachTestTab(aClient, aTitle, function (aResponse, aTabClient) {
michael@0 160 function onAttach(aResponse, aThreadClient) {
michael@0 161 aCallback(aResponse, aTabClient, aThreadClient);
michael@0 162 }
michael@0 163 aTabClient.attachThread({ useSourceMaps: true }, onAttach);
michael@0 164 });
michael@0 165 }
michael@0 166
michael@0 167 // Attach to |aClient|'s tab whose title is |aTitle|, attach to the tab's
michael@0 168 // thread, and then resume it. Pass |aCallback| the thread's response to
michael@0 169 // the 'resume' packet, a TabClient for the tab, and a ThreadClient for the
michael@0 170 // thread.
michael@0 171 function attachTestTabAndResume(aClient, aTitle, aCallback) {
michael@0 172 attachTestThread(aClient, aTitle, function(aResponse, aTabClient, aThreadClient) {
michael@0 173 aThreadClient.resume(function (aResponse) {
michael@0 174 aCallback(aResponse, aTabClient, aThreadClient);
michael@0 175 });
michael@0 176 });
michael@0 177 }
michael@0 178
michael@0 179 /**
michael@0 180 * Initialize the testing debugger server.
michael@0 181 */
michael@0 182 function initTestDebuggerServer()
michael@0 183 {
michael@0 184 DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/root.js");
michael@0 185 DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/script.js");
michael@0 186 DebuggerServer.addActors("resource://test/testactors.js");
michael@0 187 // Allow incoming connections.
michael@0 188 DebuggerServer.init(function () { return true; });
michael@0 189 }
michael@0 190
michael@0 191 function initTestTracerServer()
michael@0 192 {
michael@0 193 DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/root.js");
michael@0 194 DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/script.js");
michael@0 195 DebuggerServer.addActors("resource://test/testactors.js");
michael@0 196 DebuggerServer.registerModule("devtools/server/actors/tracer");
michael@0 197 // Allow incoming connections.
michael@0 198 DebuggerServer.init(function () { return true; });
michael@0 199 }
michael@0 200
michael@0 201 function finishClient(aClient)
michael@0 202 {
michael@0 203 aClient.close(function() {
michael@0 204 do_test_finished();
michael@0 205 });
michael@0 206 }
michael@0 207
michael@0 208 /**
michael@0 209 * Takes a relative file path and returns the absolute file url for it.
michael@0 210 */
michael@0 211 function getFileUrl(aName, aAllowMissing=false) {
michael@0 212 let file = do_get_file(aName, aAllowMissing);
michael@0 213 return Services.io.newFileURI(file).spec;
michael@0 214 }
michael@0 215
michael@0 216 /**
michael@0 217 * Returns the full path of the file with the specified name in a
michael@0 218 * platform-independent and URL-like form.
michael@0 219 */
michael@0 220 function getFilePath(aName, aAllowMissing=false)
michael@0 221 {
michael@0 222 let file = do_get_file(aName, aAllowMissing);
michael@0 223 let path = Services.io.newFileURI(file).spec;
michael@0 224 let filePrePath = "file://";
michael@0 225 if ("nsILocalFileWin" in Ci &&
michael@0 226 file instanceof Ci.nsILocalFileWin) {
michael@0 227 filePrePath += "/";
michael@0 228 }
michael@0 229 return path.slice(filePrePath.length);
michael@0 230 }
michael@0 231
michael@0 232 Cu.import("resource://gre/modules/NetUtil.jsm");
michael@0 233
michael@0 234 /**
michael@0 235 * Returns the full text contents of the given file.
michael@0 236 */
michael@0 237 function readFile(aFileName) {
michael@0 238 let f = do_get_file(aFileName);
michael@0 239 let s = Cc["@mozilla.org/network/file-input-stream;1"]
michael@0 240 .createInstance(Ci.nsIFileInputStream);
michael@0 241 s.init(f, -1, -1, false);
michael@0 242 try {
michael@0 243 return NetUtil.readInputStreamToString(s, s.available());
michael@0 244 } finally {
michael@0 245 s.close();
michael@0 246 }
michael@0 247 }
michael@0 248
michael@0 249 function writeFile(aFileName, aContent) {
michael@0 250 let file = do_get_file(aFileName, true);
michael@0 251 let stream = Cc["@mozilla.org/network/file-output-stream;1"]
michael@0 252 .createInstance(Ci.nsIFileOutputStream);
michael@0 253 stream.init(file, -1, -1, 0);
michael@0 254 try {
michael@0 255 do {
michael@0 256 let numWritten = stream.write(aContent, aContent.length);
michael@0 257 aContent = aContent.slice(numWritten);
michael@0 258 } while (aContent.length > 0);
michael@0 259 } finally {
michael@0 260 stream.close();
michael@0 261 }
michael@0 262 }
michael@0 263
michael@0 264 function connectPipeTracing() {
michael@0 265 return new TracingTransport(DebuggerServer.connectPipe());
michael@0 266 }
michael@0 267
michael@0 268 function TracingTransport(childTransport) {
michael@0 269 this.hooks = null;
michael@0 270 this.child = childTransport;
michael@0 271 this.child.hooks = this;
michael@0 272
michael@0 273 this.expectations = [];
michael@0 274 this.packets = [];
michael@0 275 this.checkIndex = 0;
michael@0 276 }
michael@0 277
michael@0 278 function deepEqual(a, b) {
michael@0 279 if (a === b)
michael@0 280 return true;
michael@0 281 if (typeof a != "object" || typeof b != "object")
michael@0 282 return false;
michael@0 283 if (a === null || b === null)
michael@0 284 return false;
michael@0 285 if (Object.keys(a).length != Object.keys(b).length)
michael@0 286 return false;
michael@0 287 for (let k in a) {
michael@0 288 if (!deepEqual(a[k], b[k]))
michael@0 289 return false;
michael@0 290 }
michael@0 291 return true;
michael@0 292 }
michael@0 293
michael@0 294 TracingTransport.prototype = {
michael@0 295 // Remove actor names
michael@0 296 normalize: function(packet) {
michael@0 297 return JSON.parse(JSON.stringify(packet, (key, value) => {
michael@0 298 if (key === "to" || key === "from" || key === "actor") {
michael@0 299 return "<actorid>";
michael@0 300 }
michael@0 301 return value;
michael@0 302 }));
michael@0 303 },
michael@0 304 send: function(packet) {
michael@0 305 this.packets.push({
michael@0 306 type: "sent",
michael@0 307 packet: this.normalize(packet)
michael@0 308 });
michael@0 309 return this.child.send(packet);
michael@0 310 },
michael@0 311 close: function() {
michael@0 312 return this.child.close();
michael@0 313 },
michael@0 314 ready: function() {
michael@0 315 return this.child.ready();
michael@0 316 },
michael@0 317 onPacket: function(packet) {
michael@0 318 this.packets.push({
michael@0 319 type: "received",
michael@0 320 packet: this.normalize(packet)
michael@0 321 });
michael@0 322 this.hooks.onPacket(packet);
michael@0 323 },
michael@0 324 onClosed: function() {
michael@0 325 this.hooks.onClosed();
michael@0 326 },
michael@0 327
michael@0 328 expectSend: function(expected) {
michael@0 329 let packet = this.packets[this.checkIndex++];
michael@0 330 do_check_eq(packet.type, "sent");
michael@0 331 do_check_true(deepEqual(packet.packet, this.normalize(expected)));
michael@0 332 },
michael@0 333
michael@0 334 expectReceive: function(expected) {
michael@0 335 let packet = this.packets[this.checkIndex++];
michael@0 336 do_check_eq(packet.type, "received");
michael@0 337 do_check_true(deepEqual(packet.packet, this.normalize(expected)));
michael@0 338 },
michael@0 339
michael@0 340 // Write your tests, call dumpLog at the end, inspect the output,
michael@0 341 // then sprinkle the calls through the right places in your test.
michael@0 342 dumpLog: function() {
michael@0 343 for (let entry of this.packets) {
michael@0 344 if (entry.type === "sent") {
michael@0 345 dump("trace.expectSend(" + entry.packet + ");\n");
michael@0 346 } else {
michael@0 347 dump("trace.expectReceive(" + entry.packet + ");\n");
michael@0 348 }
michael@0 349 }
michael@0 350 }
michael@0 351 };
michael@0 352
michael@0 353 function StubTransport() { }
michael@0 354 StubTransport.prototype.ready = function () {};
michael@0 355 StubTransport.prototype.send = function () {};
michael@0 356 StubTransport.prototype.close = function () {};
michael@0 357
michael@0 358 function executeSoon(aFunc) {
michael@0 359 Services.tm.mainThread.dispatch({
michael@0 360 run: DevToolsUtils.makeInfallible(aFunc)
michael@0 361 }, Ci.nsIThread.DISPATCH_NORMAL);
michael@0 362 }

mercurial