import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,6 @@
"use strict";
module.exports = {
// Extend from the common devtools xpcshell eslintrc config.
"extends": "../../../.eslintrc.xpcshell.js"
};

View file

@ -0,0 +1,10 @@
{
"manifest_version": 2,
"name": "Test Addons Actor Upgrade",
"version": "1.0",
"applications": {
"gecko": {
"id": "test-addons-actor@mozilla.org"
}
}
}

View file

@ -0,0 +1,10 @@
{
"manifest_version": 2,
"name": "Test Addons Actor",
"version": "1.0",
"applications": {
"gecko": {
"id": "test-addons-actor@mozilla.org"
}
}
}

View file

@ -0,0 +1,10 @@
{
"manifest_version": 2,
"name": "Test Addons Actor 2",
"version": "1.0",
"applications": {
"gecko": {
"id": "test-addons-actor2@mozilla.org"
}
}
}

View file

@ -0,0 +1,79 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";
var add = require("./lib/add");
var subtract = require("./lib/subtract");
var upperCase = require("upper-case");
(function () {
return add(1, 2);
});
},{"./lib/add":2,"./lib/subtract":3,"upper-case":4}],2:[function(require,module,exports){
"use strict";
module.exports = function (a, b) {
return a + b;
};
},{}],3:[function(require,module,exports){
"use strict";
module.exports = function (a, b) {
return a - b;
};
},{}],4:[function(require,module,exports){
/**
* Special language-specific overrides.
*
* Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
*
* @type {Object}
*/
var LANGUAGES = {
tr: {
regexp: /[\u0069]/g,
map: {
'\u0069': '\u0130'
}
},
az: {
regexp: /[\u0069]/g,
map: {
'\u0069': '\u0130'
}
},
lt: {
regexp: /[\u0069\u006A\u012F]\u0307|\u0069\u0307[\u0300\u0301\u0303]/g,
map: {
'\u0069\u0307': '\u0049',
'\u006A\u0307': '\u004A',
'\u012F\u0307': '\u012E',
'\u0069\u0307\u0300': '\u00CC',
'\u0069\u0307\u0301': '\u00CD',
'\u0069\u0307\u0303': '\u0128'
}
}
}
/**
* Upper case a string.
*
* @param {String} str
* @return {String}
*/
module.exports = function (str, locale) {
var lang = LANGUAGES[locale]
str = str == null ? '' : String(str)
if (lang) {
str = str.replace(lang.regexp, function (m) { return lang.map[m] })
}
return str.toUpperCase()
}
},{}]},{},[1])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi9Vc2Vycy9qc2FudGVsbC9EZXYvc291cmNlLW1hcC10ZXN0L2luZGV4LmpzIiwiL1VzZXJzL2pzYW50ZWxsL0Rldi9zb3VyY2UtbWFwLXRlc3QvbGliL2FkZC5qcyIsIi9Vc2Vycy9qc2FudGVsbC9EZXYvc291cmNlLW1hcC10ZXN0L2xpYi9zdWJ0cmFjdC5qcyIsIm5vZGVfbW9kdWxlcy91cHBlci1jYXNlL3VwcGVyLWNhc2UuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztBQ0FBLElBQUksR0FBRyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUMvQixJQUFJLFFBQVEsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUN6QyxJQUFJLFNBQVMsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7O0FBRXRDLENBQUM7U0FBTSxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztFQUFBLENBQUU7Ozs7O0FDSmpCLE1BQU0sQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0FBQy9CLFNBQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztDQUNkLENBQUM7Ozs7O0FDRkYsTUFBTSxDQUFDLE9BQU8sR0FBRyxVQUFVLENBQUMsRUFBRSxDQUFDLEVBQUU7QUFDL0IsU0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0NBQ2QsQ0FBQzs7O0FDRkY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsInZhciBhZGQgPSByZXF1aXJlKFwiLi9saWIvYWRkXCIpO1xudmFyIHN1YnRyYWN0ID0gcmVxdWlyZShcIi4vbGliL3N1YnRyYWN0XCIpO1xudmFyIHVwcGVyQ2FzZSA9IHJlcXVpcmUoXCJ1cHBlci1jYXNlXCIpO1xuXG4oKCkgPT4gYWRkKDEsMikpO1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYSwgYikge1xuICByZXR1cm4gYSArIGI7XG59O1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYSwgYikge1xuICByZXR1cm4gYSAtIGI7XG59O1xuIiwiLyoqXG4gKiBTcGVjaWFsIGxhbmd1YWdlLXNwZWNpZmljIG92ZXJyaWRlcy5cbiAqXG4gKiBTb3VyY2U6IGZ0cDovL2Z0cC51bmljb2RlLm9yZy9QdWJsaWMvVUNEL2xhdGVzdC91Y2QvU3BlY2lhbENhc2luZy50eHRcbiAqXG4gKiBAdHlwZSB7T2JqZWN0fVxuICovXG52YXIgTEFOR1VBR0VTID0ge1xuICB0cjoge1xuICAgIHJlZ2V4cDogL1tcXHUwMDY5XS9nLFxuICAgIG1hcDoge1xuICAgICAgJ1xcdTAwNjknOiAnXFx1MDEzMCdcbiAgICB9XG4gIH0sXG4gIGF6OiB7XG4gICAgcmVnZXhwOiAvW1xcdTAwNjldL2csXG4gICAgbWFwOiB7XG4gICAgICAnXFx1MDA2OSc6ICdcXHUwMTMwJ1xuICAgIH1cbiAgfSxcbiAgbHQ6IHtcbiAgICByZWdleHA6IC9bXFx1MDA2OVxcdTAwNkFcXHUwMTJGXVxcdTAzMDd8XFx1MDA2OVxcdTAzMDdbXFx1MDMwMFxcdTAzMDFcXHUwMzAzXS9nLFxuICAgIG1hcDoge1xuICAgICAgJ1xcdTAwNjlcXHUwMzA3JzogJ1xcdTAwNDknLFxuICAgICAgJ1xcdTAwNkFcXHUwMzA3JzogJ1xcdTAwNEEnLFxuICAgICAgJ1xcdTAxMkZcXHUwMzA3JzogJ1xcdTAxMkUnLFxuICAgICAgJ1xcdTAwNjlcXHUwMzA3XFx1MDMwMCc6ICdcXHUwMENDJyxcbiAgICAgICdcXHUwMDY5XFx1MDMwN1xcdTAzMDEnOiAnXFx1MDBDRCcsXG4gICAgICAnXFx1MDA2OVxcdTAzMDdcXHUwMzAzJzogJ1xcdTAxMjgnXG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogVXBwZXIgY2FzZSBhIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHN0clxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChzdHIsIGxvY2FsZSkge1xuICB2YXIgbGFuZyA9IExBTkdVQUdFU1tsb2NhbGVdXG5cbiAgc3RyID0gc3RyID09IG51bGwgPyAnJyA6IFN0cmluZyhzdHIpXG5cbiAgaWYgKGxhbmcpIHtcbiAgICBzdHIgPSBzdHIucmVwbGFjZShsYW5nLnJlZ2V4cCwgZnVuY3Rpb24gKG0pIHsgcmV0dXJuIGxhbmcubWFwW21dIH0pXG4gIH1cblxuICByZXR1cm4gc3RyLnRvVXBwZXJDYXNlKClcbn1cbiJdfQ==

View file

@ -0,0 +1,862 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
var CC = Components.Constructor;
// Populate AppInfo before anything (like the shared loader) accesses
// System.appinfo, which is a lazy getter.
const _appInfo = {};
Cu.import("resource://testing-common/AppInfo.jsm", _appInfo);
_appInfo.updateAppInfo({
ID: "devtools@tests.mozilla.org",
name: "devtools-tests",
version: "1",
platformVersion: "42",
crashReporter: true,
});
const { require, loader } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { worker } = Cu.import("resource://devtools/shared/worker/loader.js", {});
const promise = require("promise");
const { Task } = require("devtools/shared/task");
const { console } = require("resource://gre/modules/Console.jsm");
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
const Services = require("Services");
// Always log packets when running tests. runxpcshelltests.py will throw
// the output away anyway, unless you give it the --verbose flag.
Services.prefs.setBoolPref("devtools.debugger.log", true);
// Enable remote debugging for the relevant tests.
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const { DebuggerServer } = require("devtools/server/main");
const { DebuggerServer: WorkerDebuggerServer } = worker.require("devtools/server/main");
const { DebuggerClient, ObjectClient } = require("devtools/shared/client/main");
const { MemoryFront } = require("devtools/shared/fronts/memory");
const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
const systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
var loadSubScript = Cc[
"@mozilla.org/moz/jssubscript-loader;1"
].getService(Ci.mozIJSSubScriptLoader).loadSubScript;
/**
* Initializes any test that needs to work with add-ons.
*/
function startupAddonsManager() {
// Create a directory for extensions.
const profileDir = do_get_profile().clone();
profileDir.append("extensions");
const internalManager = Cc["@mozilla.org/addons/integration;1"]
.getService(Ci.nsIObserver)
.QueryInterface(Ci.nsITimerCallback);
internalManager.observe(null, "addons-startup", null);
}
/**
* Create a `run_test` function that runs the given generator in a task after
* having attached to a memory actor. When done, the memory actor is detached
* from, the client is finished, and the test is finished.
*
* @param {GeneratorFunction} testGeneratorFunction
* The generator function is passed (DebuggerClient, MemoryFront)
* arguments.
*
* @returns `run_test` function
*/
function makeMemoryActorTest(testGeneratorFunction) {
const TEST_GLOBAL_NAME = "test_MemoryActor";
return function run_test() {
do_test_pending();
startTestDebuggerServer(TEST_GLOBAL_NAME).then(client => {
DebuggerServer.registerModule("devtools/server/actors/heap-snapshot-file", {
prefix: "heapSnapshotFile",
constructor: "HeapSnapshotFileActor",
type: { global: true }
});
getTestTab(client, TEST_GLOBAL_NAME, function (tabForm, rootForm) {
if (!tabForm || !rootForm) {
ok(false, "Could not attach to test tab: " + TEST_GLOBAL_NAME);
return;
}
Task.spawn(function* () {
try {
const memoryFront = new MemoryFront(client, tabForm, rootForm);
yield memoryFront.attach();
yield* testGeneratorFunction(client, memoryFront);
yield memoryFront.detach();
} catch (err) {
DevToolsUtils.reportException("makeMemoryActorTest", err);
ok(false, "Got an error: " + err);
}
finishClient(client);
});
});
});
};
}
/**
* Save as makeMemoryActorTest but attaches the MemoryFront to the MemoryActor
* scoped to the full runtime rather than to a tab.
*/
function makeFullRuntimeMemoryActorTest(testGeneratorFunction) {
return function run_test() {
do_test_pending();
startTestDebuggerServer("test_MemoryActor").then(client => {
DebuggerServer.registerModule("devtools/server/actors/heap-snapshot-file", {
prefix: "heapSnapshotFile",
constructor: "HeapSnapshotFileActor",
type: { global: true }
});
getChromeActors(client).then(function (form) {
if (!form) {
ok(false, "Could not attach to chrome actors");
return;
}
Task.spawn(function* () {
try {
const rootForm = yield listTabs(client);
const memoryFront = new MemoryFront(client, form, rootForm);
yield memoryFront.attach();
yield* testGeneratorFunction(client, memoryFront);
yield memoryFront.detach();
} catch (err) {
DevToolsUtils.reportException("makeMemoryActorTest", err);
ok(false, "Got an error: " + err);
}
finishClient(client);
});
});
});
};
}
function createTestGlobal(name) {
let sandbox = Cu.Sandbox(
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
);
sandbox.__name = name;
return sandbox;
}
function connect(client) {
dump("Connecting client.\n");
return client.connect();
}
function close(client) {
dump("Closing client.\n");
return client.close();
}
function listTabs(client) {
dump("Listing tabs.\n");
return client.listTabs();
}
function findTab(tabs, title) {
dump("Finding tab with title '" + title + "'.\n");
for (let tab of tabs) {
if (tab.title === title) {
return tab;
}
}
return null;
}
function attachTab(client, tab) {
dump("Attaching to tab with title '" + tab.title + "'.\n");
return client.attachTab(tab.actor);
}
function waitForNewSource(threadClient, url) {
dump("Waiting for new source with url '" + url + "'.\n");
return waitForEvent(threadClient, "newSource", function (packet) {
return packet.source.url === url;
});
}
function attachThread(tabClient, options = {}) {
dump("Attaching to thread.\n");
return tabClient.attachThread(options);
}
function resume(threadClient) {
dump("Resuming thread.\n");
return threadClient.resume();
}
function getSources(threadClient) {
dump("Getting sources.\n");
return threadClient.getSources();
}
function findSource(sources, url) {
dump("Finding source with url '" + url + "'.\n");
for (let source of sources) {
if (source.url === url) {
return source;
}
}
return null;
}
function waitForPause(threadClient) {
dump("Waiting for pause.\n");
return waitForEvent(threadClient, "paused");
}
function setBreakpoint(sourceClient, location) {
dump("Setting breakpoint.\n");
return sourceClient.setBreakpoint(location);
}
function dumpn(msg) {
dump("DBG-TEST: " + msg + "\n");
}
function testExceptionHook(ex) {
try {
do_report_unexpected_exception(ex);
} catch (ex) {
return {throw: ex};
}
return undefined;
}
// Convert an nsIScriptError 'aFlags' value into an appropriate string.
function scriptErrorFlagsToKind(aFlags) {
var kind;
if (aFlags & Ci.nsIScriptError.warningFlag)
kind = "warning";
if (aFlags & Ci.nsIScriptError.exceptionFlag)
kind = "exception";
else
kind = "error";
if (aFlags & Ci.nsIScriptError.strictFlag)
kind = "strict " + kind;
return kind;
}
// Register a console listener, so console messages don't just disappear
// into the ether.
var errorCount = 0;
var listener = {
observe: function (aMessage) {
try {
errorCount++;
try {
// If we've been given an nsIScriptError, then we can print out
// something nicely formatted, for tools like Emacs to pick up.
var scriptError = aMessage.QueryInterface(Ci.nsIScriptError);
dumpn(aMessage.sourceName + ":" + aMessage.lineNumber + ": " +
scriptErrorFlagsToKind(aMessage.flags) + ": " +
aMessage.errorMessage);
var string = aMessage.errorMessage;
} catch (x) {
// Be a little paranoid with message, as the whole goal here is to lose
// no information.
try {
var string = "" + aMessage.message;
} catch (x) {
var string = "<error converting error message to string>";
}
}
// Make sure we exit all nested event loops so that the test can finish.
while (DebuggerServer
&& DebuggerServer.xpcInspector
&& DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
DebuggerServer.xpcInspector.exitNestedEventLoop();
}
// In the world before bug 997440, exceptions were getting lost because of
// the arbitrary JSContext being used in nsXPCWrappedJSClass::CallMethod.
// In the new world, the wanderers have returned. However, because of the,
// currently very-broken, exception reporting machinery in
// XPCWrappedJSClass these get reported as errors to the console, even if
// there's actually JS on the stack above that will catch them. If we
// throw an error here because of them our tests start failing. So, we'll
// just dump the message to the logs instead, to make sure the information
// isn't lost.
dumpn("head_dbg.js observed a console message: " + string);
} catch (_) {
// Swallow everything to avoid console reentrancy errors. We did our best
// to log above, but apparently that didn't cut it.
}
}
};
var consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.registerListener(listener);
function check_except(func)
{
try {
func();
} catch (e) {
do_check_true(true);
return;
}
dumpn("Should have thrown an exception: " + func.toString());
do_check_true(false);
}
function testGlobal(aName) {
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
.createInstance(Ci.nsIPrincipal);
let sandbox = Cu.Sandbox(systemPrincipal);
sandbox.__name = aName;
return sandbox;
}
function addTestGlobal(aName, aServer = DebuggerServer)
{
let global = testGlobal(aName);
aServer.addTestGlobal(global);
return global;
}
// List the DebuggerClient |aClient|'s tabs, look for one whose title is
// |aTitle|, and apply |aCallback| to the packet's entry for that tab.
function getTestTab(aClient, aTitle, aCallback) {
aClient.listTabs(function (aResponse) {
for (let tab of aResponse.tabs) {
if (tab.title === aTitle) {
aCallback(tab, aResponse);
return;
}
}
aCallback(null);
});
}
// Attach to |aClient|'s tab whose title is |aTitle|; pass |aCallback| the
// response packet and a TabClient instance referring to that tab.
function attachTestTab(aClient, aTitle, aCallback) {
getTestTab(aClient, aTitle, function (aTab) {
aClient.attachTab(aTab.actor, aCallback);
});
}
// Attach to |aClient|'s tab whose title is |aTitle|, and then attach to
// that tab's thread. Pass |aCallback| the thread attach response packet, a
// TabClient referring to the tab, and a ThreadClient referring to the
// thread.
function attachTestThread(aClient, aTitle, aCallback) {
attachTestTab(aClient, aTitle, function (aTabResponse, aTabClient) {
function onAttach(aResponse, aThreadClient) {
aCallback(aResponse, aTabClient, aThreadClient, aTabResponse);
}
aTabClient.attachThread({
useSourceMaps: true,
autoBlackBox: true
}, onAttach);
});
}
// Attach to |aClient|'s tab whose title is |aTitle|, attach to the tab's
// thread, and then resume it. Pass |aCallback| the thread's response to
// the 'resume' packet, a TabClient for the tab, and a ThreadClient for the
// thread.
function attachTestTabAndResume(aClient, aTitle, aCallback = () => {}) {
return new Promise((resolve, reject) => {
attachTestThread(aClient, aTitle, function (aResponse, aTabClient, aThreadClient) {
aThreadClient.resume(function (aResponse) {
aCallback(aResponse, aTabClient, aThreadClient);
resolve([aResponse, aTabClient, aThreadClient]);
});
});
});
}
/**
* Initialize the testing debugger server.
*/
function initTestDebuggerServer(aServer = DebuggerServer)
{
aServer.registerModule("xpcshell-test/testactors");
// Allow incoming connections.
aServer.init(function () { return true; });
}
/**
* Initialize the testing debugger server with a tab whose title is |title|.
*/
function startTestDebuggerServer(title, server = DebuggerServer) {
initTestDebuggerServer(server);
addTestGlobal(title);
DebuggerServer.addTabActors();
let transport = DebuggerServer.connectPipe();
let client = new DebuggerClient(transport);
return connect(client).then(() => client);
}
function finishClient(aClient)
{
aClient.close(function () {
DebuggerServer.destroy();
do_test_finished();
});
}
// Create a server, connect to it and fetch tab actors for the parent process;
// pass |aCallback| the debugger client and tab actor form with all actor IDs.
function get_chrome_actors(callback)
{
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.allowChromeProcess = true;
let client = new DebuggerClient(DebuggerServer.connectPipe());
client.connect()
.then(() => client.getProcess())
.then(response => {
callback(client, response.form);
});
}
function getChromeActors(client, server = DebuggerServer) {
server.allowChromeProcess = true;
return client.getProcess().then(response => response.form);
}
/**
* Takes a relative file path and returns the absolute file url for it.
*/
function getFileUrl(aName, aAllowMissing = false) {
let file = do_get_file(aName, aAllowMissing);
return Services.io.newFileURI(file).spec;
}
/**
* Returns the full path of the file with the specified name in a
* platform-independent and URL-like form.
*/
function getFilePath(aName, aAllowMissing = false, aUsePlatformPathSeparator = false)
{
let file = do_get_file(aName, aAllowMissing);
let path = Services.io.newFileURI(file).spec;
let filePrePath = "file://";
if ("nsILocalFileWin" in Ci &&
file instanceof Ci.nsILocalFileWin) {
filePrePath += "/";
}
path = path.slice(filePrePath.length);
if (aUsePlatformPathSeparator && path.match(/^\w:/)) {
path = path.replace(/\//g, "\\");
}
return path;
}
/**
* Returns the full text contents of the given file.
*/
function readFile(aFileName) {
let f = do_get_file(aFileName);
let s = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
s.init(f, -1, -1, false);
try {
return NetUtil.readInputStreamToString(s, s.available());
} finally {
s.close();
}
}
function writeFile(aFileName, aContent) {
let file = do_get_file(aFileName, true);
let stream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
stream.init(file, -1, -1, 0);
try {
do {
let numWritten = stream.write(aContent, aContent.length);
aContent = aContent.slice(numWritten);
} while (aContent.length > 0);
} finally {
stream.close();
}
}
function connectPipeTracing() {
return new TracingTransport(DebuggerServer.connectPipe());
}
function TracingTransport(childTransport) {
this.hooks = null;
this.child = childTransport;
this.child.hooks = this;
this.expectations = [];
this.packets = [];
this.checkIndex = 0;
}
TracingTransport.prototype = {
// Remove actor names
normalize: function (packet) {
return JSON.parse(JSON.stringify(packet, (key, value) => {
if (key === "to" || key === "from" || key === "actor") {
return "<actorid>";
}
return value;
}));
},
send: function (packet) {
this.packets.push({
type: "sent",
packet: this.normalize(packet)
});
return this.child.send(packet);
},
close: function () {
return this.child.close();
},
ready: function () {
return this.child.ready();
},
onPacket: function (packet) {
this.packets.push({
type: "received",
packet: this.normalize(packet)
});
this.hooks.onPacket(packet);
},
onClosed: function () {
this.hooks.onClosed();
},
expectSend: function (expected) {
let packet = this.packets[this.checkIndex++];
do_check_eq(packet.type, "sent");
deepEqual(packet.packet, this.normalize(expected));
},
expectReceive: function (expected) {
let packet = this.packets[this.checkIndex++];
do_check_eq(packet.type, "received");
deepEqual(packet.packet, this.normalize(expected));
},
// Write your tests, call dumpLog at the end, inspect the output,
// then sprinkle the calls through the right places in your test.
dumpLog: function () {
for (let entry of this.packets) {
if (entry.type === "sent") {
dumpn("trace.expectSend(" + entry.packet + ");");
} else {
dumpn("trace.expectReceive(" + entry.packet + ");");
}
}
}
};
function StubTransport() { }
StubTransport.prototype.ready = function () {};
StubTransport.prototype.send = function () {};
StubTransport.prototype.close = function () {};
function executeSoon(aFunc) {
Services.tm.mainThread.dispatch({
run: DevToolsUtils.makeInfallible(aFunc)
}, Ci.nsIThread.DISPATCH_NORMAL);
}
// The do_check_* family of functions expect their last argument to be an
// optional stack object. Unfortunately, most tests actually pass a in a string
// containing an error message instead, which causes error reporting to break if
// strict warnings as errors is turned on. To avoid this, we wrap these
// functions here below to ensure the correct number of arguments is passed.
//
// TODO: Remove this once bug 906232 is resolved
//
var do_check_true_old = do_check_true;
var do_check_true = function (condition) {
do_check_true_old(condition);
};
var do_check_false_old = do_check_false;
var do_check_false = function (condition) {
do_check_false_old(condition);
};
var do_check_eq_old = do_check_eq;
var do_check_eq = function (left, right) {
do_check_eq_old(left, right);
};
var do_check_neq_old = do_check_neq;
var do_check_neq = function (left, right) {
do_check_neq_old(left, right);
};
var do_check_matches_old = do_check_matches;
var do_check_matches = function (pattern, value) {
do_check_matches_old(pattern, value);
};
// Create async version of the object where calling each method
// is equivalent of calling it with asyncall. Mainly useful for
// destructuring objects with methods that take callbacks.
const Async = target => new Proxy(target, Async);
Async.get = (target, name) =>
typeof (target[name]) === "function" ? asyncall.bind(null, target[name], target) :
target[name];
// Calls async function that takes callback and errorback and returns
// returns promise representing result.
const asyncall = (fn, self, ...args) =>
new Promise((...etc) => fn.call(self, ...args, ...etc));
const Test = task => () => {
add_task(task);
run_next_test();
};
const assert = do_check_true;
/**
* Create a promise that is resolved on the next occurence of the given event.
*
* @param DebuggerClient client
* @param String event
* @param Function predicate
* @returns Promise
*/
function waitForEvent(client, type, predicate) {
return new Promise(function (resolve) {
function listener(type, packet) {
if (!predicate(packet)) {
return;
}
client.removeListener(listener);
resolve(packet);
}
if (predicate) {
client.addListener(type, listener);
} else {
client.addOneTimeListener(type, function (type, packet) {
resolve(packet);
});
}
});
}
/**
* Execute the action on the next tick and return a promise that is resolved on
* the next pause.
*
* When using promises and Task.jsm, we often want to do an action that causes a
* pause and continue the task once the pause has ocurred. Unfortunately, if we
* do the action that causes the pause within the task's current tick we will
* pause before we have a chance to yield the promise that waits for the pause
* and we enter a dead lock. The solution is to create the promise that waits
* for the pause, schedule the action to run on the next tick of the event loop,
* and finally yield the promise.
*
* @param Function action
* @param DebuggerClient client
* @returns Promise
*/
function executeOnNextTickAndWaitForPause(action, client) {
const paused = waitForPause(client);
executeSoon(action);
return paused;
}
/**
* Interrupt JS execution for the specified thread.
*
* @param ThreadClient threadClient
* @returns Promise
*/
function interrupt(threadClient) {
dumpn("Interrupting.");
return threadClient.interrupt();
}
/**
* Resume JS execution for the specified thread and then wait for the next pause
* event.
*
* @param DebuggerClient client
* @param ThreadClient threadClient
* @returns Promise
*/
function resumeAndWaitForPause(client, threadClient) {
const paused = waitForPause(client);
return resume(threadClient).then(() => paused);
}
/**
* Resume JS execution for a single step and wait for the pause after the step
* has been taken.
*
* @param DebuggerClient client
* @param ThreadClient threadClient
* @returns Promise
*/
function stepIn(client, threadClient) {
dumpn("Stepping in.");
const paused = waitForPause(client);
return threadClient.stepIn()
.then(() => paused);
}
/**
* Resume JS execution for a step over and wait for the pause after the step
* has been taken.
*
* @param DebuggerClient client
* @param ThreadClient threadClient
* @returns Promise
*/
function stepOver(client, threadClient) {
dumpn("Stepping over.");
return threadClient.stepOver()
.then(() => waitForPause(client));
}
/**
* Get the list of `count` frames currently on stack, starting at the index
* `first` for the specified thread.
*
* @param ThreadClient threadClient
* @param Number first
* @param Number count
* @returns Promise
*/
function getFrames(threadClient, first, count) {
dumpn("Getting frames.");
return threadClient.getFrames(first, count);
}
/**
* Black box the specified source.
*
* @param SourceClient sourceClient
* @returns Promise
*/
function blackBox(sourceClient) {
dumpn("Black boxing source: " + sourceClient.actor);
return sourceClient.blackBox();
}
/**
* Stop black boxing the specified source.
*
* @param SourceClient sourceClient
* @returns Promise
*/
function unBlackBox(sourceClient) {
dumpn("Un-black boxing source: " + sourceClient.actor);
return sourceClient.unblackBox();
}
/**
* Perform a "source" RDP request with the given SourceClient to get the source
* content and content type.
*
* @param SourceClient sourceClient
* @returns Promise
*/
function getSourceContent(sourceClient) {
dumpn("Getting source content for " + sourceClient.actor);
return sourceClient.source();
}
/**
* Get a source at the specified url.
*
* @param ThreadClient threadClient
* @param string url
* @returns Promise<SourceClient>
*/
function getSource(threadClient, url) {
let deferred = promise.defer();
threadClient.getSources((res) => {
let source = res.sources.filter(function (s) {
return s.url === url;
});
if (source.length) {
deferred.resolve(threadClient.source(source[0]));
}
else {
deferred.reject(new Error("source not found"));
}
});
return deferred.promise;
}
/**
* Do a fake reload which clears the thread debugger
*
* @param TabClient tabClient
* @returns Promise<response>
*/
function reload(tabClient) {
let deferred = promise.defer();
tabClient._reload({}, deferred.resolve);
return deferred.promise;
}
/**
* Returns an array of stack location strings given a thread and a sample.
*
* @param object thread
* @param object sample
* @returns object
*/
function getInflatedStackLocations(thread, sample) {
let stackTable = thread.stackTable;
let frameTable = thread.frameTable;
let stringTable = thread.stringTable;
let SAMPLE_STACK_SLOT = thread.samples.schema.stack;
let STACK_PREFIX_SLOT = stackTable.schema.prefix;
let STACK_FRAME_SLOT = stackTable.schema.frame;
let FRAME_LOCATION_SLOT = frameTable.schema.location;
// Build the stack from the raw data and accumulate the locations in
// an array.
let stackIndex = sample[SAMPLE_STACK_SLOT];
let locations = [];
while (stackIndex !== null) {
let stackEntry = stackTable.data[stackIndex];
let frame = frameTable.data[stackEntry[STACK_FRAME_SLOT]];
locations.push(stringTable[frame[FRAME_LOCATION_SLOT]]);
stackIndex = stackEntry[STACK_PREFIX_SLOT];
}
// The profiler tree is inverted, so reverse the array.
return locations.reverse();
}

View file

@ -0,0 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const protocol = require("devtools/shared/protocol");
const helloSpec = protocol.generateActorSpec({
typeName: "helloActor",
methods: {
hello: {}
}
});
var HelloActor = protocol.ActorClassWithSpec(helloSpec, {
hello: function () {
return;
}
});

View file

@ -0,0 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function PostInitGlobalActor(aConnection) {}
PostInitGlobalActor.prototype = {
actorPrefix: "postInitGlobal",
onPing: function onPing(aRequest) {
return { message: "pong" };
},
};
PostInitGlobalActor.prototype.requestTypes = {
"ping": PostInitGlobalActor.prototype.onPing,
};
DebuggerServer.addGlobalActor(PostInitGlobalActor, "postInitGlobalActor");

View file

@ -0,0 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function PostInitTabActor(aConnection) {}
PostInitTabActor.prototype = {
actorPostfix: "postInitTab",
onPing: function onPing(aRequest) {
return { message: "pong" };
},
};
PostInitTabActor.prototype.requestTypes = {
"ping": PostInitTabActor.prototype.onPing,
};
DebuggerServer.addGlobalActor(PostInitTabActor, "postInitTabActor");

View file

@ -0,0 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function PreInitGlobalActor(aConnection) {}
PreInitGlobalActor.prototype = {
actorPrefix: "preInitGlobal",
onPing: function onPing(aRequest) {
return { message: "pong" };
},
};
PreInitGlobalActor.prototype.requestTypes = {
"ping": PreInitGlobalActor.prototype.onPing,
};
DebuggerServer.addGlobalActor(PreInitGlobalActor, "preInitGlobalActor");

View file

@ -0,0 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function PreInitTabActor(aConnection) {}
PreInitTabActor.prototype = {
actorPrefix: "preInitTab",
onPing: function onPing(aRequest) {
return { message: "pong" };
},
};
PreInitTabActor.prototype.requestTypes = {
"ping": PreInitTabActor.prototype.onPing,
};
DebuggerServer.addGlobalActor(PreInitTabActor, "preInitTabActor");

View file

@ -0,0 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function Actor() {}
exports.register = function (handle) {
handle.addTabActor(Actor, "registeredActor1");
handle.addGlobalActor(Actor, "registeredActor1");
};
exports.unregister = function (handle) {
handle.removeTabActor(Actor);
handle.removeGlobalActor(Actor);
};

View file

@ -0,0 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function Actor() {}
exports.register = function (handle) {
handle.addGlobalActor(Actor, "registeredActor2");
handle.addTabActor(Actor, "registeredActor2");
};
exports.unregister = function (handle) {
handle.removeTabActor(Actor);
handle.removeGlobalActor(Actor);
};

View file

@ -0,0 +1,40 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var {method, RetVal, Actor, ActorClassWithSpec, Front, FrontClassWithSpec,
generateActorSpec} = require("devtools/shared/protocol");
var Services = require("Services");
const lazySpec = generateActorSpec({
typeName: "lazy",
methods: {
hello: {
response: { str: RetVal("string") }
}
}
});
exports.LazyActor = ActorClassWithSpec(lazySpec, {
initialize: function (conn, id) {
Actor.prototype.initialize.call(this, conn);
Services.obs.notifyObservers(null, "actor", "instantiated");
},
hello: function (str) {
return "world";
}
});
Services.obs.notifyObservers(null, "actor", "loaded");
exports.LazyFront = FrontClassWithSpec(lazySpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client);
this.actorID = form.lazyActor;
client.addActorPool(this);
this.manage(this);
}
});

View file

@ -0,0 +1,7 @@
"use strict";
function f() {}
(function () {
var a = 1; var b = 2; var c = 3;
})();

View file

@ -0,0 +1,6 @@
"use strict";
function f() {
var a = 1; var b = 2;
var c = 3;
}

View file

@ -0,0 +1,7 @@
"use strict";
function f() {}
(function () {
var a = 1; var c = 3;
})();

View file

@ -0,0 +1,5 @@
"use strict";
function f() {
var a = 1; var c = 3;
}

View file

@ -0,0 +1,5 @@
"use strict";
function f() {
var a = 1; var b = 2; var c = 3;
}

View file

@ -0,0 +1,9 @@
"use strict";
function f() {}
(function () {
var a = 1;
var b = 2;
var c = 3;
})();

View file

@ -0,0 +1,7 @@
"use strict";
function f() {
for (var i = 0; i < 1; ++i) {
;
}
}

View file

@ -0,0 +1,5 @@
"use strict";
function f() {
var a = 1; var b = 2; var c = 3;
}

View file

@ -0,0 +1,9 @@
"use strict";
function f() {}
(function () {
var a = 1;
var c = 3;
})();

View file

@ -0,0 +1,7 @@
"use strict";
function f() {
var a = 1;
var c = 3;
}

View file

@ -0,0 +1,7 @@
"use strict";
function f() {
var a = 1;
var b = 2;
var c = 3;
}

View file

@ -0,0 +1,6 @@
foo = (n) ->
return "foo" + i for i in [0...n]
[first, second, third] = foo(3)
debugger

View file

@ -0,0 +1,10 @@
{
"version": 3,
"file": "sourcemapped.js",
"sourceRoot": "",
"sources": [
"sourcemapped.coffee"
],
"names": [],
"mappings": ";AAAA;CAAA,KAAA,yBAAA;CAAA;CAAA,CAAA,CAAA,MAAO;CACL,IAAA,GAAA;AAAA,CAAA,EAAA,MAA0B,qDAA1B;CAAA,EAAe,EAAR,QAAA;CAAP,IADI;CAAN,EAAM;;CAAN,CAGA,CAAyB,IAAA;;CAEzB,UALA;CAAA"
}

View file

@ -0,0 +1,16 @@
// Generated by CoffeeScript 1.6.1
(function () {
var first, foo, second, third, _ref;
foo = function (n) {
var i, _i;
for (i = _i = 0; 0 <= n ? _i < n : _i > n; i = 0 <= n ? ++_i : --_i) {
return "foo" + i;
}
};
_ref = foo(3), first = _ref[0], second = _ref[1], third = _ref[2];
debugger;
}).call(this);

View file

@ -0,0 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that we can tell the memory actor to take a heap snapshot over the RDP
// and then create a HeapSnapshot instance from the resulting file.
const { OS } = require("resource://gre/modules/osfile.jsm");
const run_test = makeMemoryActorTest(function* (client, memoryFront) {
const snapshotFilePath = yield memoryFront.saveHeapSnapshot();
ok(!!(yield OS.File.stat(snapshotFilePath)),
"Should have the heap snapshot file");
const snapshot = ThreadSafeChromeUtils.readHeapSnapshot(snapshotFilePath);
ok(snapshot instanceof HeapSnapshot,
"And we should be able to read a HeapSnapshot instance from the file");
});

View file

@ -0,0 +1,20 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that we can properly stream heap snapshot files over the RDP as bulk
// data.
const { OS } = require("resource://gre/modules/osfile.jsm");
const run_test = makeMemoryActorTest(function* (client, memoryFront) {
const snapshotFilePath = yield memoryFront.saveHeapSnapshot({
forceCopy: true
});
ok(!!(yield OS.File.stat(snapshotFilePath)),
"Should have the heap snapshot file");
const snapshot = ThreadSafeChromeUtils.readHeapSnapshot(snapshotFilePath);
ok(snapshot instanceof HeapSnapshot,
"And we should be able to read a HeapSnapshot instance from the file");
});

View file

@ -0,0 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that we can save full runtime heap snapshots when attached to the
// ChromeActor or a ChildProcessActor.
const { OS } = require("resource://gre/modules/osfile.jsm");
const run_test = makeFullRuntimeMemoryActorTest(function* (client, memoryFront) {
const snapshotFilePath = yield memoryFront.saveHeapSnapshot();
ok(!!(yield OS.File.stat(snapshotFilePath)),
"Should have the heap snapshot file");
const snapshot = ThreadSafeChromeUtils.readHeapSnapshot(snapshotFilePath);
ok(snapshot instanceof HeapSnapshot,
"And we should be able to read a HeapSnapshot instance from the file");
});

View file

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that you can register new actors via the ActorRegistrationActor.
*/
var gClient;
var gRegistryFront;
var gActorFront;
var gOldPref;
const { ActorRegistryFront } = require("devtools/shared/fronts/actor-registry");
function run_test()
{
gOldPref = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps", false);
initTestDebuggerServer();
DebuggerServer.addBrowserActors();
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(getRegistry);
do_test_pending();
}
function getRegistry() {
gClient.listTabs((response) => {
gRegistryFront = ActorRegistryFront(gClient, response);
registerNewActor();
});
}
function registerNewActor() {
let options = {
prefix: "helloActor",
constructor: "HelloActor",
type: { global: true }
};
gRegistryFront
.registerActor("resource://test/hello-actor.js", options)
.then(actorFront => gActorFront = actorFront)
.then(talkToNewActor)
.then(null, e => {
DevToolsUtils.reportException("registerNewActor", e);
do_check_true(false);
});
}
function talkToNewActor() {
gClient.listTabs(({ helloActor }) => {
do_check_true(!!helloActor);
gClient.request({
to: helloActor,
type: "hello"
}, response => {
do_check_true(!response.error);
unregisterNewActor();
});
});
}
function unregisterNewActor() {
gActorFront
.unregister()
.then(testActorIsUnregistered)
.then(null, e => {
DevToolsUtils.reportException("unregisterNewActor", e);
do_check_true(false);
});
}
function testActorIsUnregistered() {
gClient.listTabs(({ helloActor }) => {
do_check_true(!helloActor);
Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps", gOldPref);
finishClient(gClient);
});
}

View file

@ -0,0 +1,107 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gClient;
var gActors;
/**
* The purpose of these tests is to verify that it's possible to add actors
* both before and after the DebuggerServer has been initialized, so addons
* that add actors don't have to poll the object for its initialization state
* in order to add actors after initialization but rather can add actors anytime
* regardless of the object's state.
*/
function run_test()
{
DebuggerServer.addActors("resource://test/pre_init_global_actors.js");
DebuggerServer.addActors("resource://test/pre_init_tab_actors.js");
DebuggerServer.init();
DebuggerServer.addBrowserActors();
DebuggerServer.addActors("resource://test/post_init_global_actors.js");
DebuggerServer.addActors("resource://test/post_init_tab_actors.js");
add_test(init);
add_test(test_pre_init_global_actor);
add_test(test_pre_init_tab_actor);
add_test(test_post_init_global_actor);
add_test(test_post_init_tab_actor);
add_test(test_stable_global_actor_instances);
add_test(close_client);
run_next_test();
}
function init()
{
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect()
.then(() => gClient.listTabs())
.then(aResponse => {
gActors = aResponse;
run_next_test();
});
}
function test_pre_init_global_actor()
{
gClient.request({ to: gActors.preInitGlobalActor, type: "ping" },
function onResponse(aResponse) {
do_check_eq(aResponse.message, "pong");
run_next_test();
}
);
}
function test_pre_init_tab_actor()
{
gClient.request({ to: gActors.preInitTabActor, type: "ping" },
function onResponse(aResponse) {
do_check_eq(aResponse.message, "pong");
run_next_test();
}
);
}
function test_post_init_global_actor()
{
gClient.request({ to: gActors.postInitGlobalActor, type: "ping" },
function onResponse(aResponse) {
do_check_eq(aResponse.message, "pong");
run_next_test();
}
);
}
function test_post_init_tab_actor()
{
gClient.request({ to: gActors.postInitTabActor, type: "ping" },
function onResponse(aResponse) {
do_check_eq(aResponse.message, "pong");
run_next_test();
}
);
}
// Get the object object, from the server side, for a given actor ID
function getActorInstance(connID, actorID) {
return DebuggerServer._connections[connID].getActor(actorID);
}
function test_stable_global_actor_instances()
{
// Consider that there is only one connection,
// and the first one is ours
let connID = Object.keys(DebuggerServer._connections)[0];
let postInitGlobalActor = getActorInstance(connID, gActors.postInitGlobalActor);
let preInitGlobalActor = getActorInstance(connID, gActors.preInitGlobalActor);
gClient.listTabs(function onListTabs(aResponse) {
do_check_eq(postInitGlobalActor, getActorInstance(connID, aResponse.postInitGlobalActor));
do_check_eq(preInitGlobalActor, getActorInstance(connID, aResponse.preInitGlobalActor));
run_next_test();
});
}
function close_client() {
gClient.close().then(() => run_next_test());
}

View file

@ -0,0 +1,98 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const protocol = require("devtools/shared/protocol");
const {AddonManager} = require("resource://gre/modules/AddonManager.jsm");
startupAddonsManager();
function promiseAddonEvent(event) {
return new Promise(resolve => {
let listener = {
[event]: function (...args) {
AddonManager.removeAddonListener(listener);
resolve(args);
}
};
AddonManager.addAddonListener(listener);
});
}
function* findAddonInRootList(client, addonId) {
const result = yield client.listAddons();
const addonActor = result.addons.filter(addon => addon.id === addonId)[0];
ok(addonActor, `Found add-on actor for ${addonId}`);
return addonActor;
}
function* reloadAddon(client, addonActor) {
// The add-on will be re-installed after a successful reload.
const onInstalled = promiseAddonEvent("onInstalled");
yield client.request({to: addonActor.actor, type: "reload"});
yield onInstalled;
}
function getSupportFile(path) {
const allowMissing = false;
return do_get_file(path, allowMissing);
}
add_task(function* testReloadExitedAddon() {
const client = yield new Promise(resolve => {
get_chrome_actors(client => resolve(client));
});
// Install our main add-on to trigger reloads on.
const addonFile = getSupportFile("addons/web-extension");
const installedAddon = yield AddonManager.installTemporaryAddon(
addonFile);
// Install a decoy add-on.
const addonFile2 = getSupportFile("addons/web-extension2");
const installedAddon2 = yield AddonManager.installTemporaryAddon(
addonFile2);
let addonActor = yield findAddonInRootList(client, installedAddon.id);
yield reloadAddon(client, addonActor);
// Uninstall the decoy add-on, which should cause its actor to exit.
const onUninstalled = promiseAddonEvent("onUninstalled");
installedAddon2.uninstall();
const [uninstalledAddon] = yield onUninstalled;
// Try to re-list all add-ons after a reload.
// This was throwing an exception because of the exited actor.
const newAddonActor = yield findAddonInRootList(client, installedAddon.id);
equal(newAddonActor.id, addonActor.id);
// The actor id should be the same after the reload
equal(newAddonActor.actor, addonActor.actor);
const onAddonListChanged = new Promise((resolve) => {
client.addListener("addonListChanged", function listener() {
client.removeListener("addonListChanged", listener);
resolve();
});
});
// Install an upgrade version of the first add-on.
const addonUpgradeFile = getSupportFile("addons/web-extension-upgrade");
const upgradedAddon = yield AddonManager.installTemporaryAddon(
addonUpgradeFile);
// Waiting for addonListChanged unsolicited event
yield onAddonListChanged;
// re-list all add-ons after an upgrade.
const upgradedAddonActor = yield findAddonInRootList(client, upgradedAddon.id);
equal(upgradedAddonActor.id, addonActor.id);
// The actor id should be the same after the upgrade.
equal(upgradedAddonActor.actor, addonActor.actor);
// The addon metadata has been updated.
equal(upgradedAddonActor.name, "Test Addons Actor Upgrade");
yield close(client);
});

View file

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const protocol = require("devtools/shared/protocol");
const {AddonsActor} = require("devtools/server/actors/addons");
const {AddonsFront} = require("devtools/shared/fronts/addons");
startupAddonsManager();
function* connect() {
const client = yield new Promise(resolve => {
get_chrome_actors(client => resolve(client));
});
const root = yield listTabs(client);
const addonsActor = root.addonsActor;
ok(addonsActor, "Got AddonsActor instance");
const addons = AddonsFront(client, {addonsActor});
return [client, addons];
}
add_task(function* testSuccessfulInstall() {
const [client, addons] = yield connect();
const allowMissing = false;
const usePlatformSeparator = true;
const addonPath = getFilePath("addons/web-extension",
allowMissing, usePlatformSeparator);
const installedAddon = yield addons.installTemporaryAddon(addonPath);
equal(installedAddon.id, "test-addons-actor@mozilla.org");
// The returned object is currently not a proper actor.
equal(installedAddon.actor, false);
const addonList = yield client.listAddons();
ok(addonList && addonList.addons && addonList.addons.map(a => a.name),
"Received list of add-ons");
const addon = addonList.addons.filter(a => a.id === installedAddon.id)[0];
ok(addon, "Test add-on appeared in root install list");
yield close(client);
});
add_task(function* testNonExistantPath() {
const [client, addons] = yield connect();
yield Assert.rejects(
addons.installTemporaryAddon("some-non-existant-path"),
/Could not install add-on.*Component returned failure/);
yield close(client);
});

View file

@ -0,0 +1,87 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that AnimationPlayerActor.getName returns the right name depending on
// the type of an animation and the various properties available on it.
const { AnimationPlayerActor } = require("devtools/server/actors/animation");
function run_test() {
// Mock a window with just the properties the AnimationPlayerActor uses.
let window = {
MutationObserver: function () {
this.observe = () => {};
},
Animation: function () {
this.effect = {target: getMockNode()};
},
CSSAnimation: function () {
this.effect = {target: getMockNode()};
},
CSSTransition: function () {
this.effect = {target: getMockNode()};
}
};
window.CSSAnimation.prototype = Object.create(window.Animation.prototype);
window.CSSTransition.prototype = Object.create(window.Animation.prototype);
// Helper to get a mock DOM node.
function getMockNode() {
return {
ownerDocument: {
defaultView: window
}
};
}
// Objects in this array should contain the following properties:
// - desc {String} For logging
// - animation {Object} An animation object instantiated from one of the mock
// window animation constructors.
// - props {Objet} Properties of this object will be added to the animation
// object.
// - expectedName {String} The expected name returned by
// AnimationPlayerActor.getName.
const TEST_DATA = [{
desc: "Animation with an id",
animation: new window.Animation(),
props: { id: "animation-id" },
expectedName: "animation-id"
}, {
desc: "Animation without an id",
animation: new window.Animation(),
props: {},
expectedName: ""
}, {
desc: "CSSTransition with an id",
animation: new window.CSSTransition(),
props: { id: "transition-with-id", transitionProperty: "width" },
expectedName: "transition-with-id"
}, {
desc: "CSSAnimation with an id",
animation: new window.CSSAnimation(),
props: { id: "animation-with-id", animationName: "move" },
expectedName: "animation-with-id"
}, {
desc: "CSSTransition without an id",
animation: new window.CSSTransition(),
props: { transitionProperty: "width" },
expectedName: "width"
}, {
desc: "CSSAnimation without an id",
animation: new window.CSSAnimation(),
props: { animationName: "move" },
expectedName: "move"
}];
for (let { desc, animation, props, expectedName } of TEST_DATA) {
do_print(desc);
for (let key in props) {
animation[key] = props[key];
}
let actor = AnimationPlayerActor({}, animation);
do_check_eq(actor.getName(), expectedName);
}
}

View file

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test the output of AnimationPlayerActor.getType().
const { ANIMATION_TYPES, AnimationPlayerActor } =
require("devtools/server/actors/animation");
function run_test() {
// Mock a window with just the properties the AnimationPlayerActor uses.
let window = {
MutationObserver: function () {
this.observe = () => {};
},
Animation: function () {
this.effect = {target: getMockNode()};
},
CSSAnimation: function () {
this.effect = {target: getMockNode()};
},
CSSTransition: function () {
this.effect = {target: getMockNode()};
}
};
window.CSSAnimation.prototype = Object.create(window.Animation.prototype);
window.CSSTransition.prototype = Object.create(window.Animation.prototype);
// Helper to get a mock DOM node.
function getMockNode() {
return {
ownerDocument: {
defaultView: window
}
};
}
// Objects in this array should contain the following properties:
// - desc {String} For logging
// - animation {Object} An animation object instantiated from one of the mock
// window animation constructors.
// - expectedType {String} The expected type returned by
// AnimationPlayerActor.getType.
const TEST_DATA = [{
desc: "Test CSSAnimation type",
animation: new window.CSSAnimation(),
expectedType: ANIMATION_TYPES.CSS_ANIMATION
}, {
desc: "Test CSSTransition type",
animation: new window.CSSTransition(),
expectedType: ANIMATION_TYPES.CSS_TRANSITION
}, {
desc: "Test ScriptAnimation type",
animation: new window.Animation(),
expectedType: ANIMATION_TYPES.SCRIPT_ANIMATION
}, {
desc: "Test unknown type",
animation: {effect: {target: getMockNode()}},
expectedType: ANIMATION_TYPES.UNKNOWN
}];
for (let { desc, animation, expectedType } of TEST_DATA) {
do_print(desc);
let actor = AnimationPlayerActor({}, animation);
do_check_eq(actor.getType(), expectedType);
}
}

View file

@ -0,0 +1,37 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gClient;
var gDebuggee;
function run_test()
{
initTestDebuggerServer();
gDebuggee = testGlobal("test-1");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(function ([aType, aTraits]) {
attachTestTab(gClient, "test-1", function (aReply, aTabClient) {
test_attach(aTabClient);
});
});
do_test_pending();
}
function test_attach(aTabClient)
{
aTabClient.attachThread({}, function (aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused");
aThreadClient.resume(cleanup);
});
}
function cleanup()
{
gClient.addListener("closed", function (aEvent) {
do_test_finished();
});
gClient.close();
}

View file

@ -0,0 +1,145 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test basic black boxing.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-black-box", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
testBlackBox();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
const testBlackBox = Task.async(function* () {
let packet = yield executeOnNextTickAndWaitForPause(evalCode, gClient);
let source = gThreadClient.source(packet.frame.where.source);
yield setBreakpoint(source, {
line: 2
});
yield resume(gThreadClient);
const { sources } = yield getSources(gThreadClient);
let sourceClient = gThreadClient.source(
sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
do_check_true(!sourceClient.isBlackBoxed,
"By default the source is not black boxed.");
// Test that we can step into `doStuff` when we are not black boxed.
yield runTest(
function onSteppedLocation(aLocation) {
do_check_eq(aLocation.source.url, BLACK_BOXED_URL);
do_check_eq(aLocation.line, 2);
},
function onDebuggerStatementFrames(aFrames) {
do_check_true(!aFrames.some(f => f.where.source.isBlackBoxed));
}
);
let blackBoxResponse = yield blackBox(sourceClient);
do_check_true(sourceClient.isBlackBoxed);
// Test that we step through `doStuff` when we are black boxed and its frame
// doesn't show up.
yield runTest(
function onSteppedLocation(aLocation) {
do_check_eq(aLocation.source.url, SOURCE_URL);
do_check_eq(aLocation.line, 4);
},
function onDebuggerStatementFrames(aFrames) {
for (let f of aFrames) {
if (f.where.source.url == BLACK_BOXED_URL) {
do_check_true(f.where.source.isBlackBoxed);
} else {
do_check_true(!f.where.source.isBlackBoxed);
}
}
}
);
let unBlackBoxResponse = yield unBlackBox(sourceClient);
do_check_true(!sourceClient.isBlackBoxed);
// Test that we can step into `doStuff` again.
yield runTest(
function onSteppedLocation(aLocation) {
do_check_eq(aLocation.source.url, BLACK_BOXED_URL);
do_check_eq(aLocation.line, 2);
},
function onDebuggerStatementFrames(aFrames) {
do_check_true(!aFrames.some(f => f.where.source.isBlackBoxed));
}
);
finishClient(gClient);
});
function evalCode() {
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
let arg = 15; // line 2 - Step in here
k(arg); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2 - Break here
function (n) { // line 3 - Step through `doStuff` to here
debugger; // line 4
} // line 5
); // line 6
} + "\n" // line 7
+ "debugger;", // line 8
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
const runTest = Task.async(function* (onSteppedLocation, onDebuggerStatementFrames) {
let packet = yield executeOnNextTickAndWaitForPause(gDebuggee.runTest,
gClient);
do_check_eq(packet.why.type, "breakpoint");
yield stepIn(gClient, gThreadClient);
yield stepIn(gClient, gThreadClient);
yield stepIn(gClient, gThreadClient);
const location = yield getCurrentLocation();
onSteppedLocation(location);
packet = yield resumeAndWaitForPause(gClient, gThreadClient);
do_check_eq(packet.why.type, "debuggerStatement");
let { frames } = yield getFrames(gThreadClient, 0, 100);
onDebuggerStatementFrames(frames);
return resume(gThreadClient);
});
const getCurrentLocation = Task.async(function* () {
const response = yield getFrames(gThreadClient, 0, 1);
return response.frames[0].where;
});

View file

@ -0,0 +1,113 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we don't hit breakpoints in black boxed sources, and that when we
* unblack box the source again, the breakpoint hasn't disappeared and we will
* hit it again.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-black-box", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.eval(aPacket.frame.actor, "doStuff", function (aResponse) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let obj = gThreadClient.pauseGrip(aPacket.why.frameFinished.return);
obj.getDefinitionSite(runWithSource);
});
});
function runWithSource(aPacket) {
let source = gThreadClient.source(aPacket.source);
source.setBreakpoint({
line: 2
}, function (aResponse) {
do_check_true(!aResponse.error, "Should be able to set breakpoint.");
gThreadClient.resume(test_black_box_breakpoint);
});
}
});
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
let arg = 15; // line 2 - Break here
k(arg); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
debugger; // line 5
} // line 6
); // line 7
} // line 8
+ "\n debugger;", // line 9
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_breakpoint() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "debuggerStatement",
"We should pass over the breakpoint since the source is black boxed.");
gThreadClient.resume(test_unblack_box_breakpoint.bind(null, sourceClient));
});
gDebuggee.runTest();
});
});
}
function test_unblack_box_breakpoint(aSourceClient) {
aSourceClient.unblackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "breakpoint",
"We should hit the breakpoint again");
// We will hit the debugger statement on resume, so do this nastiness to skip over it.
gClient.addOneTimeListener(
"paused",
gThreadClient.resume.bind(
gThreadClient,
finishClient.bind(null, gClient)));
gThreadClient.resume();
});
gDebuggee.runTest();
});
}

View file

@ -0,0 +1,102 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we don't stop at debugger statements inside black boxed sources.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gBpClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-black-box", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
source.setBreakpoint({
line: 4
}, function ({error}, bpClient) {
gBpClient = bpClient;
do_check_true(!error, "Should not get an error: " + error);
gThreadClient.resume(test_black_box_dbg_statement);
});
});
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
debugger; // line 2 - Break here
k(100); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
Math.abs(n); // line 4 - Break here
} // line 5
); // line 6
} // line 7
+ "\n debugger;", // line 8
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_dbg_statement() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "breakpoint",
"We should pass over the debugger statement.");
gBpClient.remove(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gThreadClient.resume(test_unblack_box_dbg_statement.bind(null, sourceClient));
});
});
gDebuggee.runTest();
});
});
}
function test_unblack_box_dbg_statement(aSourceClient) {
aSourceClient.unblackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "debuggerStatement",
"We should stop at the debugger statement again");
finishClient(gClient);
});
gDebuggee.runTest();
});
}

View file

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test behavior of blackboxing sources we are currently paused in.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-black-box", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.eval(aPacket.frame.actor, "doStuff", function (aResponse) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let obj = gThreadClient.pauseGrip(aPacket.why.frameFinished.return);
obj.getDefinitionSite(runWithSource);
});
});
function runWithSource(aPacket) {
let source = gThreadClient.source(aPacket.source);
source.setBreakpoint({
line: 2
}, function (aResponse) {
do_check_true(!aResponse.error, "Should be able to set breakpoint.");
test_black_box_paused();
});
}
});
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
debugger; // line 2
k(100); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
return n; // line 4
} // line 5
); // line 6
} // line 7
+ "\n runTest();", // line 8
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_paused() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error, pausedInSource}) {
do_check_true(!error, "Should not get an error: " + error);
do_check_true(pausedInSource, "We should be notified that we are currently paused in this source");
finishClient(gClient);
});
});
}

View file

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test exceptions inside black boxed sources.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-black-box", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
// XXX: We have to do an executeSoon so that the error isn't caught and
// reported by DebuggerClient.requester (because we are using the local
// transport and share a stack) which causes the test to fail.
Services.tm.mainThread.dispatch({
run: test_black_box
}, Ci.nsIThread.DISPATCH_NORMAL);
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", test_black_box_exception);
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
throw new Error("wu tang clan ain't nuthin' ta fuck wit"); // line 2
k(100); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
debugger; // line 4
} // line 5
); // line 6
} // line 7
+ "\ndebugger;\n" // line 8
+ "try { runTest() } catch (ex) { }", // line 9
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_exception() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gThreadClient.pauseOnExceptions(true);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.frame.where.source.url, SOURCE_URL,
"We shouldn't pause while in the black boxed source.");
finishClient(gClient);
});
gThreadClient.resume();
});
});
}

View file

@ -0,0 +1,102 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can black box source mapped sources.
*/
var gDebuggee;
var gClient;
var gThreadClient;
const {SourceNode} = require("source-map");
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-black-box", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
promise.resolve(setup_code())
.then(black_box_code)
.then(run_code)
.then(test_correct_location)
.then(null, function (error) {
do_check_true(false, "Should not get an error, got " + error);
})
.then(function () {
finishClient(gClient);
});
});
});
do_test_pending();
}
function setup_code() {
let { code, map } = (new SourceNode(null, null, null, [
new SourceNode(1, 0, "a.js", "" + function a() {
return b();
}),
"\n",
new SourceNode(1, 0, "b.js", "" + function b() {
debugger; // Don't want to stop here.
return c();
}),
"\n",
new SourceNode(1, 0, "c.js", "" + function c() {
debugger; // Want to stop here.
}),
"\n"
])).toStringWithSourceMap({
file: "abc.js",
sourceRoot: "http://example.com/"
});
code += "//# sourceMappingURL=data:text/json," + map.toString();
Components.utils.evalInSandbox(code,
gDebuggee,
"1.8",
"http://example.com/abc.js");
}
function black_box_code() {
const d = promise.defer();
gThreadClient.getSources(function ({ sources, error }) {
do_check_true(!error, "Shouldn't get an error getting sources");
const source = sources.filter((s) => {
return s.url.indexOf("b.js") !== -1;
})[0];
do_check_true(!!source, "We should have our source in the sources list");
gThreadClient.source(source).blackBox(function ({ error }) {
do_check_true(!error, "Should not get an error black boxing");
d.resolve(true);
});
});
return d.promise;
}
function run_code() {
const d = promise.defer();
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
d.resolve(aPacket);
gThreadClient.resume();
});
gDebuggee.a();
return d.promise;
}
function test_correct_location(aPacket) {
do_check_eq(aPacket.why.type, "debuggerStatement",
"Should hit a debugger statement.");
do_check_eq(aPacket.frame.where.source.url, "http://example.com/c.js",
"Should have skipped over the debugger statement in the black boxed source");
}

View file

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that sources whose URL ends with ".min.js" automatically get black
* boxed.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-black-box", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
testBlackBox();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/black-boxed.min.js";
const SOURCE_URL = "http://example.com/source.js";
const testBlackBox = Task.async(function* () {
yield executeOnNextTickAndWaitForPause(evalCode, gClient);
const { sources } = yield getSources(gThreadClient);
equal(sources.length, 2);
const blackBoxedSource = sources.filter(s => s.url === BLACK_BOXED_URL)[0];
equal(blackBoxedSource.isBlackBoxed, true);
const regularSource = sources.filter(s => s.url === SOURCE_URL)[0];
equal(regularSource.isBlackBoxed, false);
finishClient(gClient);
});
function evalCode() {
Components.utils.evalInSandbox(
"" + function blackBoxed() {},
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function source() {}
+ "\ndebugger;",
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}

View file

@ -0,0 +1,75 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check basic breakpoint functionality.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = {
line: gDebuggee.line0 + 3
};
source.setBreakpoint(location, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"var b = 2;\n", // line0 + 3
gDebuggee
);
}

View file

@ -0,0 +1,67 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting breakpoints when the debuggee is running works.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_breakpoint_running();
});
});
}
function test_breakpoint_running()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let location = { line: gDebuggee.line0 + 3 };
gThreadClient.resume();
// Setting the breakpoint later should interrupt the debuggee.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "interrupted");
});
let source = gThreadClient.source(aPacket.frame.where.source);
source.setBreakpoint(location, function (aResponse) {
// Eval scripts don't stick around long enough for the breakpoint to be set,
// so just make sure we got the expected response from the actor.
do_check_neq(aResponse.error, "noScript");
do_execute_soon(function () {
gClient.close().then(gCallback);
});
});
});
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"debugger;\n" +
"var a = 1;\n" + // line0 + 2
"var b = 2;\n", // line0 + 3
gDebuggee
);
}

View file

@ -0,0 +1,96 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint on a line without code will skip
* forward when we know the script isn't GCed (the debugger is connected,
* so it's kept alive).
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient,
"test-stack",
function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_skip_breakpoint();
});
});
}
var test_no_skip_breakpoint = Task.async(function*(source, location) {
let [aResponse, bpClient] = yield source.setBreakpoint(
Object.assign({}, location, { noSliding: true })
);
do_check_true(!aResponse.actualLocation);
do_check_eq(bpClient.location.line, gDebuggee.line0 + 3);
yield bpClient.remove();
});
var test_skip_breakpoint = function() {
gThreadClient.addOneTimeListener("paused", Task.async(function *(aEvent, aPacket) {
let location = { line: gDebuggee.line0 + 3 };
let source = gThreadClient.source(aPacket.frame.where.source);
// First, make sure that we can disable sliding with the
// `noSliding` option.
yield test_no_skip_breakpoint(source, location);
// Now make sure that the breakpoint properly slides forward one line.
const [aResponse, bpClient] = yield source.setBreakpoint(location);
do_check_true(!!aResponse.actualLocation);
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line + 1);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
gThreadClient.resume();
}));
// Use `evalInSandbox` to make the debugger treat it as normal
// globally-scoped code, where breakpoint sliding rules apply.
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"// A comment.\n" + // line0 + 3
"var b = 2;", // line0 + 4
gDebuggee
);
}

View file

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line in a child script works.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_child_breakpoint();
});
});
}
function test_child_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 3 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// actualLocation is not returned when breakpoints don't skip forward.
do_check_eq(aResponse.actualLocation, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" this.b = 2;\n" + // line0 + 3
"}\n" + // line0 + 4
"debugger;\n" + // line0 + 5
"foo();\n", // line0 + 6
gDebuggee
);
}

View file

@ -0,0 +1,82 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in a child script
* will skip forward.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_child_skip_breakpoint();
});
});
}
function test_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 3 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line + 1);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n", // line0 + 7
gDebuggee
);
}

View file

@ -0,0 +1,89 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in a deeply-nested
* child script will skip forward.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_nested_breakpoint();
});
});
}
function test_nested_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 5 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line + 1);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" function bar() {\n" + // line0 + 2
" function baz() {\n" + // line0 + 3
" this.a = 1;\n" + // line0 + 4
" // A comment.\n" + // line0 + 5
" this.b = 2;\n" + // line0 + 6
" }\n" + // line0 + 7
" baz();\n" + // line0 + 8
" }\n" + // line0 + 9
" bar();\n" + // line0 + 10
"}\n" + // line0 + 11
"debugger;\n" + // line0 + 12
"foo();\n", // line0 + 13
gDebuggee
);
}

View file

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in the second child
* script will skip forward.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_second_child_skip_breakpoint();
});
});
}
function test_second_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 6 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line + 1);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" bar();\n" + // line0 + 2
"}\n" + // line0 + 3
"function bar() {\n" + // line0 + 4
" this.a = 1;\n" + // line0 + 5
" // A comment.\n" + // line0 + 6
" this.b = 2;\n" + // line0 + 7
"}\n" + // line0 + 8
"debugger;\n" + // line0 + 9
"foo();\n", // line0 + 10
gDebuggee
);
}

View file

@ -0,0 +1,96 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in a child script
* will skip forward, in a file with two scripts.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_child_skip_breakpoint();
});
});
}
function test_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.eval(aPacket.frame.actor, "foo", function (aResponse) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let obj = gThreadClient.pauseGrip(aPacket.why.frameFinished.return);
obj.getDefinitionSite(runWithBreakpoint);
});
});
function runWithBreakpoint(aPacket) {
let source = gThreadClient.source(aPacket.source);
let location = { line: gDebuggee.line0 + 3 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line + 1);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
}
});
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n", // line0 + 5
gDebuggee,
"1.7",
"script1.js");
Cu.evalInSandbox("var line1 = Error().lineNumber;\n" +
"debugger;\n" + // line1 + 1
"foo();\n", // line1 + 2
gDebuggee,
"1.7",
"script2.js");
}

View file

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that removing a breakpoint works.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_remove_breakpoint();
});
});
}
function test_remove_breakpoint()
{
let done = false;
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 2 };
source.setBreakpoint(location, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
done = true;
gThreadClient.addOneTimeListener("paused",
function (aEvent, aPacket) {
// The breakpoint should not be hit again.
gThreadClient.resume(function () {
do_check_true(false);
});
});
gThreadClient.resume();
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo(stop) {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" if (stop) return;\n" + // line0 + 3
" delete this.a;\n" + // line0 + 4
" foo(true);\n" + // line0 + 5
"}\n" + // line0 + 6
"debugger;\n" + // line1 + 7
"foo();\n", // line1 + 8
gDebuggee);
if (!done) {
do_check_true(false);
}
gClient.close().then(gCallback);
}

View file

@ -0,0 +1,89 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line with multiple entry points
* triggers no matter which entry point we reach.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_child_breakpoint();
});
});
}
function test_child_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 3 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// actualLocation is not returned when breakpoints don't skip forward.
do_check_eq(aResponse.actualLocation, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.i, 0);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.i, 1);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit again.
gThreadClient.resume();
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a, i = 0;\n" + // line0 + 2
"for (i = 1; i <= 2; i++) {\n" + // line0 + 3
" a = i;\n" + // line0 + 4
"}\n", // line0 + 5
gDebuggee);
}

View file

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that setting a breakpoint in a line with bytecodes in multiple
* scripts, sets the breakpoint in all of them (bug 793214).
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_child_breakpoint();
});
});
}
function test_child_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 2 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// actualLocation is not returned when breakpoints don't skip forward.
do_check_eq(aResponse.actualLocation, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a.b, 1);
do_check_eq(gDebuggee.res, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit again.
gThreadClient.resume();
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = { b: 1, f: function() { return 2; } };\n" + // line0+2
"var res = a.f();\n", // line0 + 3
gDebuggee);
}

View file

@ -0,0 +1,113 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that setting a breakpoint twice in a line without bytecodes works
* as expected.
*/
const NUM_BREAKPOINTS = 10;
var gDebuggee;
var gClient;
var gThreadClient;
var gBpActor;
var gCount;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
gCount = 1;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_child_skip_breakpoint();
});
});
}
function test_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 3};
source.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gBpActor = aResponse.actor;
// Set more breakpoints at the same location.
set_breakpoints(source, location);
});
});
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n", // line0 + 7
gDebuggee);
}
// Set many breakpoints at the same location.
function set_breakpoints(source, location) {
do_check_neq(gCount, NUM_BREAKPOINTS);
source.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
// Check that the same breakpoint actor was returned.
do_check_eq(aResponse.actor, gBpActor);
if (++gCount < NUM_BREAKPOINTS) {
set_breakpoints(source, location);
return;
}
// After setting all the breakpoints, check that only one has effectively
// remained.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line + 1);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// We don't expect any more pauses after the breakpoint was hit once.
do_check_true(false);
});
gThreadClient.resume(function () {
// Give any remaining breakpoints a chance to trigger.
do_timeout(1000, function () {
gClient.close().then(gCallback);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
}

View file

@ -0,0 +1,115 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that execution doesn't pause twice while stepping, when encountering
* either a breakpoint or a debugger statement.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 2 };
source.setBreakpoint(location, Task.async(function* (aResponse, bpClient) {
const testCallbacks = [
function (aPacket) {
// Check that the stepping worked.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// Entered the foo function call frame.
do_check_eq(aPacket.frame.where.line, location.line);
do_check_neq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// At the end of the foo function call frame.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 3);
do_check_neq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// Check that the breakpoint wasn't the reason for this pause, but
// that the frame is about to be popped while stepping.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 3);
do_check_neq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.why.frameFinished.return.type, "undefined");
},
function (aPacket) {
// The foo function call frame was just popped from the stack.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.poppedFrames.length, 1);
},
function (aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 6);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 7);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
},
];
for (let callback of testCallbacks) {
let waiter = waitForPause(gThreadClient);
gThreadClient.stepIn();
let packet = yield waiter;
callback(packet);
}
// Remove the breakpoint and finish.
let waiter = waitForPause(gThreadClient);
gThreadClient.stepIn();
yield waiter;
bpClient.remove(() => gThreadClient.resume(() => gClient.close().then(gCallback)));
}));
});
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n", // line0 + 7
gDebuggee);
}

View file

@ -0,0 +1,113 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that a breakpoint or a debugger statement cause execution to pause even
* in a stepped-over function.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-stack", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = { line: gDebuggee.line0 + 2 };
source.setBreakpoint(location, Task.async(function* (aResponse, bpClient) {
const testCallbacks = [
function (aPacket) {
// Check that the stepping worked.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// Reached the breakpoint.
do_check_eq(aPacket.frame.where.line, location.line);
do_check_eq(aPacket.why.type, "breakpoint");
do_check_neq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// Stepped to the closing brace of the function.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 3);
do_check_eq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// The frame is about to be popped while stepping.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 3);
do_check_neq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.why.frameFinished.return.type, "undefined");
},
function (aPacket) {
// The foo function call frame was just popped from the stack.
do_check_eq(gDebuggee.a, 1);
do_check_eq(gDebuggee.b, undefined);
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.poppedFrames.length, 1);
},
function (aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 6);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
},
function (aPacket) {
// Check that the debugger statement wasn't the reason for this pause.
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 7);
do_check_neq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.why.type, "resumeLimit");
},
];
for (let callback of testCallbacks) {
let waiter = waitForPause(gThreadClient);
gThreadClient.stepOver();
let packet = yield waiter;
callback(packet);
}
// Remove the breakpoint and finish.
let waiter = waitForPause(gThreadClient);
gThreadClient.stepOver();
yield waiter;
bpClient.remove(() => gThreadClient.resume(() => gClient.close().then(gCallback)));
}));
});
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n", // line0 + 7
gDebuggee);
}

View file

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that adding a breakpoint in the same place returns the same actor.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
testSameBreakpoint();
});
});
do_test_pending();
}
const SOURCE_URL = "http://example.com/source.js";
const testSameBreakpoint = Task.async(function* () {
let packet = yield executeOnNextTickAndWaitForPause(evalCode, gClient);
let source = gThreadClient.source(packet.frame.where.source);
// Whole line
let wholeLineLocation = {
line: 2
};
let [firstResponse, firstBpClient] = yield setBreakpoint(source, wholeLineLocation);
let [secondResponse, secondBpClient] = yield setBreakpoint(source, wholeLineLocation);
do_check_eq(firstBpClient.actor, secondBpClient.actor, "Should get the same actor w/ whole line breakpoints");
// Specific column
let columnLocation = {
line: 2,
column: 6
};
[firstResponse, firstBpClient] = yield setBreakpoint(source, columnLocation);
[secondResponse, secondBpClient] = yield setBreakpoint(source, columnLocation);
do_check_eq(secondBpClient.actor, secondBpClient.actor, "Should get the same actor column breakpoints");
finishClient(gClient);
});
function evalCode() {
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
let arg = 15; // line 2 - Step in here
k(arg); // line 3
} + "\n" // line 4
+ "debugger;", // line 5
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}

View file

@ -0,0 +1,83 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that we can set breakpoints in columns, not just lines.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-breakpoints", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient,
"test-breakpoints",
function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_column_breakpoint();
});
});
}
function test_column_breakpoint()
{
// Debugger statement
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
let location = {
line: gDebuggee.line0 + 1,
column: 55
};
let timesBreakpointHit = 0;
source.setBreakpoint(location, function (aResponse, bpClient) {
gThreadClient.addListener("paused", function onPaused(aEvent, aPacket) {
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
do_check_eq(aPacket.frame.where.source.actor, source.actor);
do_check_eq(aPacket.frame.where.line, location.line);
do_check_eq(aPacket.frame.where.column, location.column);
do_check_eq(gDebuggee.acc, timesBreakpointHit);
do_check_eq(aPacket.frame.environment.bindings.variables.i.value,
timesBreakpointHit);
if (++timesBreakpointHit === 3) {
gThreadClient.removeListener("paused", onPaused);
bpClient.remove(function (aResponse) {
gThreadClient.resume(() => gClient.close().then(gCallback));
});
} else {
gThreadClient.resume();
}
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Components.utils.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"(function () { debugger; this.acc = 0; for (var i = 0; i < 3; i++) this.acc++; }());",
gDebuggee
);
}

View file

@ -0,0 +1,120 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that when we add 2 breakpoints to the same line at different columns and
* then remove one of them, we don't remove them both.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, do_test_finished);
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-breakpoints", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-breakpoints", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_breakpoints_columns();
});
});
}
const code =
"(" + function (global) {
global.foo = function () {
Math.abs(-1); Math.log(0.5);
debugger;
};
debugger;
} + "(this))";
const firstLocation = {
line: 3,
column: 4
};
const secondLocation = {
line: 3,
column: 18
};
function test_breakpoints_columns() {
gClient.addOneTimeListener("paused", set_breakpoints);
Components.utils.evalInSandbox(code, gDebuggee, "1.8", "http://example.com/", 1);
}
function set_breakpoints(aEvent, aPacket) {
let first, second;
let source = gThreadClient.source(aPacket.frame.where.source);
source.setBreakpoint(firstLocation, function ({ error, actualLocation },
aBreakpointClient) {
do_check_true(!error, "Should not get an error setting the breakpoint");
do_check_true(!actualLocation, "Should not get an actualLocation");
first = aBreakpointClient;
source.setBreakpoint(secondLocation, function ({ error, actualLocation },
aBreakpointClient) {
do_check_true(!error, "Should not get an error setting the breakpoint");
do_check_true(!actualLocation, "Should not get an actualLocation");
second = aBreakpointClient;
test_different_actors(first, second);
});
});
}
function test_different_actors(aFirst, aSecond) {
do_check_neq(aFirst.actor, aSecond.actor,
"Each breakpoint should have a different actor");
test_remove_one(aFirst, aSecond);
}
function test_remove_one(aFirst, aSecond) {
aFirst.remove(function ({error}) {
do_check_true(!error, "Should not get an error removing a breakpoint");
let hitSecond;
gClient.addListener("paused", function _onPaused(aEvent, {why, frame}) {
if (why.type == "breakpoint") {
hitSecond = true;
do_check_eq(why.actors.length, 1,
"Should only be paused because of one breakpoint actor");
do_check_eq(why.actors[0], aSecond.actor,
"Should be paused because of the correct breakpoint actor");
do_check_eq(frame.where.line, secondLocation.line,
"Should be at the right line");
do_check_eq(frame.where.column, secondLocation.column,
"Should be at the right column");
gThreadClient.resume();
return;
}
if (why.type == "debuggerStatement") {
gClient.removeListener("paused", _onPaused);
do_check_true(hitSecond,
"We should still hit `second`, but not `first`.");
gClient.close().then(gCallback);
return;
}
do_check_true(false, "Should never get here");
});
gThreadClient.resume(() => gDebuggee.foo());
});
}

View file

@ -0,0 +1,82 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that we only break on offsets that are entry points for the line we are
* breaking on. Bug 907278.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-breakpoints", aServer);
gDebuggee.console = { log: x => void x };
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient,
"test-breakpoints",
function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
setUpCode();
});
});
}
function setUpCode() {
gClient.addOneTimeListener("paused", setBreakpoint);
Cu.evalInSandbox(
"debugger;\n" +
function test() {
console.log("foo bar");
debugger;
},
gDebuggee,
"1.8",
"http://example.com/",
1
);
}
function setBreakpoint(aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
gClient.addOneTimeListener("resumed", runCode);
source.setBreakpoint({ line: 2 }, ({ error }) => {
do_check_true(!error);
gThreadClient.resume();
});
}
function runCode() {
gClient.addOneTimeListener("paused", testBPHit);
gDebuggee.test();
}
function testBPHit(event, { why }) {
do_check_eq(why.type, "breakpoint");
gClient.addOneTimeListener("paused", testDbgStatement);
gThreadClient.resume();
}
function testDbgStatement(event, { why }) {
// Should continue to the debugger statement.
do_check_eq(why.type, "debuggerStatement");
// Not break on another offset from the same line (that isn't an entry point
// to the line)
do_check_neq(why.type, "breakpoint");
gClient.close().then(gCallback);
}

View file

@ -0,0 +1,70 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that setting a breakpoint in a not-yet-existing script doesn't throw
* an error (see bug 897567). Also make sure that this breakpoint works.
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-breakpoints", aServer);
gDebuggee.console = { log: x => void x };
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient,
"test-breakpoints",
function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
testBreakpoint();
});
});
}
const URL = "test.js";
function setUpCode() {
Cu.evalInSandbox(
"" + function test() { // 1
var a = 1; // 2
debugger; // 3
} + // 4
"\ndebugger;", // 5
gDebuggee,
"1.8",
URL
);
}
const testBreakpoint = Task.async(function* () {
let source = yield getSource(gThreadClient, URL);
let [response, bpClient] = yield setBreakpoint(source, {line: 2});
ok(!response.error);
let actor = response.actor;
ok(actor);
yield executeOnNextTickAndWaitForPause(setUpCode, gClient);
yield resume(gThreadClient);
let packet = yield executeOnNextTickAndWaitForPause(gDebuggee.test, gClient);
equal(packet.why.type, "breakpoint");
notEqual(packet.why.actors.indexOf(actor), -1);
finishClient(gClient);
});

View file

@ -0,0 +1,108 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Verify that when two of the "same" source are loaded concurrently (like e10s
* frame scripts), breakpoints get hit in scripts defined by all sources.
*/
var gDebuggee;
var gClient;
var gTraceClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-breakpoints");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestThread(gClient, "test-breakpoints", testBreakpoint);
});
do_test_pending();
}
const testBreakpoint = Task.async(function* (threadResponse, tabClient, threadClient, tabResponse) {
evalSetupCode();
// Load the test source once.
evalTestCode();
equal(gDebuggee.functions.length, 1,
"The test code should have added a function.");
// Set a breakpoint in the test source.
const source = yield getSource(threadClient, "test.js");
const [response, bpClient] = yield setBreakpoint(source, {
line: 3
});
ok(!response.error, "Shouldn't get an error setting the BP.");
ok(!response.actualLocation,
"Shouldn't get an actualLocation, the location we provided was good.");
const bpActor = response.actor;
yield resume(threadClient);
// Load the test source again.
evalTestCode();
equal(gDebuggee.functions.length, 2,
"The test code should have added another function.");
// Should hit our breakpoint in a script defined by the first instance of the
// test source.
const bpPause1 = yield executeOnNextTickAndWaitForPause(gDebuggee.functions[0],
gClient);
equal(bpPause1.why.type, "breakpoint",
"Should pause because of hitting our breakpoint (not debugger statement).");
equal(bpPause1.why.actors[0], bpActor,
"And the breakpoint actor should be correct.");
const dbgStmtPause1 = yield executeOnNextTickAndWaitForPause(() => resume(threadClient),
gClient);
equal(dbgStmtPause1.why.type, "debuggerStatement",
"And we should hit the debugger statement after the pause.");
yield resume(threadClient);
// Should also hit our breakpoint in a script defined by the second instance
// of the test source.
const bpPause2 = yield executeOnNextTickAndWaitForPause(gDebuggee.functions[1],
gClient);
equal(bpPause2.why.type, "breakpoint",
"Should pause because of hitting our breakpoint (not debugger statement).");
equal(bpPause2.why.actors[0], bpActor,
"And the breakpoint actor should be correct.");
const dbgStmtPause2 = yield executeOnNextTickAndWaitForPause(() => resume(threadClient),
gClient);
equal(dbgStmtPause2.why.type, "debuggerStatement",
"And we should hit the debugger statement after the pause.");
finishClient(gClient);
});
function evalSetupCode() {
Cu.evalInSandbox(
"this.functions = [];",
gDebuggee,
"1.8",
"setup.js",
1
);
}
function evalTestCode() {
Cu.evalInSandbox(
` // 1
this.functions.push(function () { // 2
var setBreakpointHere = 1; // 3
debugger; // 4
}); // 5
`,
gDebuggee,
"1.8",
"test.js",
1
);
}

View file

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 1122064 - make sure that scripts introduced via onNewScripts
* properly populate the `ScriptStore` with all there nested child
* scripts, so you can set breakpoints on deeply nested scripts
*/
var gDebuggee;
var gClient;
var gThreadClient;
var gCallback;
function run_test()
{
run_test_with_server(DebuggerServer, function () {
run_test_with_server(WorkerDebuggerServer, do_test_finished);
});
do_test_pending();
}
function run_test_with_server(aServer, aCallback)
{
gCallback = aCallback;
initTestDebuggerServer(aServer);
gDebuggee = addTestGlobal("test-breakpoints", aServer);
gClient = new DebuggerClient(aServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient,
"test-breakpoints",
function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test();
});
});
}
const test = Task.async(function* () {
// Populate the `ScriptStore` so that we only test that the script
// is added through `onNewScript`
yield getSources(gThreadClient);
let packet = yield executeOnNextTickAndWaitForPause(evalCode, gClient);
let source = gThreadClient.source(packet.frame.where.source);
let location = {
line: gDebuggee.line0 + 8
};
let [res, bpClient] = yield setBreakpoint(source, location);
ok(!res.error);
yield resume(gThreadClient);
packet = yield waitForPause(gClient);
do_check_eq(packet.type, "paused");
do_check_eq(packet.why.type, "breakpoint");
do_check_eq(packet.why.actors[0], bpClient.actor);
do_check_eq(packet.frame.where.source.actor, source.actor);
do_check_eq(packet.frame.where.line, location.line);
yield resume(gThreadClient);
finishClient(gClient);
});
function evalCode() {
// Start a new script
Components.utils.evalInSandbox(
"var line0 = Error().lineNumber;\n(" + function () {
debugger;
var a = (function () {
return (function () {
return (function () {
return (function () {
return (function () {
var x = 10; // This line gets a breakpoint
return 1;
})();
})();
})();
})();
})();
} + ")()",
gDebuggee
);
}

View file

@ -0,0 +1,180 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test the functionality of the BreakpointActorMap object.
const { BreakpointActorMap } = require("devtools/server/actors/script");
function run_test() {
test_get_actor();
test_set_actor();
test_delete_actor();
test_find_actors();
test_duplicate_actors();
}
function test_get_actor() {
let bpStore = new BreakpointActorMap();
let location = {
originalSourceActor: { actor: "actor1" },
originalLine: 3
};
let columnLocation = {
originalSourceActor: { actor: "actor2" },
originalLine: 5,
originalColumn: 15
};
// Shouldn't have breakpoint
do_check_eq(null, bpStore.getActor(location),
"Breakpoint not added and shouldn't exist.");
bpStore.setActor(location, {});
do_check_true(!!bpStore.getActor(location),
"Breakpoint added but not found in Breakpoint Store.");
bpStore.deleteActor(location);
do_check_eq(null, bpStore.getActor(location),
"Breakpoint removed but still exists.");
// Same checks for breakpoint with a column
do_check_eq(null, bpStore.getActor(columnLocation),
"Breakpoint with column not added and shouldn't exist.");
bpStore.setActor(columnLocation, {});
do_check_true(!!bpStore.getActor(columnLocation),
"Breakpoint with column added but not found in Breakpoint Store.");
bpStore.deleteActor(columnLocation);
do_check_eq(null, bpStore.getActor(columnLocation),
"Breakpoint with column removed but still exists in Breakpoint Store.");
}
function test_set_actor() {
// Breakpoint with column
let bpStore = new BreakpointActorMap();
let location = {
originalSourceActor: { actor: "actor1" },
originalLine: 10,
originalColumn: 9
};
bpStore.setActor(location, {});
do_check_true(!!bpStore.getActor(location),
"We should have the column breakpoint we just added");
// Breakpoint without column (whole line breakpoint)
location = {
originalSourceActor: { actor: "actor2" },
originalLine: 103
};
bpStore.setActor(location, {});
do_check_true(!!bpStore.getActor(location),
"We should have the whole line breakpoint we just added");
}
function test_delete_actor() {
// Breakpoint with column
let bpStore = new BreakpointActorMap();
let location = {
originalSourceActor: { actor: "actor1" },
originalLine: 10,
originalColumn: 9
};
bpStore.setActor(location, {});
bpStore.deleteActor(location);
do_check_eq(bpStore.getActor(location), null,
"We should not have the column breakpoint anymore");
// Breakpoint without column (whole line breakpoint)
location = {
originalSourceActor: { actor: "actor2" },
originalLine: 103
};
bpStore.setActor(location, {});
bpStore.deleteActor(location);
do_check_eq(bpStore.getActor(location), null,
"We should not have the whole line breakpoint anymore");
}
function test_find_actors() {
let bps = [
{ originalSourceActor: { actor: "actor1" }, originalLine: 10 },
{ originalSourceActor: { actor: "actor1" }, originalLine: 10, originalColumn: 3 },
{ originalSourceActor: { actor: "actor1" }, originalLine: 10, originalColumn: 10 },
{ originalSourceActor: { actor: "actor1" }, originalLine: 23, originalColumn: 89 },
{ originalSourceActor: { actor: "actor2" }, originalLine: 10, originalColumn: 1 },
{ originalSourceActor: { actor: "actor2" }, originalLine: 20, originalColumn: 5 },
{ originalSourceActor: { actor: "actor2" }, originalLine: 30, originalColumn: 34 },
{ originalSourceActor: { actor: "actor2" }, originalLine: 40, originalColumn: 56 }
];
let bpStore = new BreakpointActorMap();
for (let bp of bps) {
bpStore.setActor(bp, bp);
}
// All breakpoints
let bpSet = new Set(bps);
for (let bp of bpStore.findActors()) {
bpSet.delete(bp);
}
do_check_eq(bpSet.size, 0,
"Should be able to iterate over all breakpoints");
// Breakpoints by URL
bpSet = new Set(bps.filter(bp => { return bp.originalSourceActor.actorID === "actor1"; }));
for (let bp of bpStore.findActors({ originalSourceActor: { actorID: "actor1" } })) {
bpSet.delete(bp);
}
do_check_eq(bpSet.size, 0,
"Should be able to filter the iteration by url");
// Breakpoints by URL and line
bpSet = new Set(bps.filter(bp => { return bp.originalSourceActor.actorID === "actor1" && bp.originalLine === 10; }));
let first = true;
for (let bp of bpStore.findActors({ originalSourceActor: { actorID: "actor1" }, originalLine: 10 })) {
if (first) {
do_check_eq(bp.originalColumn, undefined,
"Should always get the whole line breakpoint first");
first = false;
} else {
do_check_neq(bp.originalColumn, undefined,
"Should not get the whole line breakpoint any time other than first.");
}
bpSet.delete(bp);
}
do_check_eq(bpSet.size, 0,
"Should be able to filter the iteration by url and line");
}
function test_duplicate_actors() {
let bpStore = new BreakpointActorMap();
// Breakpoint with column
let location = {
originalSourceActor: { actorID: "foo-actor" },
originalLine: 10,
originalColumn: 9
};
bpStore.setActor(location, {});
bpStore.setActor(location, {});
do_check_eq(bpStore.size, 1, "We should have only 1 column breakpoint");
bpStore.deleteActor(location);
// Breakpoint without column (whole line breakpoint)
location = {
originalSourceActor: { actorID: "foo-actor" },
originalLine: 15
};
bpStore.setActor(location, {});
bpStore.setActor(location, {});
do_check_eq(bpStore.size, 1, "We should have only 1 whole line breakpoint");
bpStore.deleteActor(location);
}

View file

@ -0,0 +1,39 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gClient;
var gDebuggee;
function run_test()
{
initTestDebuggerServer();
gDebuggee = testGlobal("test-1");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(function (aType, aTraits) {
attachTestTab(gClient, "test-1", function (aReply, aTabClient) {
test_close(transport);
});
});
do_test_pending();
}
function test_close(aTransport)
{
// Check that, if we fake a transport shutdown
// (like if a device is unplugged)
// the client is automatically closed,
// and we can still call client.close.
let onClosed = function () {
gClient.removeListener("closed", onClosed);
ok(true, "Client emitted 'closed' event");
gClient.close().then(function () {
ok(true, "client.close() successfully called its callback");
do_test_finished();
});
};
gClient.addListener("closed", onClosed);
aTransport.close();
}

View file

@ -0,0 +1,214 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the DebuggerClient.request API.
var gClient, gActorId;
function TestActor(conn) {
this.conn = conn;
}
TestActor.prototype = {
actorPrefix: "test",
hello: function () {
return {hello: "world"};
},
error: function () {
return {error: "code", message: "human message"};
}
};
TestActor.prototype.requestTypes = {
"hello": TestActor.prototype.hello,
"error": TestActor.prototype.error
};
function run_test()
{
DebuggerServer.addGlobalActor(TestActor);
DebuggerServer.init();
DebuggerServer.addBrowserActors();
add_test(init);
add_test(test_client_request_callback);
add_test(test_client_request_promise);
add_test(test_client_request_promise_error);
add_test(test_client_request_event_emitter);
add_test(test_close_client_while_sending_requests);
add_test(test_client_request_after_close);
add_test(test_client_request_after_close_callback);
run_next_test();
}
function init()
{
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect()
.then(() => gClient.listTabs())
.then(aResponse => {
gActorId = aResponse.test;
run_next_test();
});
}
function checkStack(expectedName) {
if (!Services.prefs.getBoolPref("javascript.options.asyncstack")) {
do_print("Async stacks are disabled.");
return;
}
let stack = Components.stack;
while (stack) {
do_print(stack.name);
if (stack.name == expectedName) {
// Reached back to outer function before request
ok(true, "Complete stack");
return;
}
stack = stack.asyncCaller || stack.caller;
}
ok(false, "Incomplete stack");
}
function test_client_request_callback()
{
// Test that DebuggerClient.request accepts a `onResponse` callback as 2nd argument
gClient.request({
to: gActorId,
type: "hello"
}, response => {
do_check_eq(response.from, gActorId);
do_check_eq(response.hello, "world");
checkStack("test_client_request_callback");
run_next_test();
});
}
function test_client_request_promise()
{
// Test that DebuggerClient.request returns a promise that resolves on response
let request = gClient.request({
to: gActorId,
type: "hello"
});
request.then(response => {
do_check_eq(response.from, gActorId);
do_check_eq(response.hello, "world");
checkStack("test_client_request_promise");
run_next_test();
});
}
function test_client_request_promise_error()
{
// Test that DebuggerClient.request returns a promise that reject when server
// returns an explicit error message
let request = gClient.request({
to: gActorId,
type: "error"
});
request.then(() => {
do_throw("Promise shouldn't be resolved on error");
}, response => {
do_check_eq(response.from, gActorId);
do_check_eq(response.error, "code");
do_check_eq(response.message, "human message");
checkStack("test_client_request_promise_error");
run_next_test();
});
}
function test_client_request_event_emitter()
{
// Test that DebuggerClient.request returns also an EventEmitter object
let request = gClient.request({
to: gActorId,
type: "hello"
});
request.on("json-reply", reply => {
do_check_eq(reply.from, gActorId);
do_check_eq(reply.hello, "world");
checkStack("test_client_request_event_emitter");
run_next_test();
});
}
function test_close_client_while_sending_requests() {
// First send a first request that will be "active"
// while the connection is closed.
// i.e. will be sent but no response received yet.
let activeRequest = gClient.request({
to: gActorId,
type: "hello"
});
// Pile up a second one that will be "pending".
// i.e. won't event be sent.
let pendingRequest = gClient.request({
to: gActorId,
type: "hello"
});
let expectReply = promise.defer();
gClient.expectReply("root", function (response) {
do_check_eq(response.error, "connectionClosed");
do_check_eq(response.message, "server side packet can't be received as the connection just closed.");
expectReply.resolve();
});
gClient.close().then(() => {
activeRequest.then(() => {
ok(false, "First request unexpectedly succeed while closing the connection");
}, response => {
do_check_eq(response.error, "connectionClosed");
do_check_eq(response.message, "'hello' active request packet to '" + gActorId + "' can't be sent as the connection just closed.");
})
.then(() => pendingRequest)
.then(() => {
ok(false, "Second request unexpectedly succeed while closing the connection");
}, response => {
do_check_eq(response.error, "connectionClosed");
do_check_eq(response.message, "'hello' pending request packet to '" + gActorId + "' can't be sent as the connection just closed.");
})
.then(() => expectReply.promise)
.then(run_next_test);
});
}
function test_client_request_after_close()
{
// Test that DebuggerClient.request fails after we called client.close()
// (with promise API)
let request = gClient.request({
to: gActorId,
type: "hello"
});
request.then(response => {
ok(false, "Request succeed even after client.close");
}, response => {
ok(true, "Request failed after client.close");
do_check_eq(response.error, "connectionClosed");
ok(response.message.match(/'hello' request packet to '.*' can't be sent as the connection is closed./));
run_next_test();
});
}
function test_client_request_after_close_callback()
{
// Test that DebuggerClient.request fails after we called client.close()
// (with callback API)
let request = gClient.request({
to: gActorId,
type: "hello"
}, response => {
ok(true, "Request failed after client.close");
do_check_eq(response.error, "connectionClosed");
ok(response.message.match(/'hello' request packet to '.*' can't be sent as the connection is closed./));
run_next_test();
});
}

View file

@ -0,0 +1,61 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check conditional breakpoint when condition evaluates to true.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-conditional-breakpoint");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-conditional-breakpoint", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
do_test_pending();
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
source.setBreakpoint({
line: 3,
condition: "a === 1"
}, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.frame.where.line, 3);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Components.utils.evalInSandbox("debugger;\n" + // 1
"var a = 1;\n" + // 2
"var b = 2;\n", // 3
gDebuggee,
"1.8",
"test.js",
1);
}

View file

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check conditional breakpoint when condition evaluates to false.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-conditional-breakpoint");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-conditional-breakpoint", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
do_test_pending();
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
source.setBreakpoint({
line: 3,
condition: "a === 2"
}, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.why.type, "debuggerStatement");
do_check_eq(aPacket.frame.where.line, 4);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Components.utils.evalInSandbox("debugger;\n" + // 1
"var a = 1;\n" + // 2
"var b = 2;\n" + // 3
"debugger;", // 4
gDebuggee,
"1.8",
"test.js",
1);
}

View file

@ -0,0 +1,61 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check conditional breakpoint when condition throws and make sure it pauses
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-conditional-breakpoint");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-conditional-breakpoint", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
do_test_pending();
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let source = gThreadClient.source(aPacket.frame.where.source);
source.setBreakpoint({
line: 3,
condition: "throw new Error()"
}, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.why.type, "breakpointConditionThrown");
do_check_eq(aPacket.frame.where.line, 3);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
Components.utils.evalInSandbox("debugger;\n" + // 1
"var a = 1;\n" + // 2
"var b = 2;\n", // 3
gDebuggee,
"1.8",
"test.js",
1);
}

View file

@ -0,0 +1,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();
}

View file

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gClient;
var gTabClient;
var gDebuggee;
function run_test()
{
initTestDebuggerServer();
gDebuggee = testGlobal("test-1");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect().then(function ([aType, aTraits]) {
attachTestTab(gClient, "test-1", function (aReply, aTabClient) {
gTabClient = aTabClient;
test_threadAttach(aReply.threadActor);
});
});
do_test_pending();
}
function test_threadAttach(aThreadActorID)
{
do_print("Trying to attach to thread " + aThreadActorID);
gTabClient.attachThread({}, function (aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused");
do_check_eq(aThreadClient.actor, aThreadActorID);
aThreadClient.resume(function () {
do_check_eq(aThreadClient.state, "attached");
test_debugger_statement(aThreadClient);
});
});
}
function test_debugger_statement(aThreadClient)
{
aThreadClient.addListener("paused", function (aEvent, aPacket) {
do_check_eq(aThreadClient.state, "paused");
// 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);
let xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
do_check_eq(xpcInspector.eventLoopNestLevel, 1);
aThreadClient.resume(cleanup);
});
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);
}
function cleanup()
{
gClient.addListener("closed", function (aEvent) {
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();
}

View file

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test()
{
// Should get an exception if we try to interact with DebuggerServer
// before we initialize it...
check_except(function () {
DebuggerServer.createListener();
});
check_except(DebuggerServer.closeAllListeners);
check_except(DebuggerServer.connectPipe);
// Allow incoming connections.
DebuggerServer.init();
// These should still fail because we haven't added a createRootActor
// implementation yet.
check_except(function () {
DebuggerServer.createListener();
});
check_except(DebuggerServer.closeAllListeners);
check_except(DebuggerServer.connectPipe);
DebuggerServer.registerModule("xpcshell-test/testactors");
// Now they should work.
DebuggerServer.createListener();
DebuggerServer.closeAllListeners();
// Make sure we got the test's root actor all set up.
let client1 = DebuggerServer.connectPipe();
client1.hooks = {
onPacket: function (aPacket1) {
do_check_eq(aPacket1.from, "root");
do_check_eq(aPacket1.applicationType, "xpcshell-tests");
// Spin up a second connection, make sure it has its own root
// actor.
let client2 = DebuggerServer.connectPipe();
client2.hooks = {
onPacket: function (aPacket2) {
do_check_eq(aPacket2.from, "root");
do_check_neq(aPacket1.testConnectionPrefix,
aPacket2.testConnectionPrefix);
client2.close();
},
onClosed: function (aResult) {
client1.close();
},
};
client2.ready();
},
onClosed: function (aResult) {
do_test_finished();
},
};
client1.ready();
do_test_pending();
}

View file

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check basic eval resume/re-pause
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_eval();
});
});
do_test_pending();
}
function test_simple_eval()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let arg1Actor = aPacket.frame.arguments[0].actor;
gThreadClient.eval(null, "({ obj: true })", function (aResponse) {
do_check_eq(aResponse.type, "resumed");
// Expect a pause notification immediately.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value...
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "clientEvaluated");
do_check_eq(aPacket.why.frameFinished.return.type, "object");
do_check_eq(aPacket.why.frameFinished.return.class, "Object");
// Make sure the previous pause lifetime was correctly dropped.
gClient.request({ to: arg1Actor, type: "bogusRequest" }, function (aResponse) {
do_check_eq(aResponse.error, "noSuchActor");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(arg1) { debugger; }
stopMe({obj: true});
} + ")()");
}

View file

@ -0,0 +1,48 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check eval resume/re-pause with a throw.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_throw_eval();
});
});
do_test_pending();
}
function test_throw_eval()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.eval(null, "throw 'failure'", function (aResponse) {
do_check_eq(aResponse.type, "resumed");
// Expect a pause notification immediately.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value...
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "clientEvaluated");
do_check_eq(aPacket.why.frameFinished.throw, "failure");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(arg1) { debugger; }
stopMe({obj: true});
} + ")()");
}

View file

@ -0,0 +1,50 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check syntax errors in an eval.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_syntax_error_eval();
});
});
do_test_pending();
}
function test_syntax_error_eval()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.eval(null, "%$@!@#", function (aResponse) {
do_check_eq(aResponse.type, "resumed");
// Expect a pause notification immediately.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value...
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "clientEvaluated");
do_check_eq(aPacket.why.frameFinished.throw.type, "object");
do_check_eq(aPacket.why.frameFinished.throw.class, "Error");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(arg1) { debugger; }
stopMe({obj: true});
} + ")()");
}

View file

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check evals against different frames.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_syntax_error_eval();
});
});
do_test_pending();
}
function test_syntax_error_eval()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.getFrames(0, 2, function (aResponse) {
let frame0 = aResponse.frames[0];
let frame1 = aResponse.frames[1];
// Eval against the top frame...
gThreadClient.eval(frame0.actor, "arg", function (aResponse) {
do_check_eq(aResponse.type, "resumed");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// 'arg' should have been evaluated in frame0
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "clientEvaluated");
do_check_eq(aPacket.why.frameFinished.return, "arg0");
// Now eval against the second frame.
gThreadClient.eval(frame1.actor, "arg", function (aResponse) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// 'arg' should have been evaluated in frame1
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.frameFinished.return, "arg1");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
});
});
});
});
gDebuggee.eval("(" + function () {
function frame0(arg) {
debugger;
}
function frame1(arg) {
frame0("arg0");
}
frame1("arg1");
} + ")()");
}

View file

@ -0,0 +1,54 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check pauses within evals.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_syntax_error_eval();
});
});
do_test_pending();
}
function test_syntax_error_eval()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.eval(null, "debugger", function (aResponse) {
// Expect a resume then a debuggerStatement pause.
do_check_eq(aResponse.type, "resumed");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "debuggerStatement");
// Resume from the debugger statement should immediately re-pause
// with a clientEvaluated reason.
gThreadClient.resume(function (aPacket) {
do_check_eq(aPacket.type, "resumed");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "clientEvaluated");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(arg) {
debugger;
}
stopMe();
} + ")()");
}

View file

@ -0,0 +1,59 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test the eventLoopLag actor.
*/
"use strict";
function run_test()
{
let {EventLoopLagFront} = require("devtools/shared/fronts/eventlooplag");
DebuggerServer.init();
DebuggerServer.addBrowserActors();
// As seen in EventTracer.cpp
let threshold = 20;
let interval = 10;
let front;
let client = new DebuggerClient(DebuggerServer.connectPipe());
// Start tracking event loop lags.
client.connect().then(function () {
client.listTabs(function (resp) {
front = new EventLoopLagFront(client, resp);
front.start().then(success => {
do_check_true(success);
front.once("event-loop-lag", gotLagEvent);
do_execute_soon(lag);
});
});
});
// Force a lag
function lag() {
let start = new Date();
let duration = threshold + interval + 1;
while (true) {
if (((new Date()) - start) > duration) {
break;
}
}
}
// Got a lag event. The test will time out if the actor
// fails to detect the lag.
function gotLagEvent(time) {
do_print("lag: " + time);
do_check_true(time >= threshold);
front.stop().then(() => {
finishClient(client);
});
}
do_test_pending();
}

View file

@ -0,0 +1,196 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* Exercise prefix-based forwarding of packets to other transports. */
const { RootActor } = require("devtools/server/actors/root");
var gMainConnection, gMainTransport;
var gSubconnection1, gSubconnection2;
var gClient;
function run_test()
{
DebuggerServer.init();
add_test(createMainConnection);
add_test(TestNoForwardingYet);
add_test(createSubconnection1);
add_test(TestForwardPrefix1OnlyRoot);
add_test(createSubconnection2);
add_test(TestForwardPrefix12OnlyRoot);
add_test(TestForwardPrefix12WithActor1);
add_test(TestForwardPrefix12WithActor12);
run_next_test();
}
/*
* Create a pipe connection, and return an object |{ conn, transport }|,
* where |conn| is the new DebuggerServerConnection instance, and
* |transport| is the client side of the transport on which it communicates
* (that is, packets sent on |transport| go to the new connection, and
* |transport|'s hooks receive replies).
*
* |aPrefix| is optional; if present, it's the prefix (minus the '/') for
* actors in the new connection.
*/
function newConnection(aPrefix)
{
var conn;
DebuggerServer.createRootActor = function (aConn) {
conn = aConn;
return new RootActor(aConn, {});
};
var transport = DebuggerServer.connectPipe(aPrefix);
return { conn: conn, transport: transport };
}
/* Create the main connection for these tests. */
function createMainConnection()
{
({ conn: gMainConnection, transport: gMainTransport } = newConnection());
gClient = new DebuggerClient(gMainTransport);
gClient.connect().then(([aType, aTraits]) => run_next_test());
}
/*
* Exchange 'echo' messages with five actors:
* - root
* - prefix1/root
* - prefix1/actor
* - prefix2/root
* - prefix2/actor
*
* Expect proper echos from those named in |aReachables|, and 'noSuchActor'
* errors from the others. When we've gotten all our replies (errors or
* otherwise), call |aCompleted|.
*
* To avoid deep stacks, we call aCompleted from the next tick.
*/
function tryActors(aReachables, aCompleted) {
let count = 0;
let outerActor;
for (outerActor of [ "root",
"prefix1/root", "prefix1/actor",
"prefix2/root", "prefix2/actor" ]) {
/*
* Let each callback capture its own iteration's value; outerActor is
* local to the whole loop, not to a single iteration.
*/
let actor = outerActor;
count++;
gClient.request({ to: actor, type: "echo", value: "tango"}, // phone home
(aResponse) => {
if (aReachables.has(actor))
do_check_matches({ from: actor, to: actor, type: "echo", value: "tango" }, aResponse);
else
do_check_matches({ from: actor, error: "noSuchActor", message: "No such actor for ID: " + actor }, aResponse);
if (--count == 0)
do_execute_soon(aCompleted, "tryActors callback " + aCompleted.name);
});
}
}
/*
* With no forwarding established, sending messages to root should work,
* but sending messages to prefixed actor names, or anyone else, should get
* an error.
*/
function TestNoForwardingYet()
{
tryActors(new Set(["root"]), run_next_test);
}
/*
* Create a new pipe connection which forwards its reply packets to
* gMainConnection's client, and to which gMainConnection forwards packets
* directed to actors whose names begin with |aPrefix + '/'|, and.
*
* Return an object { conn, transport }, as for newConnection.
*/
function newSubconnection(aPrefix)
{
let { conn, transport } = newConnection(aPrefix);
transport.hooks = {
onPacket: (aPacket) => gMainConnection.send(aPacket),
onClosed: () => {}
};
gMainConnection.setForwarding(aPrefix, transport);
return { conn: conn, transport: transport };
}
/* Create a second root actor, to which we can forward things. */
function createSubconnection1()
{
let { conn, transport } = newSubconnection("prefix1");
gSubconnection1 = conn;
transport.ready();
gClient.expectReply("prefix1/root", (aReply) => run_next_test());
}
// Establish forwarding, but don't put any actors in that server.
function TestForwardPrefix1OnlyRoot()
{
tryActors(new Set(["root", "prefix1/root"]), run_next_test);
}
/* Create a third root actor, to which we can forward things. */
function createSubconnection2()
{
let { conn, transport } = newSubconnection("prefix2");
gSubconnection2 = conn;
transport.ready();
gClient.expectReply("prefix2/root", (aReply) => run_next_test());
}
function TestForwardPrefix12OnlyRoot()
{
tryActors(new Set(["root", "prefix1/root", "prefix2/root"]), run_next_test);
}
// A dumb actor that implements 'echo'.
//
// It's okay that both subconnections' actors behave identically, because
// the reply-sending code attaches the replying actor's name to the packet,
// so simply matching the 'from' field in the reply ensures that we heard
// from the right actor.
function EchoActor(aConnection)
{
this.conn = aConnection;
}
EchoActor.prototype.actorPrefix = "EchoActor";
EchoActor.prototype.onEcho = function (aRequest) {
/*
* Request packets are frozen. Copy aRequest, so that
* DebuggerServerConnection.onPacket can attach a 'from' property.
*/
return JSON.parse(JSON.stringify(aRequest));
};
EchoActor.prototype.requestTypes = {
"echo": EchoActor.prototype.onEcho
};
function TestForwardPrefix12WithActor1()
{
let actor = new EchoActor(gSubconnection1);
actor.actorID = "prefix1/actor";
gSubconnection1.addActor(actor);
tryActors(new Set(["root", "prefix1/root", "prefix1/actor", "prefix2/root"]), run_next_test);
}
function TestForwardPrefix12WithActor12()
{
let actor = new EchoActor(gSubconnection2);
actor.actorID = "prefix2/actor";
gSubconnection2.addActor(actor);
tryActors(new Set(["root", "prefix1/root", "prefix1/actor", "prefix2/root", "prefix2/actor"]), run_next_test);
}

View file

@ -0,0 +1,43 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Verify that we get a frame actor along with a debugger statement.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_true(!!aPacket.frame);
do_check_true(!!aPacket.frame.actor);
do_check_eq(aPacket.frame.callee.name, "stopMe");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
gDebuggee.eval("(" + function () {
function stopMe() {
debugger;
}
stopMe();
} + ")()");
}

View file

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Verify that two pauses in a row will keep the same frame actor.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket1) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket2) {
do_check_eq(aPacket1.frame.actor, aPacket2.frame.actor);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
gThreadClient.resume();
});
gDebuggee.eval("(" + function () {
function stopMe() {
debugger;
debugger;
}
stopMe();
} + ")()");
}

View file

@ -0,0 +1,47 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Verify that a frame actor is properly expired when the frame goes away.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket1) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket2) {
let poppedFrames = aPacket2.poppedFrames;
do_check_eq(typeof (poppedFrames), typeof ([]));
do_check_true(poppedFrames.indexOf(aPacket1.frame.actor) >= 0);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
gThreadClient.resume();
});
gDebuggee.eval("(" + function () {
function stopMe() {
debugger;
}
stopMe();
debugger;
} + ")()");
}

View file

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Verify the "frames" request on the thread.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
var gFrames = [
// Function calls...
{ type: "call", callee: { name: "depth3" } },
{ type: "call", callee: { name: "depth2" } },
{ type: "call", callee: { name: "depth1" } },
// Anonymous function call in our eval...
{ type: "call", callee: { name: undefined } },
// The eval itself.
{ type: "eval", callee: { name: undefined } },
];
var gSliceTests = [
{ start: 0, count: undefined, resetActors: true },
{ start: 0, count: 1 },
{ start: 2, count: 2 },
{ start: 1, count: 15 },
{ start: 15, count: undefined },
];
function test_frame_slice() {
if (gSliceTests.length == 0) {
gThreadClient.resume(function () { finishClient(gClient); });
return;
}
let test = gSliceTests.shift();
gThreadClient.getFrames(test.start, test.count, function (aResponse) {
var testFrames = gFrames.slice(test.start, test.count ? test.start + test.count : undefined);
do_check_eq(testFrames.length, aResponse.frames.length);
for (var i = 0; i < testFrames.length; i++) {
let expected = testFrames[i];
let actual = aResponse.frames[i];
if (test.resetActors) {
expected.actor = actual.actor;
}
for (let key of ["type", "callee-name"]) {
do_check_eq(expected[key] || undefined, actual[key]);
}
}
test_frame_slice();
});
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket1) {
test_frame_slice();
});
gDebuggee.eval("(" + function () {
function depth3() {
debugger;
}
function depth2() {
depth3();
}
function depth1() {
depth2();
}
depth1();
} + ")()");
}

View file

@ -0,0 +1,89 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Verify that frame actors retrieved with the frames request
* are included in the pause packet's popped-frames property.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_frame_slice() {
if (gSliceTests.length == 0) {
gThreadClient.resume(function () { finishClient(gClient); });
return;
}
let test = gSliceTests.shift();
gThreadClient.getFrames(test.start, test.count, function (aResponse) {
var testFrames = gFrames.slice(test.start, test.count ? test.start + test.count : undefined);
do_check_eq(testFrames.length, aResponse.frames.length);
for (var i = 0; i < testFrames.length; i++) {
let expected = testFrames[i];
let actual = aResponse.frames[i];
if (test.resetActors) {
expected.actor = actual.actor;
}
for (var key in expected) {
do_check_eq(expected[key], actual[key]);
}
}
test_frame_slice();
});
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket1) {
gThreadClient.getFrames(0, null, function (aFrameResponse) {
do_check_eq(aFrameResponse.frames.length, 5);
// Now wait for the next pause, after which the three
// youngest actors should be popped..
let expectPopped = aFrameResponse.frames.slice(0, 3).map(frame => frame.actor);
expectPopped.sort();
gThreadClient.addOneTimeListener("paused", function (aEvent, aPausePacket) {
let popped = aPausePacket.poppedFrames.sort();
do_check_eq(popped.length, 3);
for (let i = 0; i < 3; i++) {
do_check_eq(expectPopped[i], popped[i]);
}
gThreadClient.resume(function () { finishClient(gClient); });
});
gThreadClient.resume();
});
});
gDebuggee.eval("(" + function () {
function depth3() {
debugger;
}
function depth2() {
depth3();
}
function depth1() {
depth2();
}
depth1();
debugger;
} + ")()");
}

View file

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check a frame actor's arguments property.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let args = aPacket.frame["arguments"];
do_check_eq(args.length, 6);
do_check_eq(args[0], 42);
do_check_eq(args[1], true);
do_check_eq(args[2], "nasu");
do_check_eq(args[3].type, "null");
do_check_eq(args[4].type, "undefined");
do_check_eq(args[5].type, "object");
do_check_eq(args[5].class, "Object");
do_check_true(!!args[5].actor);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
gDebuggee.eval("(" + function () {
function stopMe(aNumber, aBool, aString, aNull, aUndefined, aObject) {
debugger;
}
stopMe(42, true, "nasu", null, undefined, { foo: "bar" });
} + ")()");
}

View file

@ -0,0 +1,77 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check a frame actor's bindings property.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let bindings = aPacket.frame.environment.bindings;
let args = bindings.arguments;
let vars = bindings.variables;
do_check_eq(args.length, 6);
do_check_eq(args[0].aNumber.value, 42);
do_check_eq(args[1].aBool.value, true);
do_check_eq(args[2].aString.value, "nasu");
do_check_eq(args[3].aNull.value.type, "null");
do_check_eq(args[4].aUndefined.value.type, "undefined");
do_check_eq(args[5].aObject.value.type, "object");
do_check_eq(args[5].aObject.value.class, "Object");
do_check_true(!!args[5].aObject.value.actor);
do_check_eq(vars.a.value, 1);
do_check_eq(vars.b.value, true);
do_check_eq(vars.c.value.type, "object");
do_check_eq(vars.c.value.class, "Object");
do_check_true(!!vars.c.value.actor);
let objClient = gThreadClient.pauseGrip(vars.c.value);
objClient.getPrototypeAndProperties(function (aResponse) {
do_check_eq(aResponse.ownProperties.a.configurable, true);
do_check_eq(aResponse.ownProperties.a.enumerable, true);
do_check_eq(aResponse.ownProperties.a.writable, true);
do_check_eq(aResponse.ownProperties.a.value, "a");
do_check_eq(aResponse.ownProperties.b.configurable, true);
do_check_eq(aResponse.ownProperties.b.enumerable, true);
do_check_eq(aResponse.ownProperties.b.writable, true);
do_check_eq(aResponse.ownProperties.b.value.type, "undefined");
do_check_false("class" in aResponse.ownProperties.b.value);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(aNumber, aBool, aString, aNull, aUndefined, aObject) {
var a = 1;
var b = true;
var c = { a: "a", b: undefined };
debugger;
}
stopMe(42, true, "nasu", null, undefined, { foo: "bar" });
} + ")()");
}

View file

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check a frame actor's parent bindings.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let parentEnv = aPacket.frame.environment.parent;
let bindings = parentEnv.bindings;
let args = bindings.arguments;
let vars = bindings.variables;
do_check_neq(parentEnv, undefined);
do_check_eq(args.length, 0);
do_check_eq(vars.stopMe.value.type, "object");
do_check_eq(vars.stopMe.value.class, "Function");
do_check_true(!!vars.stopMe.value.actor);
// Skip the global lexical scope.
parentEnv = parentEnv.parent.parent;
do_check_neq(parentEnv, undefined);
let objClient = gThreadClient.pauseGrip(parentEnv.object);
objClient.getPrototypeAndProperties(function (aResponse) {
do_check_eq(aResponse.ownProperties.Object.value.type, "object");
do_check_eq(aResponse.ownProperties.Object.value.class, "Function");
do_check_true(!!aResponse.ownProperties.Object.value.actor);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(aNumber, aBool, aString, aNull, aUndefined, aObject) {
var a = 1;
var b = true;
var c = { a: "a" };
debugger;
}
stopMe(42, true, "nasu", null, undefined, { foo: "bar" });
} + ")()");
}

View file

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check a |with| frame actor's bindings.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let env = aPacket.frame.environment;
do_check_neq(env, undefined);
let parentEnv = env.parent;
do_check_neq(parentEnv, undefined);
let bindings = parentEnv.bindings;
let args = bindings.arguments;
let vars = bindings.variables;
do_check_eq(args.length, 1);
do_check_eq(args[0].aNumber.value, 10);
do_check_eq(vars.r.value, 10);
do_check_eq(vars.a.value, Math.PI * 100);
do_check_eq(vars.arguments.value.class, "Arguments");
do_check_true(!!vars.arguments.value.actor);
let objClient = gThreadClient.pauseGrip(env.object);
objClient.getPrototypeAndProperties(function (aResponse) {
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
do_check_true(!!aResponse.ownProperties.cos.value.actor);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(aNumber) {
var a;
var r = aNumber;
with (Math) {
a = PI * r * r;
debugger;
}
}
stopMe(10);
} + ")()");
}

View file

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check the environment bindongs of a |with| within a |with|.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let env = aPacket.frame.environment;
do_check_neq(env, undefined);
let objClient = gThreadClient.pauseGrip(env.object);
objClient.getPrototypeAndProperties(function (aResponse) {
do_check_eq(aResponse.ownProperties.one.value, 1);
do_check_eq(aResponse.ownProperties.two.value, 2);
do_check_eq(aResponse.ownProperties.foo, undefined);
let parentEnv = env.parent;
do_check_neq(parentEnv, undefined);
let parentClient = gThreadClient.pauseGrip(parentEnv.object);
parentClient.getPrototypeAndProperties(function (aResponse) {
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
do_check_true(!!aResponse.ownProperties.cos.value.actor);
parentEnv = parentEnv.parent;
do_check_neq(parentEnv, undefined);
let bindings = parentEnv.bindings;
let args = bindings.arguments;
let vars = bindings.variables;
do_check_eq(args.length, 1);
do_check_eq(args[0].aNumber.value, 10);
do_check_eq(vars.r.value, 10);
do_check_eq(vars.a.value, Math.PI * 100);
do_check_eq(vars.arguments.value.class, "Arguments");
do_check_true(!!vars.arguments.value.actor);
do_check_eq(vars.foo.value, 2 * Math.PI);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("(" + function () {
function stopMe(aNumber) {
var a, obj = { one: 1, two: 2 };
var r = aNumber;
with (Math) {
a = PI * r * r;
with (obj) {
var foo = two * PI;
debugger;
}
}
}
stopMe(10);
} + ")()");
}

View file

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check the environment bindings of a |with| in global scope.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let env = aPacket.frame.environment;
do_check_neq(env, undefined);
let objClient = gThreadClient.pauseGrip(env.object);
objClient.getPrototypeAndProperties(function (aResponse) {
do_check_eq(aResponse.ownProperties.PI.value, Math.PI);
do_check_eq(aResponse.ownProperties.cos.value.type, "object");
do_check_eq(aResponse.ownProperties.cos.value.class, "Function");
do_check_true(!!aResponse.ownProperties.cos.value.actor);
// Skip the global lexical scope.
let parentEnv = env.parent.parent;
do_check_neq(parentEnv, undefined);
let parentClient = gThreadClient.pauseGrip(parentEnv.object);
parentClient.getPrototypeAndProperties(function (aResponse) {
do_check_eq(aResponse.ownProperties.a.value, Math.PI * 100);
do_check_eq(aResponse.ownProperties.r.value, 10);
do_check_eq(aResponse.ownProperties.Object.value.type, "object");
do_check_eq(aResponse.ownProperties.Object.value.class, "Function");
do_check_true(!!aResponse.ownProperties.Object.value.actor);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("var a, r = 10;\n" +
"with (Math) {\n" +
" a = PI * r * r;\n" +
" debugger;\n" +
"}");
}

View file

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-grips");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-grips", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_banana_environment();
});
});
do_test_pending();
}
function test_banana_environment()
{
gThreadClient.addOneTimeListener("paused",
function (aEvent, aPacket) {
equal(aPacket.type, "paused");
let env = aPacket.frame.environment;
equal(env.type, "function");
equal(env.function.name, "banana3");
let parent = env.parent;
equal(parent.type, "block");
ok("banana3" in parent.bindings.variables);
parent = parent.parent;
equal(parent.type, "function");
equal(parent.function.name, "banana2");
parent = parent.parent;
equal(parent.type, "block");
ok("banana2" in parent.bindings.variables);
parent = parent.parent;
equal(parent.type, "function");
equal(parent.function.name, "banana");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
gDebuggee.eval("\
function banana(x) { \n\
return function banana2(y) { \n\
return function banana3(z) { \n\
debugger; \n\
}; \n\
}; \n\
} \n\
banana('x')('y')('z'); \n\
");
}

View file

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gDebuggee;
var gClient;
var gThreadClient;
// Test that the EnvironmentClient's getBindings() method works as expected.
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-bindings");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-bindings", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_banana_environment();
});
});
do_test_pending();
}
function test_banana_environment()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let environment = aPacket.frame.environment;
do_check_eq(environment.type, "function");
let parent = environment.parent;
do_check_eq(parent.type, "block");
let grandpa = parent.parent;
do_check_eq(grandpa.type, "function");
let envClient = gThreadClient.environment(environment);
envClient.getBindings(aResponse => {
do_check_eq(aResponse.bindings.arguments[0].z.value, "z");
let parentClient = gThreadClient.environment(parent);
parentClient.getBindings(aResponse => {
do_check_eq(aResponse.bindings.variables.banana3.value.class, "Function");
let grandpaClient = gThreadClient.environment(grandpa);
grandpaClient.getBindings(aResponse => {
do_check_eq(aResponse.bindings.arguments[0].y.value, "y");
gThreadClient.resume(() => finishClient(gClient));
});
});
});
});
gDebuggee.eval("\
function banana(x) { \n\
return function banana2(y) { \n\
return function banana3(z) { \n\
debugger; \n\
}; \n\
}; \n\
} \n\
banana('x')('y')('z'); \n\
");
}

View file

@ -0,0 +1,53 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.addOneTimeListener("framesadded", function () {
do_check_eq(gThreadClient.cachedFrames.length, 3);
do_check_true(gThreadClient.moreFrames);
do_check_false(gThreadClient.fillFrames(3));
do_check_true(gThreadClient.fillFrames(30));
gThreadClient.addOneTimeListener("framesadded", function () {
do_check_false(gThreadClient.moreFrames);
do_check_eq(gThreadClient.cachedFrames.length, 7);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
do_check_true(gThreadClient.fillFrames(3));
});
gDebuggee.eval("(" + function () {
var recurseLeft = 5;
function recurse() {
if (--recurseLeft == 0) {
debugger;
return;
}
recurse();
}
recurse();
} + ")()");
}

View file

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_pause_frame();
});
});
do_test_pending();
}
function test_pause_frame()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Ask for exactly the number of frames we expect.
gThreadClient.addOneTimeListener("framesadded", function () {
do_check_false(gThreadClient.moreFrames);
gThreadClient.resume(function () {
finishClient(gClient);
});
});
do_check_true(gThreadClient.fillFrames(3));
});
gDebuggee.eval("(" + function () {
var recurseLeft = 1;
function recurse() {
if (--recurseLeft == 0) {
debugger;
return;
}
recurse();
}
recurse();
} + ")()");
}

View file

@ -0,0 +1,95 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-grips");
gDebuggee.eval(function stopMe(arg1) {
debugger;
}.toString());
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function () {
attachTestTabAndResume(gClient, "test-grips", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_named_function();
});
});
do_test_pending();
}
function test_named_function()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let args = aPacket.frame.arguments;
do_check_eq(args[0].class, "Function");
do_check_eq(args[0].name, "stopMe");
do_check_eq(args[0].displayName, "stopMe");
let objClient = gThreadClient.pauseGrip(args[0]);
objClient.getParameterNames(function (aResponse) {
do_check_eq(aResponse.parameterNames.length, 1);
do_check_eq(aResponse.parameterNames[0], "arg1");
gThreadClient.resume(test_inferred_name_function);
});
});
gDebuggee.eval("stopMe(stopMe)");
}
function test_inferred_name_function() {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let args = aPacket.frame.arguments;
do_check_eq(args[0].class, "Function");
// No name for an anonymous function, but it should have an inferred name.
do_check_eq(args[0].name, undefined);
do_check_eq(args[0].displayName, "o.m");
let objClient = gThreadClient.pauseGrip(args[0]);
objClient.getParameterNames(function (aResponse) {
do_check_eq(aResponse.parameterNames.length, 3);
do_check_eq(aResponse.parameterNames[0], "foo");
do_check_eq(aResponse.parameterNames[1], "bar");
do_check_eq(aResponse.parameterNames[2], "baz");
gThreadClient.resume(test_anonymous_function);
});
});
gDebuggee.eval("var o = { m: function(foo, bar, baz) { } }; stopMe(o.m)");
}
function test_anonymous_function() {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let args = aPacket.frame.arguments;
do_check_eq(args[0].class, "Function");
// No name for an anonymous function, and no inferred name, either.
do_check_eq(args[0].name, undefined);
do_check_eq(args[0].displayName, undefined);
let objClient = gThreadClient.pauseGrip(args[0]);
objClient.getParameterNames(function (aResponse) {
do_check_eq(aResponse.parameterNames.length, 3);
do_check_eq(aResponse.parameterNames[0], "foo");
do_check_eq(aResponse.parameterNames[1], "bar");
do_check_eq(aResponse.parameterNames[2], "baz");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
gDebuggee.eval("stopMe(function(foo, bar, baz) { })");
}

View file

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Test if getExecutableLines return correct information
*/
var gDebuggee;
var gClient;
var gThreadClient;
const SOURCE_MAPPED_FILE = getFileUrl("sourcemapped.js");
function run_test() {
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-get-executable-lines");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function _onConnect() {
attachTestTabAndResume(
gClient,
"test-get-executable-lines",
function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_executable_lines();
}
);
});
do_test_pending();
}
function test_executable_lines() {
gThreadClient.addOneTimeListener("newSource", function _onNewSource(evt, packet) {
do_check_eq(evt, "newSource");
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error);
let source = gThreadClient.source(sources[0]);
source.getExecutableLines(function (lines) {
do_check_true(arrays_equal([1, 2, 4, 6], lines));
finishClient(gClient);
});
});
});
let code = readFile("sourcemapped.js") + "\n//# sourceMappingURL=" +
getFileUrl("source-map-data/sourcemapped.map");
Components.utils.evalInSandbox(code, gDebuggee, "1.8",
SOURCE_MAPPED_FILE, 1);
}
function arrays_equal(a, b) {
return !(a < b || b < a);
}

View file

@ -0,0 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Test if getExecutableLines return correct information
*/
var gDebuggee;
var gClient;
var gThreadClient;
const SOURCE_MAPPED_FILE = getFileUrl("sourcemapped.js");
function run_test() {
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-get-executable-lines");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect().then(function _onConnect() {
attachTestTabAndResume(
gClient,
"test-get-executable-lines",
function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_executable_lines();
}
);
});
do_test_pending();
}
function test_executable_lines() {
gThreadClient.addOneTimeListener("newSource", function _onNewSource(evt, packet) {
do_check_eq(evt, "newSource");
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error);
let source = gThreadClient.source(sources[0]);
source.getExecutableLines(function (lines) {
do_check_true(arrays_equal([2, 5, 7, 8, 10, 12, 14, 16], lines));
finishClient(gClient);
});
});
});
let code = readFile("sourcemapped.js");
Components.utils.evalInSandbox(code, gDebuggee, "1.8",
SOURCE_MAPPED_FILE, 1);
}
function arrays_equal(a, b) {
return !(a < b || b < a);
}

Some files were not shown because too many files have changed in this diff Show more