This commit is contained in:
Tim Taubert 2012-02-07 20:11:47 +01:00
Родитель 9b595b2de8 4cb5f7632b
Коммит 0ae9ffc78e
134 изменённых файлов: 12772 добавлений и 437 удалений

Просмотреть файл

@ -1031,6 +1031,12 @@ pref("devtools.errorconsole.enabled", false);
pref("devtools.inspector.enabled", true);
pref("devtools.inspector.htmlHeight", 112);
// Enable the Debugger
pref("devtools.debugger.enabled", false);
// The default Debugger UI height
pref("devtools.debugger.ui.height", 250);
// Enable the style inspector
pref("devtools.styleinspector.enabled", true);

Просмотреть файл

@ -189,6 +189,11 @@
type="checkbox"
command="Tools:Inspect"
key="key_inspect"/>
<menuitem id="appmenu_debugger"
hidden="true"
label="&debuggerMenu.label;"
key="key_debugger"
command="Tools:Debugger"/>
<menuitem id="appmenu_scratchpad"
hidden="true"
label="&scratchpad.label;"

Просмотреть файл

@ -19,5 +19,7 @@
#endif
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
%aboutHomeDTD;
<!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd">
%debuggerDTD;
]>

Просмотреть файл

@ -546,6 +546,11 @@
accesskey="&inspectMenu.accesskey;"
key="key_inspect"
command="Tools:Inspect"/>
<menuitem id="menu_debugger"
hidden="true"
label="&debuggerMenu.label;"
key="key_debugger"
command="Tools:Debugger"/>
<menuitem id="menu_scratchpad"
hidden="true"
label="&scratchpad.label;"

Просмотреть файл

@ -127,6 +127,7 @@
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
<command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
<command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/>
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
<command id="Tools:StyleEditor" oncommand="StyleEditor.openChrome();" disabled="true"/>
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
@ -250,6 +251,13 @@
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
<key id="key_debugger" key="&debuggerMenu.commandkey;" command="Tools:Debugger"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
<key id="key_inspect" key="&inspectMenu.commandkey;" command="Tools:Inspect"

Просмотреть файл

@ -181,6 +181,12 @@ XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() {
return new tmp.InspectorUI(window);
});
XPCOMUtils.defineLazyGetter(this, "DebuggerUI", function() {
let tmp = {};
Cu.import("resource:///modules/devtools/DebuggerUI.jsm", tmp);
return new tmp.DebuggerUI(window);
});
XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
let tmp = {};
Cu.import("resource:///modules/devtools/Tilt.jsm", tmp);
@ -1729,6 +1735,16 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
#endif
}
// Enable Debugger?
let enabled = gPrefService.getBoolPref("devtools.debugger.enabled");
if (enabled) {
document.getElementById("menu_debugger").hidden = false;
document.getElementById("Tools:Debugger").removeAttribute("disabled");
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_debugger").hidden = false;
#endif
}
// Enable Error Console?
// XXX Temporarily always-enabled, see bug 601201
let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled");

Просмотреть файл

@ -48,6 +48,7 @@
#highlighter-nodeinfobar-container {
position: absolute;
max-width: 95%;
}
#highlighter-nodeinfobar-container:not([disable-transitions]) {
@ -60,15 +61,17 @@
display: block;
white-space: nowrap;
direction: ltr;
overflow: hidden;
text-overflow: ellipsis;
}
#highlighter-nodeinfobar-container[locked] > #highlighter-nodeinfobar {
pointer-events: auto;
}
#highlighter-nodeinfobar-id,
.highlighter-nodeinfobar-class,
#highlighter-nodeinfobar-tagname {
html|*#highlighter-nodeinfobar-id,
html|*#highlighter-nodeinfobar-classes,
html|*#highlighter-nodeinfobar-tagname {
-moz-user-select: text;
cursor: text;
}
@ -89,10 +92,6 @@
visibility: hidden;
}
#highlighter-nodeinfobar-id:empty {
display: none;
}
#highlighter-nodeinfobar-tagname {
html|*#highlighter-nodeinfobar-tagname {
text-transform: lowercase;
}

Просмотреть файл

@ -54,6 +54,7 @@ DIRS = \
styleinspector \
tilt \
scratchpad \
debugger \
shared \
$(NULL)

Просмотреть файл

@ -0,0 +1,377 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Debugger UI code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com> (original author)
* Panos Astithas <past@mozilla.com>
* Victor Porof <vporof@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
/*global Components, NetUtil, Services, XPCOMUtils */
/*global DebuggerServer, DebuggerClient, SourceEditor */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
Cu.import("resource:///modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/source-editor.jsm");
let EXPORTED_SYMBOLS = ["DebuggerUI"];
/**
* Creates a pane that will host the debugger UI.
*/
function DebuggerPane(aTab) {
this._tab = aTab;
this._close = this.close.bind(this);
this._debugTab = this.debugTab.bind(this);
}
DebuggerPane.prototype = {
/**
* Creates and initializes the widgets contained in the debugger UI.
*/
create: function DP_create(gBrowser) {
this._tab._scriptDebugger = this;
this._nbox = gBrowser.getNotificationBox(this._tab.linkedBrowser);
this._splitter = gBrowser.parentNode.ownerDocument.createElement("splitter");
this._splitter.setAttribute("class", "hud-splitter");
this.frame = gBrowser.parentNode.ownerDocument.createElement("iframe");
this.frame.height = DebuggerUIPreferences.height;
this._nbox.appendChild(this._splitter);
this._nbox.appendChild(this.frame);
let self = this;
this.frame.addEventListener("DOMContentLoaded", function initPane(aEvent) {
if (aEvent.target != self.frame.contentDocument) {
return;
}
self.frame.removeEventListener("DOMContentLoaded", initPane, true);
// Initialize the source editor.
self.frame.contentWindow.editor = self.editor = new SourceEditor();
let config = {
mode: SourceEditor.MODES.JAVASCRIPT,
showLineNumbers: true,
readOnly: true
};
let editorPlaceholder = self.frame.contentDocument.getElementById("editor");
self.editor.init(editorPlaceholder, config, self._onEditorLoad.bind(self));
}, true);
this.frame.addEventListener("DebuggerClose", this._close, true);
this.frame.setAttribute("src", "chrome://browser/content/debugger.xul");
},
/**
* The load event handler for the source editor. This method does post-load
* editor initialization.
*/
_onEditorLoad: function DP__onEditorLoad() {
// Connect to the debugger server.
this.connect();
},
/**
* Closes the debugger UI removing child nodes and event listeners.
*/
close: function DP_close() {
if (this._tab) {
this._tab._scriptDebugger = null;
this._tab = null;
}
if (this.frame) {
DebuggerUIPreferences.height = this.frame.height;
this.frame.removeEventListener("unload", this._close, true);
this.frame.removeEventListener("DebuggerClose", this._close, true);
if (this.frame.parentNode) {
this.frame.parentNode.removeChild(this.frame);
}
this.frame = null;
}
if (this._nbox) {
this._nbox.removeChild(this._splitter);
this._nbox = null;
}
this._splitter = null;
if (this._client) {
this._client.removeListener("newScript", this.onNewScript);
this._client.removeListener("tabDetached", this._close);
this._client.removeListener("tabNavigated", this._debugTab);
this._client.close();
this._client = null;
}
},
/**
* Initializes a debugger client and connects it to the debugger server,
* wiring event handlers as necessary.
*/
connect: function DP_connect() {
this.frame.addEventListener("unload", this._close, true);
let transport = DebuggerServer.connectPipe();
this._client = new DebuggerClient(transport);
// Store the new script handler locally, so when it's time to remove it we
// don't need to go through the iframe, since it might be cleared.
this.onNewScript = this.debuggerWindow.SourceScripts.onNewScript;
let self = this;
this._client.addListener("tabNavigated", this._debugTab);
this._client.addListener("tabDetached", this._close);
this._client.addListener("newScript", this.onNewScript);
this._client.connect(function(aType, aTraits) {
self._client.listTabs(function(aResponse) {
let tab = aResponse.tabs[aResponse.selected];
self.debuggerWindow.startDebuggingTab(self._client, tab);
if (self.onConnected) {
self.onConnected(self);
}
});
});
},
/**
* Starts debugging the current tab. This function is called on each location
* change in this tab.
*/
debugTab: function DP_debugTab(aNotification, aPacket) {
let self = this;
this._client.activeThread.detach(function() {
self._client.activeTab.detach(function() {
self._client.listTabs(function(aResponse) {
let tab = aResponse.tabs[aResponse.selected];
self.debuggerWindow.startDebuggingTab(self._client, tab);
if (self.onConnected) {
self.onConnected(self);
}
});
});
});
},
get debuggerWindow() {
return this.frame.contentWindow;
},
get debuggerClient() {
return this._client;
},
get activeThread() {
try {
return this.debuggerWindow.ThreadState.activeThread;
} catch(ex) {
return undefined;
}
}
};
function DebuggerUI(aWindow) {
this.aWindow = aWindow;
aWindow.addEventListener("Debugger:LoadSource", this._onLoadSource.bind(this));
}
DebuggerUI.prototype = {
/**
* Starts the debugger or stops it, if it is already started.
*/
toggleDebugger: function DebuggerUI_toggleDebugger() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
let gBrowser = this.aWindow.gBrowser;
let tab = gBrowser.selectedTab;
if (tab._scriptDebugger) {
// If the debugger is already open, just close it.
tab._scriptDebugger.close();
return tab._scriptDebugger;
}
let pane = new DebuggerPane(tab);
pane.create(gBrowser);
return pane;
},
getDebugger: function DebuggerUI_getDebugger(aTab) {
return aTab._scriptDebugger;
},
get preferences() {
return DebuggerUIPreferences;
},
/**
* Handles notifications to load a source script from the cache or from a
* local file.
* XXX: it may be better to use nsITraceableChannel to get to the sources
* without relying on caching when we can (not for eval, etc.):
* http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
*/
_onLoadSource: function DebuggerUI__onLoadSource(aEvent) {
let gBrowser = this.aWindow.gBrowser;
let url = aEvent.detail;
let scheme = Services.io.extractScheme(url);
switch (scheme) {
case "file":
case "chrome":
case "resource":
try {
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) {
if (!Components.isSuccessCode(aStatus)) {
return this.logError(url, aStatus);
}
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
aStream.close();
this._onSourceLoaded(url, source);
}.bind(this));
} catch (ex) {
return this.logError(url, ex.name);
}
break;
default:
let channel = Services.io.newChannel(url, null, null);
let chunks = [];
let streamListener = { // nsIStreamListener inherits nsIRequestObserver
onStartRequest: function (aRequest, aContext, aStatusCode) {
if (!Components.isSuccessCode(aStatusCode)) {
return this.logError(url, aStatusCode);
}
}.bind(this),
onDataAvailable: function (aRequest, aContext, aStream, aOffset, aCount) {
chunks.push(NetUtil.readInputStreamToString(aStream, aCount));
},
onStopRequest: function (aRequest, aContext, aStatusCode) {
if (!Components.isSuccessCode(aStatusCode)) {
return this.logError(url, aStatusCode);
}
this._onSourceLoaded(url, chunks.join(""));
}.bind(this)
};
channel.loadFlags = channel.LOAD_FROM_CACHE;
channel.asyncOpen(streamListener, null);
break;
}
},
/**
* Log an error message in the error console when a script fails to load.
*
* @param string aUrl
* The URL of the source script.
* @param string aStatus
* The failure status code.
*/
logError: function DebuggerUI_logError(aUrl, aStatus) {
let view = this.getDebugger(gBrowser.selectedTab).DebuggerView;
Components.utils.reportError(view.getFormatStr("loadingError", [ aUrl, aStatus ]));
},
/**
* Called when source has been loaded.
*
* @param string aSourceUrl
* The URL of the source script.
* @param string aSourceText
* The text of the source script.
*/
_onSourceLoaded: function DebuggerUI__onSourceLoaded(aSourceUrl, aSourceText) {
let dbg = this.getDebugger(this.aWindow.gBrowser.selectedTab);
if (aSourceUrl.slice(-3) == ".js") {
dbg.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
} else {
dbg.editor.setMode(SourceEditor.MODES.HTML);
}
dbg.editor.setText(aSourceText);
let doc = dbg.frame.contentDocument;
let scripts = doc.getElementById("scripts");
let elt = scripts.getElementsByAttribute("value", aSourceUrl)[0];
let script = elt.getUserData("sourceScript");
script.loaded = true;
script.text = aSourceText;
elt.setUserData("sourceScript", script, null);
}
};
/**
* Various debugger UI preferences (currently just the pane height).
*/
let DebuggerUIPreferences = {
_height: -1,
/**
* Gets the preferred height of the debugger pane.
*
* @return number
* The preferred height.
*/
get height() {
if (this._height < 0) {
this._height = Services.prefs.getIntPref("devtools.debugger.ui.height");
}
return this._height;
},
/**
* Sets the preferred height of the debugger pane.
*
* @param number value
* The new height.
*/
set height(value) {
Services.prefs.setIntPref("devtools.debugger.ui.height", value);
this._height = value;
}
};

Просмотреть файл

@ -0,0 +1,53 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla Debugger UI code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Dave Camp <dcamp@mozilla.com>
# Victor Porof <vporof@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ifdef ENABLE_TESTS
DIRS += test
endif
include $(topsrcdir)/config/rules.mk
libs::
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,173 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
* Victor Porof <vporof@mozilla.com>
* Panos Astithas <past@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* Debugger content
*/
#dbg-content > * > .vbox {
cursor: default;
}
/**
* Debugger statusbar
*/
#dbg-statusbar {
-moz-appearance: statusbar;
}
/**
* Stack frames
*/
#stack {
width: 200px;
}
#stackframes {
overflow: auto;
}
/**
* Properties elements
*/
#properties {
width: 250px;
}
#variables {
overflow: auto;
}
/**
* Scope element
*/
.scope {
display: -moz-box;
-moz-box-orient: vertical;
}
.scope > .details {
display: none;
}
.scope > .details[open] {
display: -moz-box;
-moz-box-orient: vertical;
}
/**
* Variable element
*/
.variable {
display: -moz-box;
-moz-box-orient: vertical;
}
.variable > .title {
white-space: nowrap;
}
.variable > .details {
display: none;
}
.variable > .details[open] {
display: -moz-box;
-moz-box-orient: vertical;
}
/**
* Property element
*/
.property {
display: -moz-box;
-moz-box-orient: vertical;
}
.property > .title {
white-space: nowrap;
}
.property > .title > .key {
display: inline-block;
}
.property > .title > .value {
display: inline-block;
}
.property > .details {
display: none;
}
.property > .details[open] {
display: -moz-box;
-moz-box-orient: vertical;
}
/**
* Display helpers
*/
.hbox {
display: -moz-box;
-moz-box-orient: horizontal;
}
.vbox {
display: -moz-box;
-moz-box-orient: vertical;
}
.flex {
-moz-box-flex: 1;
}
.unselectable {
-moz-user-select: -moz-none;
cursor: default;
}

Просмотреть файл

@ -0,0 +1,513 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
* Panos Astithas <past@mozilla.com>
* Victor Porof <vporof@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
var gInitialized = false;
var gClient = null;
var gTabClient = null;
function initDebugger()
{
window.removeEventListener("DOMContentLoaded", initDebugger, false);
if (gInitialized) {
return;
}
gInitialized = true;
DebuggerView.Stackframes.initialize();
DebuggerView.Properties.initialize();
DebuggerView.Scripts.initialize();
}
/**
* Called by chrome to set up a debugging session.
*
* @param DebuggerClient aClient
* The debugger client.
* @param object aTabGrip
* The remote protocol grip of the tab.
*/
function startDebuggingTab(aClient, aTabGrip)
{
gClient = aClient;
gClient.attachTab(aTabGrip.actor, function(aResponse, aTabClient) {
if (aTabClient) {
gTabClient = aTabClient;
gClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) {
if (!aThreadClient) {
dump("Couldn't attach to thread: "+aResponse.error+"\n");
return;
}
ThreadState.connect(aThreadClient, function() {
StackFrames.connect(aThreadClient, function() {
SourceScripts.connect(aThreadClient, function() {
aThreadClient.resume();
});
});
});
});
}
});
}
function shutdownDebugger()
{
window.removeEventListener("unload", shutdownDebugger, false);
SourceScripts.disconnect();
StackFrames.disconnect();
ThreadState.disconnect();
ThreadState.activeThread = false;
DebuggerView.Stackframes.destroy();
DebuggerView.Properties.destroy();
DebuggerView.Scripts.destroy();
}
/**
* ThreadState keeps the UI up to date with the state of the
* thread (paused/attached/etc.).
*/
var ThreadState = {
activeThread: null,
/**
* Connect to a thread client.
* @param object aThreadClient
* The thread client.
* @param function aCallback
* The next function in the initialization sequence.
*/
connect: function TS_connect(aThreadClient, aCallback) {
this.activeThread = aThreadClient;
aThreadClient.addListener("paused", ThreadState.update);
aThreadClient.addListener("resumed", ThreadState.update);
aThreadClient.addListener("detached", ThreadState.update);
this.update();
aCallback && aCallback();
},
/**
* Update the UI after a thread state change.
*/
update: function TS_update(aEvent) {
DebuggerView.Stackframes.updateState(this.activeThread.state);
if (aEvent == "detached") {
ThreadState.activeThread = false;
}
},
/**
* Disconnect from the client.
*/
disconnect: function TS_disconnect() {
this.activeThread.removeListener("paused", ThreadState.update);
this.activeThread.removeListener("resumed", ThreadState.update);
this.activeThread.removeListener("detached", ThreadState.update);
}
};
ThreadState.update = ThreadState.update.bind(ThreadState);
/**
* Keeps the stack frame list up-to-date, using the thread client's
* stack frame cache.
*/
var StackFrames = {
pageSize: 25,
activeThread: null,
selectedFrame: null,
/**
* Watch a given thread client.
* @param object aThreadClient
* The thread client.
* @param function aCallback
* The next function in the initialization sequence.
*/
connect: function SF_connect(aThreadClient, aCallback) {
DebuggerView.Stackframes.addClickListener(this.onClick);
this.activeThread = aThreadClient;
aThreadClient.addListener("paused", this.onPaused);
aThreadClient.addListener("framesadded", this.onFrames);
aThreadClient.addListener("framescleared", this.onFramesCleared);
this.onFramesCleared();
aCallback && aCallback();
},
/**
* Disconnect from the client.
*/
disconnect: function TS_disconnect() {
this.activeThread.removeListener("paused", this.onPaused);
this.activeThread.removeListener("framesadded", this.onFrames);
this.activeThread.removeListener("framescleared", this.onFramesCleared);
},
/**
* Handler for the thread client's paused notification.
*/
onPaused: function SF_onPaused() {
this.activeThread.fillFrames(this.pageSize);
},
/**
* Handler for the thread client's framesadded notification.
*/
onFrames: function SF_onFrames() {
DebuggerView.Stackframes.empty();
for each (let frame in this.activeThread.cachedFrames) {
this._addFramePanel(frame);
}
if (this.activeThread.moreFrames) {
DebuggerView.Stackframes.dirty = true;
}
if (!this.selectedFrame) {
this.selectFrame(0);
}
},
/**
* Handler for the thread client's framescleared notification.
*/
onFramesCleared: function SF_onFramesCleared() {
DebuggerView.Stackframes.emptyText();
this.selectedFrame = null;
// Clear the properties as well.
DebuggerView.Properties.localScope.empty();
DebuggerView.Properties.globalScope.empty();
},
/**
* Event handler for clicks on stack frames.
*/
onClick: function SF_onClick(aEvent) {
let target = aEvent.target;
while (target) {
if (target.stackFrame) {
this.selectFrame(target.stackFrame.depth);
return;
}
target = target.parentNode;
}
},
/**
* Marks the stack frame in the specified depth as selected and updates the
* properties view with the stack frame's data.
*
* @param number aDepth
* The depth of the frame in the stack.
*/
selectFrame: function SF_selectFrame(aDepth) {
if (this.selectedFrame !== null) {
DebuggerView.Stackframes.highlightFrame(this.selectedFrame, false);
}
this.selectedFrame = aDepth;
if (aDepth !== null) {
DebuggerView.Stackframes.highlightFrame(this.selectedFrame, true);
}
// Display the local variables.
let frame = this.activeThread.cachedFrames[aDepth];
if (!frame) {
return;
}
let localScope = DebuggerView.Properties.localScope;
localScope.empty();
// Add "this".
if (frame["this"]) {
let thisVar = localScope.addVar("this");
thisVar.setGrip({ "type": frame["this"].type,
"class": frame["this"].class });
this._addExpander(thisVar, frame["this"]);
}
if (frame.arguments && frame.arguments.length > 0) {
// Add "arguments".
let argsVar = localScope.addVar("arguments");
argsVar.setGrip({ "type": "object", "class": "Arguments" });
this._addExpander(argsVar, frame.arguments);
// Add variables for every argument.
let objClient = this.activeThread.pauseGrip(frame.callee);
objClient.getSignature(function SF_getSignature(aResponse) {
for (let i = 0; i < aResponse.parameters.length; i++) {
let param = aResponse.parameters[i];
let paramVar = localScope.addVar(param);
let paramVal = frame.arguments[i];
paramVar.setGrip(paramVal);
this._addExpander(paramVar, paramVal);
}
}.bind(this));
}
},
_addExpander: function SF_addExpander(aVar, aObject) {
// No need for expansion for null and undefined values, but we do need them
// for frame.arguments which is a regular array.
if (!aObject || typeof aObject != "object" ||
(aObject.type != "object" && !Array.isArray(aObject))) {
return;
}
// Add a dummy property to force the twisty to show up.
aVar.addProperties({ " ": { value: " " }});
aVar.onexpand = this._addVarProperties.bind(this, aVar, aObject);
},
_addVarProperties: function SF_addVarProperties(aVar, aObject) {
// Retrieve the properties only once.
if (aVar.fetched) {
return;
}
// Clear the placeholder property put in place to display the twisty.
aVar.empty();
// For arrays we have to construct a grip-like object to pass into
// addProperties.
if (Array.isArray(aObject)) {
let properties = { length: { writable: true, value: aObject.length } };
for (let i = 0; i < aObject.length; i++) {
properties[i + ""] = { value: aObject[i] };
}
aVar.addProperties(properties);
// Expansion handlers must be set after the properties are added.
for (let i = 0; i < aObject.length; i++) {
this._addExpander(aVar[i + ""], aObject[i]);
}
aVar.fetched = true;
return;
}
let objClient = this.activeThread.pauseGrip(aObject);
objClient.getPrototypeAndProperties(function SF_onProtoAndProps(aResponse) {
// Add __proto__.
if (aResponse.prototype.type != "null") {
let properties = {};
properties["__proto__ "] = { value: aResponse.prototype };
aVar.addProperties(properties);
// Expansion handlers must be set after the properties are added.
this._addExpander(aVar["__proto__ "], aResponse.prototype);
}
// Sort the rest of the properties before adding them, for better UX.
let properties = {};
for each (let prop in Object.keys(aResponse.ownProperties).sort()) {
properties[prop] = aResponse.ownProperties[prop];
}
aVar.addProperties(properties);
// Expansion handlers must be set after the properties are added.
for (let prop in aResponse.ownProperties) {
this._addExpander(aVar[prop], aResponse.ownProperties[prop].value);
}
aVar.fetched = true;
}.bind(this));
},
/**
* Adds the specified stack frame to the list.
*
* @param Debugger.Frame aFrame
* The new frame to add.
*/
_addFramePanel: function SF_addFramePanel(aFrame) {
let depth = aFrame.depth;
let idText = "#" + aFrame.depth + " ";
let nameText = this._frameTitle(aFrame);
let panel = DebuggerView.Stackframes.addFrame(depth, idText, nameText);
if (panel) {
panel.stackFrame = aFrame;
}
},
/**
* Loads more stack frames from the debugger server cache.
*/
_addMoreFrames: function SF_addMoreFrames() {
this.activeThread.fillFrames(
this.activeThread.cachedFrames.length + this.pageSize);
},
/**
* Create a textual representation for the stack frame specified, for
* displaying in the stack frame list.
*
* @param Debugger.Frame aFrame
* The stack frame to label.
*/
_frameTitle: function SF_frameTitle(aFrame) {
if (aFrame.type == "call") {
return aFrame["calleeName"] ? aFrame["calleeName"] + "()" : "(anonymous)";
}
return "(" + aFrame.type + ")";
}
};
StackFrames.onPaused = StackFrames.onPaused.bind(StackFrames);
StackFrames.onFrames = StackFrames.onFrames.bind(StackFrames);
StackFrames.onFramesCleared = StackFrames.onFramesCleared.bind(StackFrames);
StackFrames.onClick = StackFrames.onClick.bind(StackFrames);
/**
* Keeps the source script list up-to-date, using the thread client's
* source script cache.
*/
var SourceScripts = {
pageSize: 25,
activeThread: null,
/**
* Watch a given thread client.
* @param object aThreadClient
* The thread client.
* @param function aCallback
* The next function in the initialization sequence.
*/
connect: function SS_connect(aThreadClient, aCallback) {
DebuggerView.Scripts.addChangeListener(this.onChange);
this.activeThread = aThreadClient;
aThreadClient.addListener("paused", this.onPaused);
aThreadClient.addListener("scriptsadded", this.onScripts);
aThreadClient.addListener("scriptscleared", this.onScriptsCleared);
this.onScriptsCleared();
aCallback && aCallback();
},
/**
* Disconnect from the client.
*/
disconnect: function TS_disconnect() {
this.activeThread.removeListener("paused", this.onPaused);
this.activeThread.removeListener("scriptsadded", this.onScripts);
this.activeThread.removeListener("scriptscleared", this.onScriptsCleared);
},
/**
* Handler for the thread client's paused notification.
*/
onPaused: function SS_onPaused() {
this.activeThread.fillScripts();
},
/**
* Handler for the debugger client's unsolicited newScript notification.
*/
onNewScript: function SS_onNewScript(aNotification, aPacket) {
this._addScript({ url: aPacket.url, startLine: aPacket.startLine });
},
/**
* Handler for the thread client's scriptsadded notification.
*/
onScripts: function SS_onScripts() {
this.onScriptsCleared();
for each (let script in this.activeThread.cachedScripts) {
this._addScript(script);
}
},
/**
* Handler for the thread client's scriptscleared notification.
*/
onScriptsCleared: function SS_onScriptsCleared() {
DebuggerView.Scripts.empty();
},
/**
* Handler for changes on the selected source script.
*/
onChange: function SS_onClick(aEvent) {
let scripts = aEvent.target;
let script = scripts.selectedItem.getUserData("sourceScript");
this._showScript(script);
},
/**
* Add the specified script to the list and display it in the editor if the
* editor is empty.
*/
_addScript: function SS_addScript(aScript) {
DebuggerView.Scripts.addScript(aScript.url, aScript);
if (window.editor.getCharCount() == 0) {
this._showScript(aScript);
}
},
/**
* Load the editor with the script text if available, otherwise fire an event
* to load and display the script text.
*/
_showScript: function SS_showScript(aScript) {
if (!aScript.loaded) {
// Notify the chrome code that we need to load a script file.
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent("Debugger:LoadSource", true, false, aScript.url);
document.documentElement.dispatchEvent(evt);
window.editor.setText(DebuggerView.getStr("loadingText"));
} else {
window.editor.setText(aScript.text);
}
}
};
SourceScripts.onPaused = SourceScripts.onPaused.bind(SourceScripts);
SourceScripts.onScripts = SourceScripts.onScripts.bind(SourceScripts);
SourceScripts.onNewScript = SourceScripts.onNewScript.bind(SourceScripts);
SourceScripts.onScriptsCleared = SourceScripts.onScriptsCleared.bind(SourceScripts);
SourceScripts.onChange = SourceScripts.onChange.bind(SourceScripts);
window.addEventListener("DOMContentLoaded", initDebugger, false);
window.addEventListener("unload", shutdownDebugger, false);

Просмотреть файл

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is mozilla.org code.
-
- The Initial Developer of the Original Code is
- Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Dave Camp <dcamp@mozilla.com>
- Panos Astithas <past@mozilla.com>
- Victor Porof <vporof@mozilla.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/orion.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/debugger.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/debugger.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd" >
%debuggerDTD;
]>
<xul:window xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<xul:script type="text/javascript" src="debugger.js"/>
<xul:script type="text/javascript" src="debugger-view.js"/>
<div id="body" class="vbox flex">
<xul:toolbar id="dbg-toolbar">
<xul:button id="close">&debuggerUI.closeButton;</xul:button>
<xul:button id="resume">&debuggerUI.resumeButton;</xul:button>
<xul:menulist id="scripts"/>
</xul:toolbar>
<div id="dbg-content" class="hbox flex">
<div id="stack" class="vbox">
<div class="title unselectable">&debuggerUI.stackTitle;</div>
<div id="stackframes" class="vbox flex"></div>
</div>
<div id="script" class="vbox flex">
<div class="title unselectable">&debuggerUI.scriptTitle;</div>
<div id="editor" class="vbox flex"></div>
</div>
<div id="properties" class="vbox">
<div class="title unselectable">&debuggerUI.propertiesTitle;</div>
<div id="variables" class="vbox flex"></div>
</div>
</div>
<div id="dbg-statusbar">
<span id="status"></span>
</div>
</div>
</xul:window>

Просмотреть файл

@ -0,0 +1,90 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Dave Camp <dcamp@mozilla.com>
# Victor Porof <vporof@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/devtools/debugger/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_dbg_debuggerstatement.js \
browser_dbg_listtabs.js \
browser_dbg_tabactor-01.js \
browser_dbg_tabactor-02.js \
browser_dbg_contextactor-01.js \
browser_dbg_contextactor-02.js \
testactors.js \
browser_dbg_nav-01.js \
browser_dbg_propertyview-01.js \
browser_dbg_propertyview-02.js \
browser_dbg_propertyview-03.js \
browser_dbg_propertyview-04.js \
browser_dbg_propertyview-05.js \
browser_dbg_propertyview-06.js \
browser_dbg_propertyview-07.js \
browser_dbg_propertyview-08.js \
browser_dbg_panesize.js \
browser_dbg_stack-01.js \
browser_dbg_stack-02.js \
browser_dbg_stack-03.js \
browser_dbg_stack-04.js \
browser_dbg_location-changes.js \
browser_dbg_script-switching.js \
head.js \
$(NULL)
_BROWSER_TEST_PAGES = \
browser_dbg_tab1.html \
browser_dbg_tab2.html \
browser_dbg_debuggerstatement.html \
browser_dbg_stack.html \
browser_dbg_script-switching.html \
test-script-switching-01.js \
test-script-switching-02.js \
browser_dbg_frame-parameters.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
libs:: $(_BROWSER_TEST_PAGES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check extension-added context actor lifetimes.
*/
var gTab1 = null;
var gTab1Actor = null;
var gClient = null;
function test()
{
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
get_tab();
});
}
function get_tab()
{
gTab1 = addTab(TAB1_URL, function() {
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: aGrip.actor, type: "testContextActor1" }, function(aResponse) {
ok(aResponse.actor, "testContextActor1 request should return an actor.");
ok(aResponse.actor.indexOf("testone") >= 0,
"testContextActor's actorPrefix should be used.");
gClient.request({ to: aResponse.actor, type: "ping" }, function(aResponse) {
is(aResponse.pong, "pong", "Actor should response to requests.");
finish_test();
});
});
});
});
}
function finish_test()
{
gClient.close(function() {
removeTab(gTab1);
finish();
});
};

Просмотреть файл

@ -0,0 +1,59 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check extension-added context actor lifetimes.
*/
var gTab1 = null;
var gTab1Actor = null;
var gClient = null;
function test()
{
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
get_tab();
});
}
function get_tab()
{
gTab1 = addTab(TAB1_URL, function() {
get_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: gTab1Actor, type: "attach" }, function(aResponse) {
gClient.request({ to: gTab1Actor, type: "testContextActor1" }, function(aResponse) {
navigate_tab(aResponse.actor);
});
});
});
});
}
function navigate_tab(aTestActor)
{
gClient.addOneTimeListener("tabNavigated", function(aEvent, aResponse) {
gClient.request({ to: aTestActor, type: "ping" }, function(aResponse) {
// TODO: Currently the client is supposed to clean up after tabNavigated
// events. We should remove this check, or even better, remove the whole
// test.
todo(aResponse.error, "noSuchActor", "testContextActor1 should have gone away with the navigation.");
finish_test();
});
});
gTab1.linkedBrowser.loadURI(TAB2_URL);
}
function finish_test()
{
gClient.close(function() {
removeTab(gTab1);
finish();
});
}

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<head><title>Browser Debugger Test Tab</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
function runDebuggerStatement()
{
debugger;
}
</script>
</head>
<body></body>
</html>

Просмотреть файл

@ -0,0 +1,72 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests the behavior of the debugger statement.
var gClient = null;
var gTab = null;
const DEBUGGER_TAB_URL = "http://example.com/browser/browser/devtools/" +
"debugger/test/" +
"browser_dbg_debuggerstatement.html";
function test()
{
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
gTab = addTab(DEBUGGER_TAB_URL, function() {
attach_tab_actor_for_url(gClient, DEBUGGER_TAB_URL, function(actor, response) {
test_early_debugger_statement(response);
});
});
});
}
function test_early_debugger_statement(aActor)
{
let paused = function(aEvent, aPacket) {
ok(false, "Pause shouldn't be called before we've attached!\n");
finish_test();
};
gClient.addListener("paused", paused);
// This should continue without nesting an event loop and calling
// the onPaused hook, because we haven't attached yet.
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
gClient.removeListener("paused", paused);
// Now attach and resume...
gClient.request({ to: aActor.threadActor, type: "attach" }, function(aResponse) {
gClient.request({ to: aActor.threadActor, type: "resume" }, function(aResponse) {
test_debugger_statement(aActor);
});
});
}
function test_debugger_statement(aActor)
{
var stopped = false;
gClient.addListener("paused", function(aEvent, aPacket) {
stopped = true;
gClient.request({ to: aActor.threadActor, type: "resume" }, function() {
finish_test();
});
});
// Reach around the debugging protocol and execute the debugger
// statement.
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
ok(stopped, "Should trigger the pause handler on a debugger statement.");
}
function finish_test()
{
removeTab(gTab);
gClient.close(function() {
finish();
});
}

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Debugger Function Call Parameter Test</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
window.addEventListener("load", function() {
function test(aArg, bArg, cArg, dArg, eArg, fArg) {
var a = 1;
var b = { a: a };
var c = { a: 1, b: "beta", c: true, d: b };
debugger;
}
function load() {
var a = { a: 1, b: "beta", c: true };
var e = eval("test(a, 'beta', 3, false, null)");
}
var button = document.querySelector("button");
button.addEventListener("click", load, false);
});
</script>
</head>
<body>
<button>Click me!</button>
</body>
</html>

Просмотреть файл

@ -0,0 +1,100 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gTab1 = null;
var gTab1Actor = null;
var gTab2 = null;
var gTab2Actor = null;
var gClient = null;
function test()
{
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
test_first_tab();
});
}
/**
* Verify that a new tab shows up in a listTabs call.
*/
function test_first_tab()
{
gTab1 = addTab(TAB1_URL, function() {
gClient.listTabs(function(aResponse) {
for each (let tab in aResponse.tabs) {
if (tab.url == TAB1_URL) {
gTab1Actor = tab.actor;
}
}
ok(gTab1Actor, "Should find a tab actor for tab1.");
test_second_tab();
});
});
}
function test_second_tab()
{
gTab2 = addTab(TAB2_URL, function() {
gClient.listTabs(function(aResponse) {
// Verify that tab1 has the same actor it used to.
let foundTab1 = false;
for each (let tab in aResponse.tabs) {
if (tab.url == TAB1_URL) {
is(tab.actor, gTab1Actor, "Tab1's actor shouldn't have changed.");
foundTab1 = true;
}
if (tab.url == TAB2_URL) {
gTab2Actor = tab.actor;
}
}
ok(foundTab1, "Should have found an actor for tab 1.");
ok(gTab2Actor != null, "Should find an actor for tab2.");
test_remove_tab();
});
});
}
function test_remove_tab()
{
removeTab(gTab1);
gTab1 = null;
gClient.listTabs(function(aResponse) {
// Verify that tab1 is no longer included in listTabs.
let foundTab1 = false;
for each (let tab in aResponse.tabs) {
if (tab.url == TAB1_URL) {
ok(false, "Tab1 should be gone.");
}
}
ok(!foundTab1, "Tab1 should be gone.");
test_attach_removed_tab();
});
}
function test_attach_removed_tab()
{
removeTab(gTab2);
gTab2 = null;
gClient.addListener("paused", function(aEvent, aPacket) {
ok(false, "Attaching to an exited tab actor shouldn't generate a pause.");
finish_test();
});
gClient.request({ to: gTab2Actor, type: "attach" }, function(aResponse) {
is(aResponse.type, "exited", "Tab should consider itself exited.");
finish_test();
});
}
function finish_test()
{
gClient.close(function() {
finish();
});
}

Просмотреть файл

@ -0,0 +1,64 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that changing the tab location URL works.
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test()
{
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({
run: function() {
var frames = gDebugger.DebuggerView.Stackframes._frames,
childNodes = frames.childNodes;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
"Should have only one frame.");
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
"All children should be frames.");
testLocationChange();
}
}, 0);
});
gDebuggee.simpleCall();
}
function testLocationChange()
{
gDebugger.StackFrames.activeThread.resume(function() {
gPane._client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
ok(true, "tabNavigated event was fired.");
gPane._client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
ok(true, "Successfully reattached to the tab again.");
removeTab(gTab);
finish();
});
});
content.location = TAB1_URL;
});
}

Просмотреть файл

@ -0,0 +1,48 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check tab attach/navigation.
*/
var gTab1 = null;
var gTab1Actor = null;
var gClient = null;
function test()
{
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
get_tab();
});
}
function get_tab()
{
gTab1 = addTab(TAB1_URL, function() {
get_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: aGrip.actor, type: "attach" }, function(aResponse) {
gClient.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
is(aPacket.url, TAB2_URL, "Got a tab navigation notification.");
gClient.addOneTimeListener("tabDetached", function (aEvent, aPacket) {
ok(true, "Got a tab detach notification.");
finish_test();
});
removeTab(gTab1);
});
gTab1.linkedBrowser.loadURI(TAB2_URL);
});
});
});
}
function finish_test()
{
gClient.close(function() {
finish();
});
}

Просмотреть файл

@ -0,0 +1,40 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
var tab1 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = tab1;
ok(!DebuggerUI.getDebugger(gBrowser.selectedTab),
"Shouldn't have a debugger pane for this tab yet.");
let pane = DebuggerUI.toggleDebugger();
let someHeight = parseInt(Math.random() * 200) + 200;
ok(pane, "toggleDebugger() should return a pane.");
is(DebuggerUI.getDebugger(gBrowser.selectedTab), pane,
"getDebugger() should return the same pane as toggleDebugger().");
ok(DebuggerUI.preferences.height,
"The debugger preferences should have a saved height value.");
is(DebuggerUI.preferences.height, pane.frame.height,
"The debugger pane height should be the same as the preferred value.");
pane.frame.height = someHeight;
ok(DebuggerUI.preferences.height !== someHeight,
"Height preferences shouldn't have been updated yet.");
pane.onConnected = function() {
removeTab(tab1);
finish();
is(DebuggerUI.preferences.height, someHeight,
"Height preferences should have been updated by now.");
};
});
}

Просмотреть файл

@ -0,0 +1,89 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let globalScope = gDebugger.DebuggerView.Properties._globalScope;
let localScope = gDebugger.DebuggerView.Properties._localScope;
let withScope = gDebugger.DebuggerView.Properties._withScope;
let closureScope = gDebugger.DebuggerView.Properties._closureScope;
ok(globalScope,
"Should have a globalScope container for the variables property view.");
ok(localScope,
"Should have a localScope container for the variables property view.");
ok(withScope,
"Should have a withScope container for the variables property view.");
ok(closureScope,
"Should have a closureScope container for the variables property view.");
is(globalScope, gDebugger.DebuggerView.Properties.globalScope,
"The globalScope object should be equal to the corresponding getter.");
is(localScope, gDebugger.DebuggerView.Properties.localScope,
"The localScope object should be equal to the corresponding getter.");
is(withScope, gDebugger.DebuggerView.Properties.withScope,
"The withScope object should be equal to the corresponding getter.");
is(closureScope, gDebugger.DebuggerView.Properties.closureScope,
"The closureScope object should be equal to the corresponding getter.");
ok(!globalScope.expanded,
"The globalScope should be initially collapsed.");
ok(localScope.expanded,
"The localScope should be initially expanded.");
ok(!withScope.expanded,
"The withScope should be initially collapsed.");
ok(!withScope.visible,
"The withScope should be initially hidden.");
ok(!closureScope.expanded,
"The closureScope should be initially collapsed.");
ok(!closureScope.visible,
"The closureScope should be initially hidden.");
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
"Should have only 4 scopes created: global, local, with and scope.");
resumeAndFinish();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,131 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
ok(testScope,
"Should have created a scope.");
is(testScope.id, "test-scope",
"The newly created scope should have the default id set.");
is(testScope.querySelector(".name").textContent, "test",
"Any new scope should have the designated title.");
is(testScope.querySelector(".details").childNodes.length, 0,
"Any new scope should have a container with no child nodes.");
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 5,
"Should have 5 scopes created: global, local, with, closure and test.");
ok(!testScope.expanded,
"Any new created scope should be initially collapsed.");
ok(testScope.visible,
"Any new created scope should be initially visible.");
let expandCallbackSender = null;
let collapseCallbackSender = null;
let toggleCallbackSender = null;
let hideCallbackSender = null;
let showCallbackSender = null;
testScope.onexpand = function(sender) { expandCallbackSender = sender; };
testScope.oncollapse = function(sender) { collapseCallbackSender = sender; };
testScope.ontoggle = function(sender) { toggleCallbackSender = sender; };
testScope.onhide = function(sender) { hideCallbackSender = sender; };
testScope.onshow = function(sender) { showCallbackSender = sender; };
testScope.expand();
ok(testScope.expanded,
"The testScope shouldn't be collapsed anymore.");
is(expandCallbackSender, testScope,
"The expandCallback wasn't called as it should.");
testScope.collapse();
ok(!testScope.expanded,
"The testScope should be collapsed again.");
is(collapseCallbackSender, testScope,
"The collapseCallback wasn't called as it should.");
testScope.expanded = true;
ok(testScope.expanded,
"The testScope shouldn't be collapsed anymore.");
testScope.toggle();
ok(!testScope.expanded,
"The testScope should be collapsed again.");
is(toggleCallbackSender, testScope,
"The toggleCallback wasn't called as it should.");
testScope.hide();
ok(!testScope.visible,
"The testScope should be invisible after hiding.");
is(hideCallbackSender, testScope,
"The hideCallback wasn't called as it should.");
testScope.show();
ok(testScope.visible,
"The testScope should be visible again.");
is(showCallbackSender, testScope,
"The showCallback wasn't called as it should.");
testScope.visible = false;
ok(!testScope.visible,
"The testScope should be invisible after hiding.");
ok(!testScope.expanded,
"The testScope should remember it is collapsed even if it is hidden.");
EventUtils.sendMouseEvent({ type: "click" },
testScope.querySelector(".title"),
gDebugger);
ok(testScope.expanded,
"Clicking the testScope tilte should expand it.");
EventUtils.sendMouseEvent({ type: "click" },
testScope.querySelector(".title"),
gDebugger);
ok(!testScope.expanded,
"Clicking again the testScope tilte should collapse it.");
resumeAndFinish();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,133 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
let testVar = testScope.addVar("something");
let duplVar = testScope.addVar("something");
ok(testVar,
"Should have created a variable.");
is(duplVar, null,
"Shouldn't be able to duplicate variables in the same scope.");
is(testVar.id, "test-scope->something-variable",
"The newly created scope should have the default id set.");
is(testVar.querySelector(".name").textContent, "something",
"Any new variable should have the designated title.");
is(testVar.querySelector(".details").childNodes.length, 0,
"Any new variable should have a details container with no child nodes.");
ok(!testVar.expanded,
"Any new created variable should be initially collapsed.");
ok(testVar.visible,
"Any new created variable should be initially visible.");
testVar.expand();
ok(testVar.expanded,
"The testVar shouldn't be collapsed anymore.");
testVar.collapse();
ok(!testVar.expanded,
"The testVar should be collapsed again.");
testVar.expanded = true;
ok(testVar.expanded,
"The testVar shouldn't be collapsed anymore.");
testVar.toggle();
ok(!testVar.expanded,
"The testVar should be collapsed again.");
testVar.hide();
ok(!testVar.visible,
"The testVar should be invisible after hiding.");
testVar.show();
ok(testVar.visible,
"The testVar should be visible again.");
testVar.visible = false;
ok(!testVar.visible,
"The testVar should be invisible after hiding.");
ok(!testVar.expanded,
"The testVar should remember it is collapsed even if it is hidden.");
EventUtils.sendMouseEvent({ type: "click" },
testVar.querySelector(".title"),
gDebugger);
ok(testVar.expanded,
"Clicking the testScope tilte should expand it.");
EventUtils.sendMouseEvent({ type: "click" },
testVar.querySelector(".title"),
gDebugger);
ok(!testVar.expanded,
"Clicking again the testScope tilte should collapse it.");
let emptyCallbackSender = null;
let removeCallbackSender = null;
testScope.onempty = function(sender) { emptyCallbackSender = sender; };
testScope.onremove = function(sender) { removeCallbackSender = sender; };
testScope.empty();
is(emptyCallbackSender, testScope,
"The emptyCallback wasn't called as it should.");
is(testScope.querySelector(".details").childNodes.length, 0,
"The scope should remove all it's details container tree children.");
testScope.remove();
is(removeCallbackSender, testScope,
"The removeCallback wasn't called as it should.");
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
"The scope should have been removed from the parent container tree.");
resumeAndFinish();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,88 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
let testVar = testScope.addVar("something");
let properties = testVar.addProperties({ "child": { "value": { "type": "object",
"class": "Object" } } });
is(testVar.querySelector(".details").childNodes.length, 1,
"A new detail node should have been added in the variable tree.");
ok(testVar.child,
"The added detail property should be accessible from the variable.");
is(testVar.child, properties.child,
"Adding a detail property should return that exact property.");
let properties2 = testVar.child.addProperties({ "grandchild": { "value": { "type": "object",
"class": "Object" } } });
is(testVar.child.querySelector(".details").childNodes.length, 1,
"A new detail node should have been added in the variable tree.");
ok(testVar.child.grandchild,
"The added detail property should be accessible from the variable.");
is(testVar.child.grandchild, properties2.grandchild,
"Adding a detail property should return that exact property.");
testVar.child.empty();
is(testVar.child.querySelector(".details").childNodes.length, 0,
"The child should remove all it's details container tree children.");
testVar.child.remove();
is(testVar.querySelector(".details").childNodes.length, 0,
"The child should have been removed from the parent container tree.");
testVar.empty();
is(testVar.querySelector(".details").childNodes.length, 0,
"The var should remove all it's details container tree children.");
testVar.remove();
is(testScope.querySelector(".details").childNodes.length, 0,
"The var should have been removed from the parent container tree.");
resumeAndFinish();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,96 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
let testVar = testScope.addVar("something");
testVar.setGrip(1.618);
is(testVar.querySelector(".info").textContent, "1.618",
"The grip information for the variable wasn't set correctly.");
is(testVar.querySelector(".details").childNodes.length, 0,
"Adding a value property shouldn't add any new tree nodes.");
testVar.setGrip({ "type": "object", "class": "Window" });
is(testVar.querySelector(".details").childNodes.length, 0,
"Adding type and class properties shouldn't add any new tree nodes.");
is(testVar.querySelector(".info").textContent, "[object Window]",
"The information for the variable wasn't set correctly.");
testVar.addProperties({ "helloWorld": { "value": "hello world" } });
is(testVar.querySelector(".details").childNodes.length, 1,
"A new detail node should have been added in the variable tree.");
testVar.addProperties({ "helloWorld": { "value": "hello jupiter" } });
is(testVar.querySelector(".details").childNodes.length, 1,
"Shouldn't be able to duplicate nodes added in the variable tree.");
testVar.addProperties({ "someProp0": { "value": "random string" },
"someProp1": { "value": "another string" } });
is(testVar.querySelector(".details").childNodes.length, 3,
"Two new detail nodes should have been added in the variable tree.");
testVar.addProperties({ "someProp2": { "value": { "type": "null" } },
"someProp3": { "value": { "type": "undefined" } },
"someProp4": { "value": { "type": "object", "class": "Object" } } });
is(testVar.querySelector(".details").childNodes.length, 6,
"Three new detail nodes should have been added in the variable tree.");
testVar.empty();
is(testVar.querySelector(".details").childNodes.length, 0,
"The var should remove all it's details container tree children.");
testVar.remove();
is(testScope.querySelector(".details").childNodes.length, 0,
"The var should have been removed from the parent container tree.");
resumeAndFinish();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,133 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let globalScope = gDebugger.DebuggerView.Properties.globalScope;
let localScope = gDebugger.DebuggerView.Properties.localScope;
let windowVar = globalScope.addVar("window");
let documentVar = globalScope.addVar("document");
let localVar0 = localScope.addVar("localVariable");
let localVar1 = localScope.addVar("localVar1");
let localVar2 = localScope.addVar("localVar2");
let localVar3 = localScope.addVar("localVar3");
let localVar4 = localScope.addVar("localVar4");
let localVar5 = localScope.addVar("localVar5");
localVar0.setGrip(42);
localVar1.setGrip(true);
localVar2.setGrip("nasu");
localVar3.setGrip({ "type": "undefined" });
localVar4.setGrip({ "type": "null" });
localVar5.setGrip({ "type": "object", "class": "Object" });
localVar5.addProperties({ "someProp0": { "value": 42 },
"someProp1": { "value": true },
"someProp2": { "value": "nasu" },
"someProp3": { "value": { "type": "undefined" } },
"someProp4": { "value": { "type": "null" } },
"someProp5": { "value": { "type": "object", "class": "Object" } } });
localVar5.someProp5.addProperties({ "someProp0": { "value": 42 },
"someProp1": { "value": true },
"someProp2": { "value": "nasu" },
"someProp3": { "value": { "type": "undefined" } },
"someProp4": { "value": { "type": "null" } },
"someAccessor": { "get": { "type": "object", "class": "Function" },
"set": { "type": "undefined" } } });
windowVar.setGrip({ "type": "object", "class": "Window" });
windowVar.addProperties({ "helloWorld": { "value": "hello world" } });
documentVar.setGrip({ "type": "object", "class": "HTMLDocument" });
documentVar.addProperties({ "onload": { "value": { "type": "null" } },
"onunload": { "value": { "type": "null" } },
"onfocus": { "value": { "type": "null" } },
"onblur": { "value": { "type": "null" } },
"onclick": { "value": { "type": "null" } },
"onkeypress": { "value": { "type": "null" } } });
ok(windowVar, "The windowVar hasn't been created correctly.");
ok(documentVar, "The documentVar hasn't been created correctly.");
ok(localVar0, "The localVar0 hasn't been created correctly.");
ok(localVar1, "The localVar1 hasn't been created correctly.");
ok(localVar2, "The localVar2 hasn't been created correctly.");
ok(localVar3, "The localVar3 hasn't been created correctly.");
ok(localVar4, "The localVar4 hasn't been created correctly.");
ok(localVar5, "The localVar5 hasn't been created correctly.");
is(globalScope.querySelector(".details").childNodes.length, 2,
"The globalScope doesn't contain all the created variable elements.");
is(localScope.querySelector(".details").childNodes.length, 7,
"The localScope doesn't contain all the created variable elements.");
is(localVar5.querySelector(".details").childNodes.length, 6,
"The localVar5 doesn't contain all the created properties.");
is(localVar5.someProp5.querySelector(".details").childNodes.length, 6,
"The localVar5.someProp5 doesn't contain all the created properties.");
is(windowVar.querySelector(".info").textContent, "[object Window]",
"The grip information for the windowVar wasn't set correctly.");
is(documentVar.querySelector(".info").textContent, "[object HTMLDocument]",
"The grip information for the documentVar wasn't set correctly.");
is(localVar0.querySelector(".info").textContent, "42",
"The grip information for the localVar0 wasn't set correctly.");
is(localVar1.querySelector(".info").textContent, "true",
"The grip information for the localVar1 wasn't set correctly.");
is(localVar2.querySelector(".info").textContent, "\"nasu\"",
"The grip information for the localVar2 wasn't set correctly.");
is(localVar3.querySelector(".info").textContent, "undefined",
"The grip information for the localVar3 wasn't set correctly.");
is(localVar4.querySelector(".info").textContent, "null",
"The grip information for the localVar4 wasn't set correctly.");
is(localVar5.querySelector(".info").textContent, "[object Object]",
"The grip information for the localVar5 wasn't set correctly.");
resumeAndFinish();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,97 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the property view displays function parameters.
*/
const TAB_URL = "http://example.com/browser/browser/devtools/debugger/test/" +
"browser_dbg_frame-parameters.html";
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testFrameParameters();
});
}
function testFrameParameters()
{
// scriptsadded is fired last when switching to a paused state, so the
// property view will have had a chance to fetch the call parameters.
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.Stackframes._frames,
childNodes = frames.childNodes,
localScope = gDebugger.DebuggerView.Properties.localScope,
localNodes = localScope.querySelector(".details").childNodes;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
"Should have three frames.");
is(localNodes.length, 8,
"The localScope should contain all the created variable elements.");
is(localNodes[0].querySelector(".info").textContent, "[object Proxy]",
"Should have the right property value for 'this'.");
is(localNodes[1].querySelector(".info").textContent, "[object Arguments]",
"Should have the right property value for 'arguments'.");
is(localNodes[2].querySelector(".info").textContent, "[object Object]",
"Should have the right property value for 'aArg'.");
is(localNodes[3].querySelector(".info").textContent, '"beta"',
"Should have the right property value for 'bArg'.");
is(localNodes[4].querySelector(".info").textContent, "3",
"Should have the right property value for 'cArg'.");
is(localNodes[5].querySelector(".info").textContent, "false",
"Should have the right property value for 'dArg'.");
is(localNodes[6].querySelector(".info").textContent, "null",
"Should have the right property value for 'eArg'.");
is(localNodes[7].querySelector(".info").textContent, "undefined",
"Should have the right property value for 'fArg'.");
resumeAndFinish();
}}, 0);
});
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"),
content.window);
}
function resumeAndFinish() {
gPane.activeThread.addOneTimeListener("framescleared", function() {
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.Stackframes._frames;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
removeTab(gTab);
finish();
}}, 0);
});
gDebugger.StackFrames.activeThread.resume();
}

Просмотреть файл

@ -0,0 +1,111 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the property view displays the properties of objects.
*/
const TAB_URL = "http://example.com/browser/browser/devtools/debugger/test/" +
"browser_dbg_frame-parameters.html";
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testFrameParameters();
});
}
function testFrameParameters()
{
// scriptsadded is fired last when switching to a paused state, so the
// property view will have had a chance to fetch the call parameters.
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.Stackframes._frames,
localScope = gDebugger.DebuggerView.Properties.localScope,
localNodes = localScope.querySelector(".details").childNodes;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
"Should have three frames.");
is(localNodes.length, 8,
"The localScope should contain all the created variable elements.");
is(localNodes[0].querySelector(".info").textContent, "[object Proxy]",
"Should have the right property value for 'this'.");
// Expand the __proto__ and arguments tree nodes. This causes their
// properties to be retrieved and displayed.
localNodes[0].expand();
localNodes[1].expand();
// Poll every few milliseconds until the properties are retrieved.
let count = 0;
let intervalID = content.setInterval(function(){
if (++count > 50) {
ok(false, "Timed out while polling for the properties.");
resumeAndFinish();
}
if (!localNodes[0].fetched || !localNodes[1].fetched) {
return;
}
content.clearInterval(intervalID);
is(localNodes[0].querySelector(".property > .title > .key")
.textContent, "__proto__ ",
"Should have the right property name for __proto__.");
ok(localNodes[0].querySelector(".property > .title > .value")
.textContent.search(/object/) != -1,
"__proto__ should be an object.");
is(localNodes[1].querySelector(".info").textContent, "[object Arguments]",
"Should have the right property value for 'arguments'.");
is(localNodes[1].querySelector(".property > .title > .key")
.textContent, "length",
"Should have the right property name for length.");
is(localNodes[1].querySelector(".property > .title > .value")
.textContent, 5,
"Should have the right argument length.");
resumeAndFinish();
}, 100);
}}, 0);
});
EventUtils.synthesizeMouseAtCenter(content.document.querySelector("button"),
{},
content.window);
}
function resumeAndFinish() {
gPane.activeThread.addOneTimeListener("framescleared", function() {
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.Stackframes._frames;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
removeTab(gTab);
finish();
}}, 0);
});
gDebugger.StackFrames.activeThread.resume();
}

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Browser Debugger Script Switching Test</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript" src="test-script-switching-01.js"></script>
<script type="text/javascript" src="test-script-switching-02.js"></script>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,101 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that switching the displayed script in the UI works as advertised.
*/
const TAB_URL = "http://example.com/browser/browser/devtools/debugger/" +
"test/browser_dbg_script-switching.html";
let tempScope = {};
Cu.import("resource:///modules/source-editor.jsm", tempScope);
let SourceEditor = tempScope.SourceEditor;
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
var gScripts = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testScriptsDisplay();
});
}
function testScriptsDisplay() {
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let count = 0;
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
function onScriptLoad() {
// Skip the first change event, since we're only interested in the
// second.
if (count++ < 1) {
return;
}
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onScriptLoad);
gScripts = gDebugger.DebuggerView.Scripts._scripts;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(gScripts.itemCount, 2, "Found the expected number of scripts.");
ok(gDebugger.editor.getText().search(/debugger/) != -1,
"The correct script was loaded initially.");
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
function onChange() {
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onChange);
testSwitchPaused();
});
gScripts.selectedIndex = 0;
gDebugger.SourceScripts.onChange({ target: gScripts });
});
}}, 0);
});
gDebuggee.firstCall();
}
function testSwitchPaused()
{
ok(gDebugger.editor.getText().search(/debugger/) == -1,
"The second script is no longer displayed.");
ok(gDebugger.editor.getText().search(/firstCall/) != -1,
"The first script is displayed.");
gDebugger.StackFrames.activeThread.resume(function() {
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
function onSecondChange() {
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onSecondChange);
testSwitchRunning();
});
gScripts.selectedIndex = 1;
gDebugger.SourceScripts.onChange({ target: gScripts });
});
}
function testSwitchRunning()
{
ok(gDebugger.editor.getText().search(/debugger/) != -1,
"The second script is displayed again.");
ok(gDebugger.editor.getText().search(/firstCall/) == -1,
"The first script is no longer displayed.");
removeTab(gTab);
finish();
}

Просмотреть файл

@ -0,0 +1,51 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.Stackframes._frames;
let childNodes = frames.childNodes;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
"Should have only one frame.");
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
"All children should be frames.");
resumeAndFinish();
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,83 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testEvalCall();
});
}
function testEvalCall() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.Stackframes._frames;
let childNodes = frames.childNodes;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 2,
"Should have two frames.");
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
"All children should be frames.");
is(frames.querySelector("#stackframe-0 .dbg-stackframe-name").textContent,
"(eval)", "Frame name should be (eval)");
ok(frames.querySelector("#stackframe-0").classList.contains("selected"),
"First frame should be selected by default.");
ok(!frames.querySelector("#stackframe-1").classList.contains("selected"),
"Second frame should not be selected.");
EventUtils.sendMouseEvent({ type: "click" },
frames.querySelector("#stackframe-1"),
gDebugger);
ok(!frames.querySelector("#stackframe-0").classList.contains("selected"),
"First frame should not be selected after click.");
ok(frames.querySelector("#stackframe-1").classList.contains("selected"),
"Second frame should be selected after click.");
EventUtils.sendMouseEvent({ type: "click" },
frames.querySelector("#stackframe-0 .dbg-stackframe-name"),
gDebugger);
ok(frames.querySelector("#stackframe-0").classList.contains("selected"),
"First frame should be selected after click inside the first frame.");
ok(!frames.querySelector("#stackframe-1").classList.contains("selected"),
"Second frame should not be selected after click inside the first frame.");
resumeAndFinish();
}}, 0);
});
gDebuggee.evalCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,68 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testRecurse();
});
}
function testRecurse() {
gDebuggee.gRecurseLimit = (gDebugger.StackFrames.pageSize * 2) + 1;
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.Stackframes._frames;
let pageSize = gDebugger.StackFrames.pageSize;
let recurseLimit = gDebuggee.gRecurseLimit;
let childNodes = frames.childNodes;
is(frames.querySelectorAll(".dbg-stackframe").length, pageSize,
"Should have the max limit of frames.");
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
"All children should be frames.");
gPane.activeThread.addOneTimeListener("framesadded", function() {
is(frames.querySelectorAll(".dbg-stackframe").length, pageSize * 2,
"Should now have twice the max limit of frames.");
gPane.activeThread.addOneTimeListener("framesadded", function() {
is(frames.querySelectorAll(".dbg-stackframe").length, recurseLimit,
"Should have reached the recurse limit.");
resumeAndFinish();
});
frames.scrollTop = frames.scrollHeight;
});
frames.scrollTop = frames.scrollHeight;
}}, 0);
});
gDebuggee.recurse();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
}

Просмотреть файл

@ -0,0 +1,60 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testEvalCallResume();
});
}
function testEvalCallResume() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.Stackframes._frames;
let childNodes = frames.childNodes;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 2,
"Should have two frames.");
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
"All children should be frames.");
gPane.activeThread.addOneTimeListener("framescleared", function() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames after resume");
is(childNodes.length, 1,
"Should only have one child.");
is(frames.querySelectorAll(".empty").length, 1,
"Should have the empty list explanation.");
removeTab(gTab);
finish();
});
gPane.activeThread.resume();
}}, 0);
});
gDebuggee.evalCall();
}

Просмотреть файл

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<head><title>Browser Debugger Test Tab</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
function simpleCall() {
debugger;
}
function evalCall() {
eval("debugger;");
}
var gRecurseLimit = 100;
var gRecurseDepth = 0;
function recurse() {
if (++gRecurseDepth == gRecurseLimit) {
debugger;
gRecurseDepth = 0;
return;
}
recurse();
}
</script>
</head>
<body></body>
</html>

Просмотреть файл

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Browser Debugger Test Tab</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Browser Debugger Test Tab 2</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check extension-added tab actor lifetimes.
*/
var gTab1 = null;
var gTab1Actor = null;
var gClient = null;
function test()
{
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function (aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
get_tab();
});
}
function get_tab()
{
gTab1 = addTab(TAB1_URL, function () {
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
ok(aResponse.actor, "testTabActor1 request should return an actor.");
ok(aResponse.actor.indexOf("testone") >= 0,
"testTabActor's actorPrefix should be used.");
gClient.request({ to: aResponse.actor, type: "ping" }, function (aResponse) {
is(aResponse.pong, "pong", "Actor should response to requests.");
finish_test();
});
});
});
});
}
function finish_test()
{
gClient.close(function() {
removeTab(gTab1);
finish();
});
}

Просмотреть файл

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check extension-added tab actor lifetimes.
*/
var gTab1 = null;
var gTab1Actor = null;
var gClient = null;
function test()
{
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function (aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
get_tab();
});
}
function get_tab()
{
gTab1 = addTab(TAB1_URL, function () {
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
close_tab(aResponse.actor);
});
});
});
}
function close_tab(aTestActor)
{
removeTab(gTab1);
gClient.request({ to: aTestActor, type: "ping" }, function (aResponse) {
is(aResponse.error, "noSuchActor", "testTabActor1 should have gone away with the tab.");
finish_test();
});
}
function finish_test()
{
gClient.close(function () {
finish();
});
}

Просмотреть файл

@ -0,0 +1,99 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
let tempScope = {};
Cu.import("resource:///modules/devtools/dbg-server.jsm", tempScope);
Cu.import("resource:///modules/devtools/dbg-client.jsm", tempScope);
Cu.import("resource:///modules/Services.jsm", tempScope);
let DebuggerServer = tempScope.DebuggerServer;
let DebuggerTransport = tempScope.DebuggerTransport;
let DebuggerClient = tempScope.DebuggerClient;
let Services = tempScope.Services;
const TAB1_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_tab1.html";
const TAB2_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_tab2.html";
const STACK_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_stack.html";
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
waitForExplicitFinish();
function addTab(aURL, aOnload)
{
gBrowser.selectedTab = gBrowser.addTab(aURL);
let tab = gBrowser.selectedTab;
if (aOnload) {
let handler = function() {
if (tab.linkedBrowser.currentURI.spec == aURL) {
tab.removeEventListener("load", handler, false);
aOnload();
}
}
tab.addEventListener("load", handler, false);
}
return tab;
}
function removeTab(aTab) {
gBrowser.removeTab(aTab);
}
function get_tab_actor_for_url(aClient, aURL, aCallback) {
aClient.listTabs(function(aResponse) {
for each (let tab in aResponse.tabs) {
if (tab.url == aURL) {
aCallback(tab);
return;
}
}
});
}
function attach_tab_actor_for_url(aClient, aURL, aCallback) {
get_tab_actor_for_url(aClient, aURL, function(actor) {
aClient.request({ to: actor.actor, type: "attach" }, function(aResponse) {
aCallback(actor, aResponse);
});
});
}
function attach_thread_actor_for_url(aClient, aURL, aCallback) {
attach_tab_actor_for_url(aClient, aURL, function(aTabActor, aResponse) {
aClient.request({ "to": actor.threadActor, "type": "attach" }, function(aResponse) {
// We don't care about the pause right now (use
// get_actor_for_url() if you do), so resume it.
aClient.request({ to: actor.threadActor, type: "resume" }, function(aResponse) {
aCallback(actor);
});
});
});
}
function debug_tab_pane(aURL, aOnDebugging)
{
let tab = addTab(aURL, function() {
gBrowser.selectedTab = gTab;
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
let pane = DebuggerUI.toggleDebugger();
pane.onConnected = function() {
// Wait for the initial resume...
pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
delete pane.onConnected;
aOnDebugging(tab, debuggee, pane);
});
};
});
}

Просмотреть файл

@ -0,0 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function firstCall() {
eval("secondCall();");
}

Просмотреть файл

@ -0,0 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function secondCall() {
eval("debugger;");
}

Просмотреть файл

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function TestActor1(aConnection, aTab, aOnDisconnect)
{
this.conn = aConnection;
this.tab = aTab;
this.onDisconnect = aOnDisconnect;
}
TestActor1.prototype = {
actorPrefix: "testone",
disconnect: function TA1_disconnect() {
this.onDisconnect();
},
grip: function TA1_grip() {
return { actor: this.actorID,
test: "TestActor1" };
},
onPing: function TA1_onPing() {
return { pong: "pong" };
}
};
TestActor1.prototype.requestTypes = {
"ping": TestActor1.prototype.onPing
};
DebuggerServer.addTabRequest("testTabActor1", function (aTab) {
if (aTab._testTabActor1) {
return aTab._testTabActor1.grip();
}
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
delete aTab._testTabActor1;
});
aTab.tabActorPool.addActor(actor);
aTab._testTabActor1 = actor;
return actor.grip();
});
DebuggerServer.addTabRequest("testContextActor1", function (aTab, aRequest) {
if (aTab._testContextActor1) {
return aTab._testContextActor1.grip();
}
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
delete aTab._testContextActor1;
});
aTab.contextActorPool.addActor(actor);
aTab._testContextActor1 = actor;
return actor.grip();
});

Просмотреть файл

@ -409,11 +409,11 @@ Highlighter.prototype = {
*
* <box id="highlighter-nodeinfobar-container">
* <box id="Highlighter-nodeinfobar-arrow-top"/>
* <vbox id="highlighter-nodeinfobar">
* <label id="highlighter-nodeinfobar-tagname"/>
* <label id="highlighter-nodeinfobar-id"/>
* <vbox id="highlighter-nodeinfobar-classes"/>
* </vbox>
* <hbox id="highlighter-nodeinfobar">
* <xhtml:span id="highlighter-nodeinfobar-tagname"/>
* <xhtml:span id="highlighter-nodeinfobar-id"/>
* <xhtml:span id="highlighter-nodeinfobar-classes"/>
* </hbox>
* <box id="Highlighter-nodeinfobar-arrow-bottom"/>
* </box>
*
@ -438,16 +438,16 @@ Highlighter.prototype = {
arrowBoxBottom.className = "highlighter-nodeinfobar-arrow";
arrowBoxBottom.id = "highlighter-nodeinfobar-arrow-bottom";
let tagNameLabel = this.chromeDoc.createElement("label");
let tagNameLabel = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
tagNameLabel.id = "highlighter-nodeinfobar-tagname";
tagNameLabel.className = "plain";
let idLabel = this.chromeDoc.createElement("label");
let idLabel = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
idLabel.id = "highlighter-nodeinfobar-id";
idLabel.className = "plain";
let classesBox = this.chromeDoc.createElement("hbox");
let classesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
classesBox.id = "highlighter-nodeinfobar-classes";
// Add some content to force a better boundingClientRect down below.
classesBox.textContent = "&nbsp;";
nodeInfobar.appendChild(tagNameLabel);
nodeInfobar.appendChild(idLabel);
@ -528,7 +528,7 @@ Highlighter.prototype = {
},
/**
* Update node information (tagName#id.class)
* Update node information (tagName#id.class)
*/
updateInfobar: function Highlighter_updateInfobar()
{
@ -540,20 +540,9 @@ Highlighter.prototype = {
// Classes
let classes = this.nodeInfo.classesBox;
while (classes.hasChildNodes()) {
classes.removeChild(classes.firstChild);
}
if (this.node.className) {
let fragment = this.chromeDoc.createDocumentFragment();
for (let i = 0; i < this.node.classList.length; i++) {
let classLabel = this.chromeDoc.createElement("label");
classLabel.className = "highlighter-nodeinfobar-class plain";
classLabel.textContent = "." + this.node.classList[i];
fragment.appendChild(classLabel);
}
classes.appendChild(fragment);
}
classes.textContent = this.node.classList.length ?
"." + Array.join(this.node.classList, ".") : "";
},
/**

Просмотреть файл

@ -222,9 +222,11 @@ InspectorUI.prototype = {
openInspectorUI: function IUI_openInspectorUI(aNode)
{
// InspectorUI is already up and running. Lock a node if asked (via context).
if (this.isInspectorOpen && aNode) {
this.inspectNode(aNode);
this.stopInspecting();
if (this.isInspectorOpen) {
if (aNode) {
this.inspectNode(aNode);
this.stopInspecting();
}
return;
}

Просмотреть файл

@ -25,7 +25,7 @@ function test()
function setupInfobarTest()
{
nodes = [
{node: doc.querySelector("#top"), position: "bottom", tag: "DIV", id: "#top", classes: ".class1 .class2"},
{node: doc.querySelector("#top"), position: "bottom", tag: "DIV", id: "#top", classes: ".class1.class2"},
{node: doc.querySelector("#vertical"), position: "overlap", tag: "DIV", id: "#vertical", classes: ""},
{node: doc.querySelector("#bottom"), position: "top", tag: "DIV", id: "#bottom", classes: ""},
{node: doc.querySelector("body"), position: "overlap", tag: "BODY", id: "", classes: ""},
@ -86,14 +86,7 @@ function test()
is(idLabel.textContent, nodes[cursor].id, "node " + cursor + ": id matches.");
let classesBox = document.getElementById("highlighter-nodeinfobar-classes");
let displayedClasses = [];
for (let i = 0; i < classesBox.childNodes.length; i++) {
displayedClasses.push(classesBox.childNodes[i].textContent);
}
displayedClasses = displayedClasses.join(" ");
is(displayedClasses, nodes[cursor].classes, "node " + cursor + ": classes match.");
is(classesBox.textContent, nodes[cursor].classes, "node " + cursor + ": classes match.");
}
function finishUp() {

Просмотреть файл

@ -11,6 +11,9 @@ browser.jar:
content/browser/devtools/styleinspector.css (styleinspector/styleinspector.css)
content/browser/orion.js (sourceeditor/orion/orion.js)
content/browser/orion.css (sourceeditor/orion/orion.css)
content/browser/orion-mozilla.css (sourceeditor/orion/mozilla.css)
content/browser/source-editor-overlay.xul (sourceeditor/source-editor-overlay.xul)
* content/browser/debugger.xul (debugger/debugger.xul)
content/browser/debugger.css (debugger/debugger.css)
content/browser/debugger.js (debugger/debugger.js)
content/browser/debugger-view.js (debugger/debugger-view.js)

Просмотреть файл

@ -64,7 +64,7 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
* SourceEditor.THEMES to Orion CSS files.
*/
const ORION_THEMES = {
mozilla: ["chrome://browser/content/orion-mozilla.css"],
mozilla: ["chrome://browser/skin/devtools/orion.css"],
};
/**
@ -809,6 +809,20 @@ SourceEditor.prototype = {
return this._model.getLineDelimiter();
},
/**
* Get the indentation string used in the document being edited.
*
* @return string
* The indentation string.
*/
getIndentationString: function SE_getIndentationString()
{
if (this._expandTab) {
return (new Array(this._tabSize + 1)).join(" ");
}
return "\t";
},
/**
* Set the source editor mode to the file type you are editing.
*

Просмотреть файл

@ -324,6 +324,9 @@ function testReturnKey()
let lineDelimiter = editor.getLineDelimiter();
ok(lineDelimiter, "we have the line delimiter");
let indentationString = editor.getIndentationString();
is(" ", indentationString, "we have an indentation string of 7 spaces");
is(editor.getText(), " a" + lineDelimiter + " x\n b\n c",
"return maintains indentation");

Просмотреть файл

@ -46,3 +46,7 @@
.ruleview-code {
direction: ltr;
}
.ruleview-property:not(:hover) > .ruleview-enableproperty {
visibility: hidden;
}

Просмотреть файл

@ -212,6 +212,9 @@ AutocompletePopup.prototype = {
*/
_updateSize: function AP__updateSize()
{
if (!this._panel) {
return;
}
this._list.width = this._panel.clientWidth +
this._scrollbarWidth;
},

Просмотреть файл

@ -6948,6 +6948,12 @@ GcliTerm.prototype = {
this.context = Cu.getWeakReference(aContentWindow);
this.console = aConsole;
this.createSandbox();
this.opts.environment.contentDocument = aContentWindow.document;
this.opts.contentDocument = aContentWindow.document;
this.opts.jsEnvironment.globalObject = unwrap(aContentWindow);
gcli._internal.reattachConsole(this.opts);
},
/**

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -54,44 +54,16 @@ var Node = Components.interfaces.nsIDOMNode;
* http://opensource.org/licenses/BSD-3-Clause
*/
define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite', 'gcli/types/javascript'], function(require, exports, module) {
define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite'], function(require, exports, module) {
var examiner = require('gclitest/suite').examiner;
var javascript = require('gcli/types/javascript');
/**
* Run the tests defined in the test suite
* @param options How the tests are run. Properties include:
* - window: The browser window object to run the tests against
* - useFakeWindow: Use a test subset and a fake DOM to avoid a real document
* - detailedResultLog: console.log test passes and failures in more detail
* A simple proxy to examiner.run, for convenience - this is run from the
* top level.
*/
exports.run = function(options) {
options = options || {};
if (options.useFakeWindow) {
// A minimum fake dom to get us through the JS tests
var doc = { title: 'Fake DOM' };
var fakeWindow = {
window: { document: doc },
document: doc
};
options.window = fakeWindow;
}
if (options.window) {
javascript.setGlobalObject(options.window);
}
examiner.run(options);
if (options.detailedResultLog) {
examiner.log();
}
else {
console.log('Completed test suite');
}
examiner.run(options || {});
};
});
/*
@ -100,7 +72,7 @@ define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite', 'gc
* http://opensource.org/licenses/BSD-3-Clause
*/
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testExec', 'gclitest/testKeyboard', 'gclitest/testScratchpad', 'gclitest/testHistory', 'gclitest/testRequire', 'gclitest/testJs'], function(require, exports, module) {
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testExec', 'gclitest/testKeyboard', 'gclitest/testScratchpad', 'gclitest/testHistory', 'gclitest/testRequire', 'gclitest/testResource', 'gclitest/testJs', 'gclitest/testUtil'], function(require, exports, module) {
// We need to make sure GCLI is initialized before we begin testing it
require('gcli/index');
@ -118,7 +90,9 @@ define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/e
examiner.addSuite('gclitest/testScratchpad', require('gclitest/testScratchpad'));
examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory'));
examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire'));
examiner.addSuite('gclitest/testResource', require('gclitest/testResource'));
examiner.addSuite('gclitest/testJs', require('gclitest/testJs'));
examiner.addSuite('gclitest/testUtil', require('gclitest/testUtil'));
exports.examiner = examiner;
});
@ -161,20 +135,56 @@ examiner.addSuite = function(name, suite) {
};
/**
* Run all the tests synchronously
* Run the tests defined in the test suite synchronously
* @param options How the tests are run. Properties include:
* - window: The browser window object to run the tests against
* - useFakeWindow: Use a test subset and a fake DOM to avoid a real document
* - detailedResultLog: console.log test passes and failures in more detail
*/
examiner.run = function(options) {
examiner._checkOptions(options);
Object.keys(examiner.suites).forEach(function(suiteName) {
var suite = examiner.suites[suiteName];
suite.run(options);
}.bind(this));
if (options.detailedResultLog) {
examiner.log();
}
else {
console.log('Completed test suite');
}
return examiner.suites;
};
/**
* Check the options object. There should be either useFakeWindow or a window.
* Setup the fake window if requested.
*/
examiner._checkOptions = function(options) {
if (options.useFakeWindow) {
// A minimum fake dom to get us through the JS tests
var doc = { title: 'Fake DOM' };
var fakeWindow = {
window: { document: doc },
document: doc
};
options.window = fakeWindow;
}
if (!options.window) {
throw new Error('Tests need either window or useFakeWindow');
}
};
/**
* Run all the tests asynchronously
*/
examiner.runAsync = function(options, callback) {
examiner._checkOptions(options);
this.runAsyncInternal(0, options, callback);
};
@ -286,12 +296,12 @@ Suite.prototype.run = function(options) {
*/
Suite.prototype.runAsync = function(options, callback) {
if (typeof this.suite.setup == "function") {
this.suite.setup();
this.suite.setup(options);
}
this.runAsyncInternal(0, options, function() {
if (typeof this.suite.shutdown == "function") {
this.suite.shutdown();
this.suite.shutdown(options);
}
if (typeof callback === 'function') {
@ -377,7 +387,7 @@ Test.prototype.run = function(options) {
*/
Test.prototype.runAsync = function(options, callback) {
setTimeout(function() {
this.run();
this.run(options);
if (typeof callback === 'function') {
callback();
}
@ -1047,7 +1057,7 @@ function update(input) {
status = requ.getStatus();
assignC = requ.getAssignmentAt(input.cursor.start);
statuses = requ.getInputStatusMarkup(input.cursor.start).map(function(s) {
return s.toString()[0];
return Array(s.string.length + 1).join(s.status.toString()[0]);
}).join('');
if (requ.commandAssignment.getValue()) {
@ -1506,7 +1516,7 @@ var mockDoc = {
* http://opensource.org/licenses/BSD-3-Clause
*/
define('gclitest/testKeyboard', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/types', 'gcli/canon', 'gclitest/commands', 'gcli/types/node', 'test/assert'], function(require, exports, module) {
define('gclitest/testKeyboard', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/types', 'gcli/canon', 'gclitest/commands', 'gcli/types/node', 'gcli/types/javascript', 'test/assert'], function(require, exports, module) {
var Requisition = require('gcli/cli').Requisition;
@ -1514,16 +1524,24 @@ var Status = require('gcli/types').Status;
var canon = require('gcli/canon');
var commands = require('gclitest/commands');
var nodetype = require('gcli/types/node');
var javascript = require('gcli/types/javascript');
var test = require('test/assert');
var tempWindow;
exports.setup = function(options) {
tempWindow = javascript.getGlobalObject();
javascript.setGlobalObject(options.window);
exports.setup = function() {
commands.setup();
};
exports.shutdown = function() {
exports.shutdown = function(options) {
commands.shutdown();
javascript.setGlobalObject(tempWindow);
tempWindow = undefined;
};
var COMPLETES_TO = 'complete';
@ -1661,15 +1679,15 @@ stubScratchpad.activate = function(value) {
exports.testActivate = function(options) {
if (options.inputter) {
var ev = {};
stubScratchpad.activatedCount = 0;
options.inputter.onKeyUp(ev);
test.is(1, stubScratchpad.activatedCount, 'scratchpad is activated');
}
else {
console.log('Skipping scratchpad tests');
if (!options.inputter) {
console.log('No inputter. Skipping scratchpad tests');
return;
}
var ev = {};
stubScratchpad.activatedCount = 0;
options.inputter.onKeyUp(ev);
test.is(1, stubScratchpad.activatedCount, 'scratchpad is activated');
};
@ -1837,6 +1855,86 @@ define('gclitest/requirable', ['require', 'exports', 'module' ], function(requir
exports.setStatus = function(aStatus) { status = aStatus; };
exports.getStatus = function() { return status; };
});
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
*/
define('gclitest/testResource', ['require', 'exports', 'module' , 'gcli/types/resource', 'gcli/types', 'test/assert'], function(require, exports, module) {
var resource = require('gcli/types/resource');
var types = require('gcli/types');
var Status = require('gcli/types').Status;
var test = require('test/assert');
var tempDocument;
exports.setup = function(options) {
tempDocument = resource.getDocument();
resource.setDocument(options.window.document);
};
exports.shutdown = function(options) {
resource.setDocument(tempDocument);
tempDocument = undefined;
};
exports.testPredictions = function(options) {
if (options.useFakeWindow) {
console.log('Skipping resource tests: options.useFakeWindow = true');
return;
}
var resource1 = types.getType('resource');
var predictions1 = resource1.parseString('').getPredictions();
test.ok(predictions1.length > 1, 'have resources');
predictions1.forEach(function(prediction) {
checkPrediction(resource1, prediction);
});
var resource2 = types.getType({ name: 'resource', include: 'text/javascript' });
var predictions2 = resource2.parseString('').getPredictions();
test.ok(predictions2.length > 1, 'have resources');
predictions2.forEach(function(prediction) {
checkPrediction(resource2, prediction);
});
var resource3 = types.getType({ name: 'resource', include: 'text/css' });
var predictions3 = resource3.parseString('').getPredictions();
// jsdom fails to support digging into stylesheets
if (!options.isNode) {
test.ok(predictions3.length > 1, 'have resources');
}
predictions3.forEach(function(prediction) {
checkPrediction(resource3, prediction);
});
var resource4 = types.getType({ name: 'resource' });
var predictions4 = resource4.parseString('').getPredictions();
test.is(predictions1.length, predictions4.length, 'type spec');
test.is(predictions2.length + predictions3.length, predictions4.length, 'split');
};
function checkPrediction(res, prediction) {
var name = prediction.name;
var value = prediction.value;
var conversion = res.parseString(name);
test.is(conversion.getStatus(), Status.VALID, 'status VALID for ' + name);
test.is(conversion.value, value, 'value for ' + name);
var strung = res.stringify(value);
test.is(strung, name, 'stringify for ' + name);
test.is(typeof value.loadContents, 'function', 'resource for ' + name);
test.is(typeof value.element, 'object', 'resource for ' + name);
}
});
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
@ -1859,11 +1957,14 @@ var requ;
var assign;
var status;
var statuses;
var globalObject;
var tempWindow;
exports.setup = function() {
globalObject = javascript.getGlobalObject();
Object.defineProperty(globalObject, 'donteval', {
exports.setup = function(options) {
tempWindow = javascript.getGlobalObject();
javascript.setGlobalObject(options.window);
Object.defineProperty(options.window, 'donteval', {
get: function() {
test.ok(false, 'donteval should not be used');
return { cant: '', touch: '', 'this': '' };
@ -1873,9 +1974,11 @@ exports.setup = function() {
});
};
exports.shutdown = function() {
delete globalObject.donteval;
globalObject = undefined;
exports.shutdown = function(options) {
delete options.window.donteval;
javascript.setGlobalObject(tempWindow);
tempWindow = undefined;
};
function input(typed) {
@ -1894,7 +1997,7 @@ function input(typed) {
status = requ.getStatus();
statuses = requ.getInputStatusMarkup(input.cursor.start).map(function(s) {
return s.toString()[0];
return Array(s.string.length + 1).join(s.status.toString()[0]);
}).join('');
if (requ.commandAssignment.getValue()) {
@ -1948,7 +2051,7 @@ function check(expStatuses, expStatus, expAssign, expPredict) {
}
}
exports.testBasic = function() {
exports.testBasic = function(options) {
input('{');
check('V', Status.ERROR, '');
@ -1976,7 +2079,7 @@ exports.testBasic = function() {
input('{ document.title');
check('VVVVVVVVVVVVVVVV', Status.VALID, 'document.title', 0);
test.ok('donteval' in globalObject, 'donteval exists');
test.ok('donteval' in options.window, 'donteval exists');
input('{ don');
check('VVIII', Status.ERROR, 'don', 'donteval');
@ -2001,6 +2104,35 @@ exports.testBasic = function() {
};
});
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
*/
define('gclitest/testUtil', ['require', 'exports', 'module' , 'gcli/util', 'test/assert'], function(require, exports, module) {
var util = require('gcli/util');
var test = require('test/assert');
exports.testFindCssSelector = function(options) {
if (options.useFakeWindow) {
console.log('Skipping dom.findCssSelector tests due to useFakeWindow');
return;
}
var nodes = options.window.document.querySelectorAll('*');
for (var i = 0; i < nodes.length; i++) {
var selector = util.dom.findCssSelector(nodes[i]);
var matches = options.window.document.querySelectorAll(selector);
test.is(matches.length, 1, 'multiple matches for ' + selector);
test.is(matches[0], nodes[i], 'non-matching selector: ' + selector);
}
};
});
function undefine() {
@ -2018,7 +2150,9 @@ function undefine() {
delete define.modules['gclitest/testHistory'];
delete define.modules['gclitest/testRequire'];
delete define.modules['gclitest/requirable'];
delete define.modules['gclitest/testResource'];
delete define.modules['gclitest/testJs'];
delete define.modules['gclitest/testUtil'];
delete define.globalDomain.modules['gclitest/index'];
delete define.globalDomain.modules['gclitest/suite'];
@ -2034,7 +2168,9 @@ function undefine() {
delete define.globalDomain.modules['gclitest/testHistory'];
delete define.globalDomain.modules['gclitest/testRequire'];
delete define.globalDomain.modules['gclitest/requirable'];
delete define.globalDomain.modules['gclitest/testResource'];
delete define.globalDomain.modules['gclitest/testJs'];
delete define.globalDomain.modules['gclitest/testUtil'];
}
registerCleanupFunction(function() {

Просмотреть файл

@ -193,6 +193,7 @@
@BINPATH@/components/jar.xpt
@BINPATH@/components/jsdservice.xpt
@BINPATH@/components/jsdebugger.xpt
@BINPATH@/components/jsinspector.xpt
@BINPATH@/components/layout_base.xpt
@BINPATH@/components/layout_forms.xpt
#ifdef NS_PRINTING

Просмотреть файл

@ -0,0 +1,40 @@
<!-- LOCALIZATION NOTE : FILE This file contains the Script Debugger strings -->
<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
- keep it in English, or another language commonly spoken among web developers.
- You want to make that choice consistent across the developer tools.
- A good criteria is the language in which you'd find the best
- documentation on web development on the web. -->
<!-- LOCALIZATION NOTE (debuggerMenu.label): This is the label for the
- application menu item that opens the debugger UI. -->
<!ENTITY debuggerMenu.label "Script Debugger">
<!-- LOCALIZATION NOTE (debuggerMenu.commandkey): This is the command key that
- launches the debugger UI. Do not translate this one! -->
<!ENTITY debuggerMenu.commandkey "S">
<!-- LOCALIZATION NOTE (debuggerUI.closeButton): This is the label for the
- button that closes the debugger UI. -->
<!ENTITY debuggerUI.closeButton "Close">
<!-- LOCALIZATION NOTE (debuggerUI.resumeButton): This is the label for the
- button that resumes the debugger, after it has reached a paused state. In
- a paused state the debugger can be used to inspect stack frames, local,
- variables etc. -->
<!ENTITY debuggerUI.resumeButton "Resume">
<!-- LOCALIZATION NOTE (debuggerUI.stackTitle): This is the label for the
- widget that displays the call stack frames in the debugger. -->
<!ENTITY debuggerUI.stackTitle "Call stack">
<!-- LOCALIZATION NOTE (debuggerUI.scriptTitle): This is the label for the
- widget that displays the source code for the script that is currently
- being inspected in the debugger. -->
<!ENTITY debuggerUI.scriptTitle "Script">
<!-- LOCALIZATION NOTE (debuggerUI.propertiesTitle): This is the label for the
- widget that displays the variables in the various available scopes in the
- debugger. -->
<!ENTITY debuggerUI.propertiesTitle "Scope variables">

Просмотреть файл

@ -0,0 +1,46 @@
# LOCALIZATION NOTE These strings are used inside the Script Debugger
# which is available from the Web Developer sub-menu -> 'Script Debugger'.
# The correct localization of this file might be to keep it in
# English, or another language commonly spoken among web developers.
# You want to make that choice consistent across the developer tools.
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (pausedState): The label that is displayed when the
# debugger is in a paused state.
pausedState=Paused
# LOCALIZATION NOTE (runningState): The label that is displayed when the
# debugger is in a running state.
runningState=Running
# LOCALIZATION NOTE (localScope): The label that is displayed in the variables
# pane as a header on the local scope container.
localScope=Local
# LOCALIZATION NOTE (globalScope): The label that is displayed in the variables
# pane as a header on the globel scope container.
globalScope=Global
# LOCALIZATION NOTE (localScope): The label that is displayed in the variables
# pane as a header on the container for identifiers in a with block.
withScope=With block
# LOCALIZATION NOTE (closureScope): The label that is displayed in the variables
# pane as a header on container for identifiers in a closure scope.
closureScope=Closure
# LOCALIZATION NOTE (emptyText): The text that is displayed in the stack frames
# list when there are no frames to display.
emptyText=Empty
# LOCALIZATION NOTE (loadingText): The text that is displayed in the script
# editor when the laoding process has started but there is no file to display
# yet.
loadingText=Loading\u2026
# LOCALIZATION NOTE (loadingError):
# This is the error message that is displayed on failed attempts to load an
# external resource file.
# %1$S=URL, %2$S=status code
loadingError=Error loading %1$S: %2$S

Просмотреть файл

@ -15,6 +15,8 @@
* locale/browser/browser.dtd (%chrome/browser/browser.dtd)
locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd)
locale/browser/browser.properties (%chrome/browser/browser.properties)
locale/browser/devtools/debugger.dtd (%chrome/browser/devtools/debugger.dtd)
locale/browser/devtools/debugger.properties (%chrome/browser/devtools/debugger.properties)
locale/browser/devtools/gcli.properties (%chrome/browser/devtools/gcli.properties)
locale/browser/devtools/gclicommands.properties (%chrome/browser/devtools/gclicommands.properties)
locale/browser/devtools/webconsole.properties (%chrome/browser/devtools/webconsole.properties)

Просмотреть файл

@ -68,6 +68,7 @@ browser/components/shell/public/Makefile
browser/components/shell/src/Makefile
browser/components/tabview/Makefile
browser/devtools/Makefile
browser/devtools/debugger/Makefile
browser/devtools/highlighter/Makefile
browser/devtools/scratchpad/Makefile
browser/devtools/shared/Makefile
@ -136,6 +137,7 @@ if [ "$ENABLE_TESTS" ]; then
browser/components/privatebrowsing/test/browser/Makefile
browser/components/tabview/test/Makefile
browser/components/test/Makefile
browser/devtools/debugger/test/Makefile
browser/devtools/highlighter/test/Makefile
browser/devtools/scratchpad/test/Makefile
browser/devtools/shared/test/Makefile

Просмотреть файл

@ -2019,21 +2019,18 @@ panel[dimmed="true"] {
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-tagname {
html|*#highlighter-nodeinfobar-tagname {
color: white;
}
#highlighter-nodeinfobar-id {
html|*#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
.highlighter-nodeinfobar-class {
color: hsl(200, 100%, 65%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;

Просмотреть файл

@ -0,0 +1,262 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
* Victor Porof <vporof@mozilla.com>
* Panos Astithas <past@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#body {
background: -moz-dialog;
}
div,
span,
a {
font: inherit;
}
/**
* Debugger toolbar
*/
#dbg-toolbar {
padding: 2px;
}
#dbg-toolbar > button {
text-align: center;
}
/**
* Debugger content
*/
#dbg-content {
padding: 6px;
}
#dbg-content > * > .vbox {
background-color: #fff;
border: 1px solid #bbb;
box-shadow: 0 -5px 10px -3px #ccc;
-moz-margin-end: -1px;
}
#dbg-content > * > .title {
text-shadow: 0 1px #fff;
}
/**
* Debugger statusbar
*/
#dbg-statusbar {
font: -moz-list;
padding: 2px;
-moz-padding-start: 5px;
}
/**
* Lists and headers
*/
.list-item {
padding: 2px;
font: -moz-list;
}
.list-item.selected {
background: Highlight;
color: HighlightText;
}
.list-item.empty {
color: GrayText;
}
/**
* Stack frames
*/
#stackframes {
background-color: white;
}
.dbg-stackframe-id {
-moz-padding-end: 1em;
}
/**
* Properties elements
*/
#variables {
background-color: white;
}
/**
* Generic element details container
*/
.details {
-moz-margin-start: 10px;
font: -moz-list;
}
/**
* Scope element
*/
.scope > .title {
margin-top: 1px;
-moz-margin-start: 1px;
-moz-padding-start: 2px;
background: -moz-linear-gradient(bottom,
rgb(160,175,205) 0,
rgb(120,140,175) 100%);
border-bottom: 1px solid #888;
box-shadow: 0 0 4px #ccc;
text-shadow: 0 1px #777;
color: #fff;
font: -moz-list;
}
.scope > .title > .name {
padding-top: 2px;
padding-bottom: 2px;
}
.scope > .details {
-moz-margin-start: 2px;
-moz-margin-end: 2px;
}
/**
* Variable element
*/
.variable {
-moz-margin-start: 1px;
-moz-margin-end: 1px;
border-bottom: 1px dotted #aaa;
}
.variable > .title > .name {
padding-top: 2px;
padding-bottom: 2px;
color: #048;
font-weight: 600;
}
/**
* Property element
*/
.property > .title > .key {
padding-top: 2px;
padding-bottom: 2px;
color: #881090;
}
.property > .title > .value {
padding-top: 2px;
padding-bottom: 2px;
}
/**
* Property colors
*/
.token-undefined {
-moz-padding-start: 6px;
color: #bbb;
}
.token-null {
-moz-padding-start: 6px;
color: #999;
}
.token-boolean {
-moz-padding-start: 6px;
color: #777;
}
.token-number {
-moz-padding-start: 6px;
color: #c40a16;
}
.token-string {
-moz-padding-start: 6px;
color: #1c00cf;
}
.token-other {
-moz-padding-start: 6px;
color: #333;
}
/**
* Expand/collapse arrow
*/
.arrow {
-moz-appearance: treetwisty;
-moz-margin-start: 10px;
-moz-margin-end: 5px;
}
.arrow[open] {
-moz-appearance: treetwistyopen;
}
/**
* Display helpers
*/
.unselectable {
padding-top: 2px;
padding-bottom: 2px;
}
.info {
padding-top: 2px;
padding-bottom: 2px;
}

Просмотреть файл

@ -1,5 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* 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/. */
.viewContainer {
background: #cddae5; /* This will be seen as the continuation of the ruler */
@ -22,17 +23,11 @@
padding-left: 4px; /* Margin between the ruler and the editor */
}
/* Styles for rulers */
.ruler.lines {
text-align: right;
}
/* Styles for the line number ruler */
.rulerLines {
border-right: 1px solid #b4c4d3;
background: #cddae5;
color: #7a8a99;
min-width: 1.4em;
padding-left: 4px;
padding-right: 4px;
text-align: end;
@ -121,9 +116,6 @@
font-weight: bold;
}
.annotationRange.currentBracket {
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}

Просмотреть файл

@ -93,6 +93,7 @@ browser.jar:
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.png (devtools/webconsole.png)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png)
skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png (devtools/breadcrumbs/ltr-end-selected-pressed.png)
skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png (devtools/breadcrumbs/ltr-end-selected.png)
@ -119,6 +120,7 @@ browser.jar:
skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)

Просмотреть файл

@ -2768,21 +2768,18 @@ panel[dimmed="true"] {
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-tagname {
html|*#highlighter-nodeinfobar-tagname {
color: white;
}
#highlighter-nodeinfobar-id {
html|*#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
.highlighter-nodeinfobar-class {
color: hsl(200, 100%, 65%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;

Просмотреть файл

@ -0,0 +1,258 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
* Victor Porof <vporof@mozilla.com>
* Panos Astithas <past@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#body {
background: -moz-dialog;
}
div,
span,
a {
font: inherit;
}
/**
* Debugger toolbar
*/
#dbg-toolbar {
padding: 2px;
}
#dbg-toolbar > button {
text-align: center;
}
#dbg-toolbar > button, menulist {
-moz-appearance: toolbarbutton;
}
/**
* Debugger content
*/
#dbg-content {
padding: 6px;
}
#dbg-content > * > .vbox {
background-color: #fff;
border: 1px solid #bbb;
box-shadow: 0 -5px 10px -3px #ccc;
-moz-margin-end: -1px;
}
#dbg-content > * > .title {
text-shadow: 0 1px #fff;
}
/**
* Debugger statusbar
*/
#dbg-statusbar {
font: -moz-list;
padding: 2px;
-moz-padding-start: 5px;
}
/**
* Lists and headers
*/
.list-item {
padding: 2px;
font: -moz-list;
}
.list-item.selected {
background: Highlight;
color: HighlightText;
}
.list-item.empty {
color: GrayText;
}
/**
* Stack frames
*/
#stackframes {
background-color: white;
}
.dbg-stackframe-id {
-moz-padding-end: 1em;
}
/**
* Properties elements
*/
#variables {
background-color: white;
}
/**
* Generic element details container
*/
.details {
-moz-margin-start: 10px;
font: -moz-list;
}
/**
* Scope element
*/
.scope > .title {
margin-top: 1px;
-moz-margin-start: 1px;
-moz-padding-start: 2px;
background: -moz-linear-gradient(bottom,
rgb(160,175,205) 0,
rgb(120,140,175) 100%);
border-bottom: 1px solid #888;
box-shadow: 0 0 4px #ccc;
text-shadow: 0 1px #777;
color: #fff;
font: -moz-list;
}
.scope > .title > .name {
padding-top: 4px;
}
.scope > .details {
-moz-margin-start: 2px;
-moz-margin-end: 2px;
}
/**
* Variable element
*/
.variable {
-moz-margin-start: 1px;
-moz-margin-end: 1px;
border-bottom: 1px dotted #aaa;
}
.variable > .title > .name {
padding-top: 4px;
color: #048;
font-weight: 600;
}
/**
* Property element
*/
.property > .title > .key {
padding-top: 4px;
color: #881090;
}
.property > .title > .value {
padding-top: 4px;
}
/**
* Property colors
*/
.token-undefined {
-moz-padding-start: 6px;
color: #bbb;
}
.token-null {
-moz-padding-start: 6px;
color: #999;
}
.token-boolean {
-moz-padding-start: 6px;
color: #777;
}
.token-number {
-moz-padding-start: 6px;
color: #c40a16;
}
.token-string {
-moz-padding-start: 6px;
color: #1c00cf;
}
.token-other {
-moz-padding-start: 6px;
color: #333;
}
/**
* Expand/collapse arrow
*/
.arrow {
-moz-appearance: treetwisty;
}
.arrow[open] {
-moz-appearance: treetwistyopen;
}
/**
* Display helpers
*/
.unselectable {
padding-top: 4px;
}
.info {
padding-top: 4px;
}

Просмотреть файл

@ -0,0 +1,121 @@
/* 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/. */
.viewContainer {
background: #cddae5; /* This will be seen as the continuation of the ruler */
font-family: monospace;
font-size: inherit; /* inherit browser's default monospace font size */
}
.view {
color: black; /* Default text color */
background: #f0f0ff; /* Background of the editor */
padding-left: 0;
}
.readonly > .view {
background: #f0f0ff;
}
/* One line */
.viewContent > div {
padding-left: 4px; /* Margin between the ruler and the editor */
}
/* Styles for the line number ruler */
.rulerLines {
border-right: 1px solid #b4c4d3;
background: #cddae5;
color: #7a8a99;
padding-left: 4px;
padding-right: 4px;
text-align: end;
}
.token_singleline_comment {
color: #45a946; /* green */
}
.token_multiline_comment {
color: #45a946; /* green */
}
.token_doc_comment {
color: #45a946; /* green */
}
.token_doc_html_markup {
color: #dd0058; /* purple */
}
.token_doc_tag {
color: #dd0058; /* purple */
}
.token_task_tag { /* "TODO" */
color: black;
background: yellow;
}
.token_string {
color: #1e66b1; /* blue */
font-style: italic;
}
.token_keyword {
color: #dd0058; /* purple */
}
.token_space {
/* images/white_space.png */
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAABnRSTlMA/wAAAACkwsAdAAAAIUlEQVR4nGP4z8CAC+GUIEXuABhgkTuABEiRw2cmae4EAH05X7xDolNRAAAAAElFTkSuQmCC");
background-repeat: no-repeat;
background-position: center center;
}
.token_tab {
/* images/white_tab.png */
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMA/wD/AP83WBt9AAAAMklEQVR4nGP4TwRgoK6i52c3bz5w6zMSA6tJn28d2Lx589nnCAYu63AaSLxJRLoJPwAAeNk0aG4opfMAAAAASUVORK5CYII=");
background-repeat: no-repeat;
background-position: left center;
}
.line_caret { /* Current line */
background: #dae2ee; /* lighter than the background */
}
.readonly .line_caret {
background: #cddae5; /* a bit darker than the background */
}
/* Styling for html syntax highlighting */
.entity-name-tag {
color: #dd0058; /* purple */
}
.entity-other-attribute-name {
color: #dd0058; /* purple */
}
.punctuation-definition-comment {
color: #45a946; /* green */
}
.comment {
color: #45a946; /* green */
}
.string-quoted {
color: #1e66b1; /* blue */
font-style: italic;
}
.invalid {
color: red;
font-weight: bold;
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}

Просмотреть файл

@ -129,6 +129,7 @@ browser.jar:
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
@ -159,6 +160,7 @@ browser.jar:
skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)

Просмотреть файл

@ -2699,21 +2699,18 @@ panel[dimmed="true"] {
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-tagname {
html|*#highlighter-nodeinfobar-tagname {
color: white;
}
#highlighter-nodeinfobar-id {
html|*#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
.highlighter-nodeinfobar-class {
color: hsl(200, 100%, 65%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;

Просмотреть файл

@ -0,0 +1,264 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
* Victor Porof <vporof@mozilla.com>
* Panos Astithas <past@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#body {
background: -moz-dialog;
}
div,
span,
a {
font: inherit;
}
/**
* Debugger toolbar
*/
#dbg-toolbar {
padding: 2px;
}
#dbg-toolbar > button {
text-align: center;
}
/**
* Debugger content
*/
#dbg-content {
padding: 6px;
}
#dbg-content > * > .vbox {
background-color: #fff;
border: 1px solid #bbb;
box-shadow: 0 -5px 10px -3px #ccc;
-moz-margin-end: -1px;
}
#dbg-content > * > .title {
text-shadow: 0 1px #fff;
}
/**
* Debugger statusbar
*/
#dbg-statusbar {
font: -moz-list;
padding: 2px;
-moz-padding-start: 5px;
}
/**
* Lists and headers
*/
.list-item {
padding: 2px;
font: -moz-list;
}
.list-item.selected {
background: Highlight;
color: HighlightText;
}
.list-item.empty {
color: GrayText;
}
/**
* Stack frames
*/
#stackframes {
background-color: white;
}
.dbg-stackframe-id {
-moz-padding-end: 1em;
}
/**
* Properties elements
*/
#variables {
background-color: white;
}
/**
* Generic element details container
*/
.details {
-moz-margin-start: 10px;
font: -moz-list;
}
/**
* Scope element
*/
.scope > .title {
margin-top: 1px;
-moz-margin-start: 1px;
-moz-padding-start: 2px;
background: -moz-linear-gradient(bottom,
rgb(160,175,205) 0,
rgb(120,140,175) 100%);
border-bottom: 1px solid #888;
box-shadow: 0 0 4px #ccc;
text-shadow: 0 1px #777;
color: #fff;
font: -moz-list;
}
.scope > .title > .name {
padding-top: 2px;
padding-bottom: 2px;
}
.scope > .details {
-moz-margin-start: 2px;
-moz-margin-end: 2px;
}
/**
* Variable element
*/
.variable {
-moz-margin-start: 1px;
-moz-margin-end: 1px;
border-bottom: 1px dotted #aaa;
}
.variable > .title > .name {
padding-top: 2px;
padding-bottom: 2px;
color: #048;
font-weight: 600;
}
/**
* Property element
*/
.property > .title > .key {
padding-top: 2px;
padding-bottom: 2px;
color: #881090;
}
.property > .title > .value {
padding-top: 2px;
padding-bottom: 2px;
}
/**
* Property colors
*/
.token-undefined {
-moz-padding-start: 6px;
color: #bbb;
}
.token-null {
-moz-padding-start: 6px;
color: #999;
}
.token-boolean {
-moz-padding-start: 6px;
color: #777;
}
.token-number {
-moz-padding-start: 6px;
color: #c40a16;
}
.token-string {
-moz-padding-start: 6px;
color: #1c00cf;
}
.token-other {
-moz-padding-start: 6px;
color: #333;
}
/**
* Expand/collapse arrow
*/
.arrow {
width: 9px;
height: 9px;
-moz-margin-start: 5px;
-moz-margin-end: 5px;
background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
}
.arrow[open] {
background-image: url("chrome://global/skin/tree/twisty-open.png");
}
/**
* Display helpers
*/
.unselectable {
padding-top: 2px;
padding-bottom: 2px;
}
.info {
padding-top: 2px;
padding-bottom: 2px;
}

Просмотреть файл

@ -0,0 +1,121 @@
/* 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/. */
.viewContainer {
background: #cddae5; /* This will be seen as the continuation of the ruler */
font-family: monospace;
font-size: inherit; /* inherit browser's default monospace font size */
}
.view {
color: black; /* Default text color */
background: #f0f0ff; /* Background of the editor */
padding-left: 0;
}
.readonly > .view {
background: #f0f0ff;
}
/* One line */
.viewContent > div {
padding-left: 4px; /* Margin between the ruler and the editor */
}
/* Styles for the line number ruler */
.rulerLines {
border-right: 1px solid #b4c4d3;
background: #cddae5;
color: #7a8a99;
padding-left: 4px;
padding-right: 4px;
text-align: end;
}
.token_singleline_comment {
color: #45a946; /* green */
}
.token_multiline_comment {
color: #45a946; /* green */
}
.token_doc_comment {
color: #45a946; /* green */
}
.token_doc_html_markup {
color: #dd0058; /* purple */
}
.token_doc_tag {
color: #dd0058; /* purple */
}
.token_task_tag { /* "TODO" */
color: black;
background: yellow;
}
.token_string {
color: #1e66b1; /* blue */
font-style: italic;
}
.token_keyword {
color: #dd0058; /* purple */
}
.token_space {
/* images/white_space.png */
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAABnRSTlMA/wAAAACkwsAdAAAAIUlEQVR4nGP4z8CAC+GUIEXuABhgkTuABEiRw2cmae4EAH05X7xDolNRAAAAAElFTkSuQmCC");
background-repeat: no-repeat;
background-position: center center;
}
.token_tab {
/* images/white_tab.png */
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMA/wD/AP83WBt9AAAAMklEQVR4nGP4TwRgoK6i52c3bz5w6zMSA6tJn28d2Lx589nnCAYu63AaSLxJRLoJPwAAeNk0aG4opfMAAAAASUVORK5CYII=");
background-repeat: no-repeat;
background-position: left center;
}
.line_caret { /* Current line */
background: #dae2ee; /* lighter than the background */
}
.readonly .line_caret {
background: #cddae5; /* a bit darker than the background */
}
/* Styling for html syntax highlighting */
.entity-name-tag {
color: #dd0058; /* purple */
}
.entity-other-attribute-name {
color: #dd0058; /* purple */
}
.punctuation-definition-comment {
color: #45a946; /* green */
}
.comment {
color: #45a946; /* green */
}
.string-quoted {
color: #1e66b1; /* blue */
font-style: italic;
}
.invalid {
color: red;
font-weight: bold;
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}

Просмотреть файл

@ -105,7 +105,7 @@
height: 26px;
background-origin: border-box;
background-clip: border-box;
border-top: 1px solid hsla(210,8%,5%,.5);
border-top-width: 0;
border-bottom: 1px solid hsla(210,8%,5%,.65);
padding: 3px;
}

Просмотреть файл

@ -113,6 +113,7 @@ browser.jar:
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
@ -143,6 +144,7 @@ browser.jar:
skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
@ -275,6 +277,7 @@ browser.jar:
skin/classic/aero/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/aero/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/aero/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/aero/browser/devtools/orion.css (devtools/orion.css)
skin/classic/aero/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/aero/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
@ -305,6 +308,7 @@ browser.jar:
skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
skin/classic/aero/browser/devtools/splitview.css (devtools/splitview.css)
skin/classic/aero/browser/devtools/styleeditor.css (devtools/styleeditor.css)
skin/classic/aero/browser/devtools/debugger.css (devtools/debugger.css)
skin/classic/aero/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
skin/classic/aero/browser/devtools/itemToggle.png (devtools/itemToggle.png)
skin/classic/aero/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)

Просмотреть файл

@ -15,6 +15,7 @@
[include:embedding/tests/unit/xpcshell.ini]
[include:toolkit/components/commandlines/test/unit/xpcshell.ini]
[include:toolkit/components/contentprefs/tests/unit/xpcshell.ini]
[include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
[include:toolkit/components/passwordmgr/test/unit/xpcshell.ini]
# Bug 676989: tests hang on Android
skip-if = os == "android"

Просмотреть файл

@ -48,6 +48,7 @@ include $(DEPTH)/config/autoconf.mk
PARALLEL_DIRS = \
components \
content \
devtools \
locales \
mozapps/downloads \
mozapps/extensions \

Просмотреть файл

@ -0,0 +1,49 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Panos Astithas <past@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(topsrcdir)/config/config.mk
PARALLEL_DIRS += \
debugger \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,76 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation <http://www.mozilla.org/>.
# Portions created by the Initial Developer are Copyright (C) 2009-2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Dave Camp <dcamp@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = jsinspector
MODULE_NAME = jsinspector
GRE_MODULE = 1
LIBRARY_NAME = jsinspector
XPIDL_MODULE = jsinspector
LIBXUL_LIBRARY = 1
EXPORT_LIBRARY = 1
IS_COMPONENT = 1
CPPSRCS = \
nsJSInspector.cpp \
$(NULL)
EXTRA_DSO_LDOPTS += \
$(MOZ_COMPONENT_LIBS) \
$(MOZ_JS_LIBS) \
$(NULL)
XPIDLSRCS = \
nsIJSInspector.idl \
$(NULL)
ifdef ENABLE_TESTS
DIRS += tests
endif
include $(topsrcdir)/config/rules.mk
libs::
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
$(NSINSTALL) $(srcdir)/server/*.jsm $(FINAL_TARGET)/modules/devtools

Просмотреть файл

@ -0,0 +1,940 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Debug Protocol Client code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com> (original author)
* Panos Astithas <past@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
const Cr = Components.results;
var EXPORTED_SYMBOLS = ["DebuggerTransport",
"DebuggerClient",
"debuggerSocketConnect"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "socketTransportService",
"@mozilla.org/network/socket-transport-service;1",
"nsISocketTransportService");
function dumpn(str)
{
dump("DBG-CLIENT: " + str + "\n");
}
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://global/content/devtools/dbg-transport.js");
/**
* Add simple event notification to a prototype object. Any object that has
* some use for event notifications or the observer pattern in general can be
* augmented with the necessary facilities by passing its prototype to this
* function.
*
* @param aProto object
* The prototype object that will be modified.
*/
function eventSource(aProto) {
/**
* Add a listener to the event source for a given event.
*
* @param aName string
* The event to listen for, or null to listen to all events.
* @param aListener function
* Called when the event is fired. If the same listener
* is added more the once, it will be called once per
* addListener call.
*/
aProto.addListener = function EV_addListener(aName, aListener) {
if (typeof aListener != "function") {
return;
}
if (!this._listeners) {
this._listeners = {};
}
if (!aName) {
aName = '*';
}
this._getListeners(aName).push(aListener);
};
/**
* Add a listener to the event source for a given event. The
* listener will be removed after it is called for the first time.
*
* @param aName string
* The event to listen for, or null to respond to the first event
* fired by the object.
* @param aListener function
* Called when the event is fired.
*/
aProto.addOneTimeListener = function EV_addOneTimeListener(aName, aListener) {
let self = this;
let l = function() {
self.removeListener(aName, l);
aListener.apply(null, arguments);
};
this.addListener(aName, l);
};
/**
* Remove a listener from the event source previously added with
* addListener().
*
* @param aName string
* The event name used during addListener to add the listener.
* @param aListener function
* The callback to remove. If addListener was called multiple
* times, all instances will be removed.
*/
aProto.removeListener = function EV_removeListener(aName, aListener) {
if (!this._listeners || !this._listeners[aName]) {
return;
}
this._listeners[aName] =
this._listeners[aName].filter(function(l) { return l != aListener });
};
/**
* Returns the listeners for the specified event name. If none are defined it
* initializes an empty list and returns that.
*
* @param aName string
* The event name.
*/
aProto._getListeners = function EV_getListeners(aName) {
if (aName in this._listeners) {
return this._listeners[aName];
}
this._listeners[aName] = [];
return this._listeners[aName];
};
/**
* Notify listeners of an event.
*
* @param aName string
* The event to fire.
* @param arguments
* All arguments will be passed along to the listeners,
* including the name argument.
*/
aProto.notify = function EV_notify() {
if (!this._listeners) {
return;
}
let name = arguments[0];
let listeners = this._getListeners(name).slice(0);
if (this._listeners['*']) {
listeners.concat(this._listeners['*']);
}
for each (let listener in listeners) {
try {
listener.apply(null, arguments);
} catch (e) {
// Prevent a bad listener from interfering with the others.
Cu.reportError(e);
}
}
}
}
/**
* Set of protocol messages that affect thread state, and the
* state the actor is in after each message.
*/
const ThreadStateTypes = {
"paused": "paused",
"resumed": "attached",
"detached": "detached"
};
/**
* Set of debug protocol request types that specify the protocol request being
* sent to the server.
*/
const DebugProtocolTypes = {
"attach": "attach",
"clientEvaluate": "clientEvaluate",
"delete": "delete",
"detach": "detach",
"frames": "frames",
"listTabs": "listTabs",
"nameAndParameters": "nameAndParameters",
"ownPropertyNames": "ownPropertyNames",
"property": "property",
"prototype": "prototype",
"prototypeAndProperties": "prototypeAndProperties",
"resume": "resume",
"scripts": "scripts",
"setBreakpoint": "setBreakpoint"
};
const ROOT_ACTOR_NAME = "root";
/**
* Creates a client for the remote debugging protocol server. This client
* provides the means to communicate with the server and exchange the messages
* required by the protocol in a traditional JavaScript API.
*/
function DebuggerClient(aTransport)
{
this._transport = aTransport;
this._transport.hooks = this;
this._threadClients = {};
this._tabClients = {};
this._pendingRequests = [];
this._activeRequests = {};
this._eventsEnabled = true;
}
DebuggerClient.prototype = {
/**
* Connect to the server and start exchanging protocol messages.
*
* @param aOnConnected function
* If specified, will be called when the greeting packet is
* received from the debugging server.
*/
connect: function DC_connect(aOnConnected) {
if (aOnConnected) {
this.addOneTimeListener("connected", function(aName, aApplicationType, aTraits) {
aOnConnected(aApplicationType, aTraits);
});
}
this._transport.ready();
},
/**
* Shut down communication with the debugging server.
*
* @param aOnClosed function
* If specified, will be called when the debugging connection
* has been closed.
*/
close: function DC_close(aOnClosed) {
// Disable detach event notifications, because event handlers will be in a
// cleared scope by the time they run.
this._eventsEnabled = false;
if (aOnClosed) {
this.addOneTimeListener('closed', function(aEvent) {
aOnClosed();
});
}
let closeTransport = function _closeTransport() {
this._transport.close();
this._transport = null;
}.bind(this);
let detachTab = function _detachTab() {
if (this.activeTab) {
this.activeTab.detach(closeTransport);
} else {
closeTransport();
}
}.bind(this);
if (this.activeThread) {
this.activeThread.detach(detachTab);
} else {
detachTab();
}
},
/**
* List the open tabs.
*
* @param function aOnResponse
* Called with the response packet.
*/
listTabs: function DC_listTabs(aOnResponse) {
let packet = { to: ROOT_ACTOR_NAME, type: DebugProtocolTypes.listTabs };
this.request(packet, function(aResponse) {
aOnResponse(aResponse);
});
},
/**
* Attach to a tab actor.
*
* @param string aTabActor
* The actor ID for the tab to attach.
* @param function aOnResponse
* Called with the response packet and a TabClient
* (which will be undefined on error).
*/
attachTab: function DC_attachTab(aTabActor, aOnResponse) {
let self = this;
let packet = { to: aTabActor, type: DebugProtocolTypes.attach };
this.request(packet, function(aResponse) {
if (!aResponse.error) {
var tabClient = new TabClient(self, aTabActor);
self._tabClients[aTabActor] = tabClient;
self.activeTab = tabClient;
}
aOnResponse(aResponse, tabClient);
});
},
/**
* Attach to a thread actor.
*
* @param string aThreadActor
* The actor ID for the thread to attach.
* @param function aOnResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
*/
attachThread: function DC_attachThread(aThreadActor, aOnResponse) {
let self = this;
let packet = { to: aThreadActor, type: DebugProtocolTypes.attach };
this.request(packet, function(aResponse) {
if (!aResponse.error) {
var threadClient = new ThreadClient(self, aThreadActor);
self._threadClients[aThreadActor] = threadClient;
self.activeThread = threadClient;
}
aOnResponse(aResponse, threadClient);
});
},
/**
* Send a request to the debugging server.
*
* @param aRequest object
* A JSON packet to send to the debugging server.
* @param aOnResponse function
* If specified, will be called with the response packet when
* debugging server responds.
*/
request: function DC_request(aRequest, aOnResponse) {
if (!this._connected) {
throw "Have not yet received a hello packet from the server.";
}
if (!aRequest.to) {
throw "Request packet has no destination.";
}
this._pendingRequests.push({ to: aRequest.to,
request: aRequest,
onResponse: aOnResponse });
this._sendRequests();
},
/**
* Send pending requests to any actors that don't already have an
* active request.
*/
_sendRequests: function DC_sendRequests() {
let self = this;
this._pendingRequests = this._pendingRequests.filter(function(request) {
if (request.to in self._activeRequests) {
return true;
}
self._activeRequests[request.to] = request;
self._transport.send(request.request);
return false;
});
},
// Transport hooks.
/**
* Called by DebuggerTransport to dispatch incoming packets as appropriate.
*
* @param aPacket object
* The incoming packet.
*/
onPacket: function DC_onPacket(aPacket) {
if (!this._connected) {
// Hello packet.
this._connected = true;
this.notify("connected",
aPacket.applicationType,
aPacket.traits);
return;
}
try {
if (!aPacket.from) {
dumpn("Server did not specify an actor, dropping packet: " + JSON.stringify(aPacket));
return;
}
let onResponse;
if (aPacket.from in this._activeRequests) {
onResponse = this._activeRequests[aPacket.from].onResponse;
delete this._activeRequests[aPacket.from];
}
// paused/resumed/detached get special treatment...
if (aPacket.type in ThreadStateTypes &&
aPacket.from in this._threadClients) {
this._threadClients[aPacket.from]._onThreadState(aPacket);
}
this.notify(aPacket.type, aPacket);
if (onResponse) {
onResponse(aPacket);
}
} catch(ex) {
dumpn("Error handling response: " + ex + " - " + ex.stack);
Cu.reportError(ex);
}
this._sendRequests();
},
/**
* Called by DebuggerTransport when the underlying stream is closed.
*
* @param aStatus nsresult
* The status code that corresponds to the reason for closing
* the stream.
*/
onClosed: function DC_onClosed(aStatus) {
this.notify("closed");
},
}
eventSource(DebuggerClient.prototype);
/**
* Creates a tab client for the remote debugging protocol server. This client
* is a front to the tab actor created in the server side, hiding the protocol
* details in a traditional JavaScript API.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aActor string
* The actor ID for this tab.
*/
function TabClient(aClient, aActor) {
this._client = aClient;
this._actor = aActor;
}
TabClient.prototype = {
/**
* Detach the client from the tab actor.
*
* @param function aOnResponse
* Called with the response packet.
*/
detach: function TabC_detach(aOnResponse) {
let self = this;
let packet = { to: this._actor, type: DebugProtocolTypes.detach };
this._client.request(packet, function(aResponse) {
if (self.activeTab === self._client._tabClients[self._actor]) {
delete self.activeTab;
}
delete self._client._tabClients[self._actor];
if (aOnResponse) {
aOnResponse(aResponse);
}
});
}
};
eventSource(TabClient.prototype);
/**
* Creates a thread client for the remote debugging protocol server. This client
* is a front to the thread actor created in the server side, hiding the
* protocol details in a traditional JavaScript API.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aActor string
* The actor ID for this thread.
*/
function ThreadClient(aClient, aActor) {
this._client = aClient;
this._actor = aActor;
this._frameCache = [];
this._scriptCache = {};
}
ThreadClient.prototype = {
_state: "paused",
get state() { return this._state; },
_actor: null,
get actor() { return this._actor; },
_assertPaused: function TC_assertPaused(aCommand) {
if (this._state !== "paused") {
throw aCommand + " command sent while not paused.";
}
},
/**
* Resume a paused thread.
*
* @param function aOnResponse
* Called with the response packet.
*/
resume: function TC_resume(aOnResponse) {
this._assertPaused("resume");
// Put the client in a tentative "resuming" state so we can prevent
// further requests that should only be sent in the paused state.
this._state = "resuming";
let self = this;
let packet = { to: this._actor, type: DebugProtocolTypes.resume };
this._client.request(packet, function(aResponse) {
if (aResponse.error) {
// There was an error resuming, back to paused state.
self._state = "paused";
}
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Send a clientEvaluate packet to the debuggee. Response
* will be a resume packet.
*/
eval: function TC_eval(aFrame, aExpression, aOnResponse) {
this._assertPaused("eval");
// Put the client in a tentative "resuming" state so we can prevent
// further requests that should only be sent in the paused state.
this._state = "resuming";
let self = this;
let request = { to: this._actor, type: DebugProtocolTypes.clientEvaluate,
frame: aFrame, expression: aExpression };
this._client.request(request, function(aResponse) {
if (aResponse.error) {
// There was an error resuming, back to paused state.
self._state = "paused";
}
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Detach from the thread actor.
*
* @param function aOnResponse
* Called with the response packet.
*/
detach: function TC_detach(aOnResponse) {
let self = this;
let packet = { to: this._actor, type: DebugProtocolTypes.detach };
this._client.request(packet, function(aResponse) {
if (self.activeThread === self._client._threadClients[self._actor]) {
delete self.activeThread;
}
delete self._client._threadClients[self._actor];
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Request to set a breakpoint in the specified location.
*
* @param aLocation object
* The source location object where the breakpoint
* will be set.
* @param aOnResponse integer
* Called with the thread's response.
*/
setBreakpoint: function TC_setBreakpoint(aLocation, aOnResponse) {
this._assertPaused("setBreakpoint");
let self = this;
let packet = { to: this._actor, type: DebugProtocolTypes.setBreakpoint,
location: aLocation };
this._client.request(packet, function (aResponse) {
if (aOnResponse) {
let bpClient = new BreakpointClient(self._client,
aResponse.actor);
aOnResponse(aResponse, bpClient);
}
});
},
/**
* Request the loaded scripts for the current thread.
*
* @param aOnResponse integer
* Called with the thread's response.
*/
getScripts: function TC_getScripts(aOnResponse) {
let packet = { to: this._actor, type: DebugProtocolTypes.scripts };
this._client.request(packet, aOnResponse);
},
/**
* A cache of source scripts. Clients can observe the scriptsadded and
* scriptscleared event to keep up to date on changes to this cache,
* and can fill it using the fillScripts method.
*/
get cachedScripts() { return this._scriptCache; },
/**
* Ensure that source scripts have been loaded in the
* ThreadClient's source script cache. A scriptsadded event will be
* sent when the source script cache is updated.
*
* @returns true if a scriptsadded notification should be expected.
*/
fillScripts: function TC_fillScripts() {
let self = this;
this.getScripts(function(aResponse) {
for each (let script in aResponse.scripts) {
self._scriptCache[script.url] = script;
}
// If the cache was modified, notify listeners.
if (aResponse.scripts && aResponse.scripts.length) {
self.notify("scriptsadded");
}
});
return true;
},
/**
* Clear the thread's source script cache. A scriptscleared event
* will be sent.
*/
_clearScripts: function TC_clearScripts() {
if (Object.keys(this._scriptCache).length > 0) {
this._scriptCache = {}
this.notify("scriptscleared");
}
},
/**
* Request frames from the callstack for the current thread.
*
* @param aStart integer
* The number of the youngest stack frame to return (the youngest
* frame is 0).
* @param aCount integer
* The maximum number of frames to return, or null to return all
* frames.
* @param aOnResponse function
* Called with the thread's response.
*/
getFrames: function TC_getFrames(aStart, aCount, aOnResponse) {
this._assertPaused("frames");
let packet = { to: this._actor, type: DebugProtocolTypes.frames,
start: aStart, count: aCount ? aCount : undefined };
this._client.request(packet, aOnResponse);
},
/**
* An array of cached frames. Clients can observe the framesadded and
* framescleared event to keep up to date on changes to this cache,
* and can fill it using the fillFrames method.
*/
get cachedFrames() { return this._frameCache; },
/**
* true if there are more stack frames available on the server.
*/
get moreFrames() {
return this.state === "paused"
&& (!this._frameCache || this._frameCache.length == 0
|| !this._frameCache[this._frameCache.length - 1].oldest);
},
/**
* Ensure that at least aTotal stack frames have been loaded in the
* ThreadClient's stack frame cache. A framesadded event will be
* sent when the stack frame cache is updated.
*
* @param aTotal number
* The minimum number of stack frames to be included.
*
* @returns true if a framesadded notification should be expected.
*/
fillFrames: function TC_fillFrames(aTotal) {
this._assertPaused("fillFrames");
if (this._frameCache.length >= aTotal) {
return false;
}
let numFrames = this._frameCache.length;
let self = this;
this.getFrames(numFrames, aTotal - numFrames, function(aResponse) {
for each (let frame in aResponse.frames) {
self._frameCache[frame.depth] = frame;
}
// If we got as many frames as we asked for, there might be more
// frames available.
self.notify("framesadded");
});
return true;
},
/**
* Clear the thread's stack frame cache. A framescleared event
* will be sent.
*/
_clearFrames: function TC_clearFrames() {
if (this._frameCache.length > 0) {
this._frameCache = [];
this.notify("framescleared");
}
},
/**
* Return a GripClient object for the given object grip.
*
* @param aGrip object
* A pause-lifetime object grip returned by the protocol.
*/
pauseGrip: function TC_pauseGrip(aGrip) {
if (!this._pauseGrips) {
this._pauseGrips = {};
}
if (aGrip.actor in this._pauseGrips) {
return this._pauseGrips[aGrip.actor];
}
let client = new GripClient(this._client, aGrip);
this._pauseGrips[aGrip.actor] = client;
return client;
},
/**
* Invalidate pause-lifetime grip clients and clear the list of
* current grip clients.
*/
_clearPauseGrips: function TC_clearPauseGrips(aPacket) {
for each (let grip in this._pauseGrips) {
grip.valid = false;
}
this._pauseGrips = null;
},
/**
* Handle thread state change by doing necessary cleanup and notifying all
* registered listeners.
*/
_onThreadState: function TC_onThreadState(aPacket) {
this._state = ThreadStateTypes[aPacket.type];
this._clearFrames();
this._clearPauseGrips();
this._client._eventsEnabled && this.notify(aPacket.type, aPacket);
},
};
eventSource(ThreadClient.prototype);
/**
* Grip clients are used to retrieve information about the relevant object.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aGrip object
* A pause-lifetime object grip returned by the protocol.
*/
function GripClient(aClient, aGrip)
{
this._grip = aGrip;
this._client = aClient;
}
GripClient.prototype = {
get actor() { return this._grip.actor },
_valid: true,
get valid() { return this._valid; },
set valid(aValid) { this._valid = !!aValid; },
/**
* Request the name of the function and its formal parameters.
*
* @param aOnResponse function
* Called with the request's response.
*/
getSignature: function GC_getSignature(aOnResponse) {
if (this._grip["class"] !== "Function") {
throw "getSignature is only valid for function grips.";
}
let packet = { to: this.actor, type: DebugProtocolTypes.nameAndParameters };
this._client.request(packet, function (aResponse) {
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Request the names of the properties defined on the object and not its
* prototype.
*
* @param aOnResponse function Called with the request's response.
*/
getOwnPropertyNames: function GC_getOwnPropertyNames(aOnResponse) {
let packet = { to: this.actor, type: DebugProtocolTypes.ownPropertyNames };
this._client.request(packet, function (aResponse) {
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Request the prototype and own properties of the object.
*
* @param aOnResponse function Called with the request's response.
*/
getPrototypeAndProperties: function GC_getPrototypeAndProperties(aOnResponse) {
let packet = { to: this.actor,
type: DebugProtocolTypes.prototypeAndProperties };
this._client.request(packet, function (aResponse) {
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Request the property descriptor of the object's specified property.
*
* @param aName string The name of the requested property.
* @param aOnResponse function Called with the request's response.
*/
getProperty: function GC_getProperty(aName, aOnResponse) {
let packet = { to: this.actor, type: DebugProtocolTypes.property,
name: aName };
this._client.request(packet, function (aResponse) {
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Request the prototype of the object.
*
* @param aOnResponse function Called with the request's response.
*/
getPrototype: function GC_getPrototype(aOnResponse) {
let packet = { to: this.actor, type: DebugProtocolTypes.prototype };
this._client.request(packet, function (aResponse) {
if (aOnResponse) {
aOnResponse(aResponse);
}
});
}
};
/**
* Breakpoint clients are used to remove breakpoints that are no longer used.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aActor string
* The actor ID for this breakpoint.
*/
function BreakpointClient(aClient, aActor) {
this._client = aClient;
this._actor = aActor;
}
BreakpointClient.prototype = {
_actor: null,
get actor() { return this._actor; },
/**
* Remove the breakpoint from the server.
*/
remove: function BC_remove(aOnResponse) {
let packet = { to: this._actor, type: DebugProtocolTypes["delete"] };
this._client.request(packet, function(aResponse) {
if (aOnResponse) {
aOnResponse(aResponse);
}
});
}
};
eventSource(BreakpointClient.prototype);
/**
* Connects to a debugger server socket and returns a DebuggerTransport.
*
* @param aHost string
* The host name or IP address of the debugger server.
* @param aPort number
* The port number of the debugger server.
*/
function debuggerSocketConnect(aHost, aPort)
{
let s = socketTransportService.createTransport(null, 0, aHost, aPort, null);
let transport = new DebuggerTransport(s.openInputStream(0, 0, 0),
s.openOutputStream(0, 0, 0));
return transport;
}

Просмотреть файл

@ -0,0 +1,182 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
Cu.import("resource://gre/modules/NetUtil.jsm");
/**
* An adapter that handles data transfers between the debugger client and
* server. It can work with both nsIPipe and nsIServerSocket transports so
* long as the properly created input and output streams are specified. Data is
* transferred as a JSON packet serialized into a string, with the string length
* prepended to the packet, followed by a colon ([length]:[packet]). The
* contents of the JSON packet are specified in the Remote Debugging Protocol
* specification.
*
* @param aInput nsIInputStream
* The input stream.
* @param aOutput nsIOutputStream
* The output stream.
*/
function DebuggerTransport(aInput, aOutput)
{
this._input = aInput;
this._output = aOutput;
this._outgoing = "";
this._incoming = "";
}
DebuggerTransport.prototype = {
_hooks: null,
get hooks() { return this._hooks; },
set hooks(aHooks) { this._hooks = aHooks; },
/**
* Transmit the specified packet.
*/
send: function DT_send(aPacket) {
// TODO (bug 709088): remove pretty printing when the protocol is done.
let data = JSON.stringify(aPacket, null, 2);
data = data.length + ':' + data;
this._outgoing += data;
this._flushOutgoing();
},
/**
* Close the transport.
*/
close: function DT_close() {
this._input.close();
this._output.close();
},
/**
* Flush the outgoing stream.
*/
_flushOutgoing: function DT_flushOutgoing() {
if (this._outgoing.length > 0) {
var threadManager = Cc["@mozilla.org/thread-manager;1"].getService();
this._output.asyncWait(this, 0, 0, threadManager.currentThread);
}
},
onOutputStreamReady: function DT_onOutputStreamReady(aStream) {
let written = aStream.write(this._outgoing, this._outgoing.length);
this._outgoing = this._outgoing.slice(written);
this._flushOutgoing();
},
/**
* Initialize the input stream for reading.
*/
ready: function DT_ready() {
let pump = Cc["@mozilla.org/network/input-stream-pump;1"]
.createInstance(Ci.nsIInputStreamPump);
pump.init(this._input, -1, -1, 0, 0, false);
pump.asyncRead(this, null);
},
// nsIStreamListener
onStartRequest: function DT_onStartRequest(aRequest, aContext) {},
onStopRequest: function DT_onStopRequest(aRequest, aContext, aStatus) {
this.close();
this.hooks.onClosed(aStatus);
},
onDataAvailable: function DT_onDataAvailable(aRequest, aContext,
aStream, aOffset, aCount) {
try {
this._incoming += NetUtil.readInputStreamToString(aStream,
aStream.available());
while (this._processIncoming()) {};
} catch(e) {
dumpn("Unexpected error reading from debugging connection: " + e + " - " + e.stack);
this.close();
return;
}
},
/**
* Process incoming packets. Returns true if a packet has been received, either
* if it was properly parsed or not. Returns false if the incoming stream does
* not contain a full packet yet. After a proper packet is parsed, the dispatch
* handler DebuggerTransport.hooks.onPacket is called with the packet as a
* parameter.
*/
_processIncoming: function DT__processIncoming() {
// Well this is ugly.
let sep = this._incoming.indexOf(':');
if (sep < 0) {
return false;
}
let count = parseInt(this._incoming.substring(0, sep));
if (this._incoming.length - (sep + 1) < count) {
// Don't have a complete request yet.
return false;
}
// We have a complete request, pluck it out of the data and parse it.
this._incoming = this._incoming.substring(sep + 1);
let packet = this._incoming.substring(0, count);
this._incoming = this._incoming.substring(count);
try {
var parsed = JSON.parse(packet);
} catch(e) {
dumpn("Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")");
return true;
}
try {
dumpn("Got: " + packet);
let thr = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
let self = this;
thr.dispatch({run: function() {
self.hooks.onPacket(parsed);
}}, 0);
} catch(e) {
dumpn("Error handling incoming packet: " + e + " - " + e.stack);
dumpn("Packet was: " + packet);
}
return true;
}
}

Просмотреть файл

@ -0,0 +1,67 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
/**
* Utilities for integrating the JSInspector object into an XPCOM
* application.
*/
[scriptable, uuid(dbf84113-506a-4fd3-9183-a0348c6fa9cc)]
interface nsIJSInspector : nsISupports
{
/**
* Process the thread's event queue until exit.
*
* @return depth Returns the number of times the event loop
* has been nested using this API.
*/
unsigned long enterNestedEventLoop();
/**
* Exits the current nested event loop.
*
* @return depth The number of nested event loops left after
* exiting the event loop.
*
* @throws NS_ERROR_FAILURE if there are no nested event loops
* running.
*/
unsigned long exitNestedEventLoop();
readonly attribute unsigned long eventLoopNestLevel;
};

Просмотреть файл

@ -0,0 +1,146 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation <http://www.mozilla.org/>.
* Portions created by the Initial Developer are Copyright (C) 2009-2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsJSInspector.h"
#include "nsIXPConnect.h"
#include "nsIJSContextStack.h"
#include "nsThreadUtils.h"
#include "jsapi.h"
#include "jsgc.h"
#include "jsfriendapi.h"
#include "jsdbgapi.h"
#include "mozilla/ModuleUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsMemory.h"
#define JSINSPECTOR_CONTRACTID \
"@mozilla.org/jsinspector;1"
#define JSINSPECTOR_CID \
{ 0xec5aa99c, 0x7abb, 0x4142, { 0xac, 0x5f, 0xaa, 0xb2, 0x41, 0x9e, 0x38, 0xe2 } }
namespace mozilla {
namespace jsinspector {
NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSInspector)
NS_IMPL_ISUPPORTS1(nsJSInspector, nsIJSInspector)
nsJSInspector::nsJSInspector() : mNestedLoopLevel(0)
{
}
nsJSInspector::~nsJSInspector()
{
}
NS_IMETHODIMP
nsJSInspector::EnterNestedEventLoop(PRUint32 *out)
{
nsresult rv;
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 nestLevel = ++mNestedLoopLevel;
if (NS_SUCCEEDED(stack->Push(nsnull))) {
while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
if (!NS_ProcessNextEvent())
rv = NS_ERROR_UNEXPECTED;
}
JSContext *cx;
stack->Pop(&cx);
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
} else {
rv = NS_ERROR_FAILURE;
}
NS_ASSERTION(mNestedLoopLevel <= nestLevel,
"nested event didn't unwind properly");
if (mNestedLoopLevel == nestLevel)
--mNestedLoopLevel;
*out = mNestedLoopLevel;
return rv;
}
NS_IMETHODIMP
nsJSInspector::ExitNestedEventLoop(PRUint32 *out)
{
if (mNestedLoopLevel > 0) {
--mNestedLoopLevel;
} else {
return NS_ERROR_FAILURE;
}
*out = mNestedLoopLevel;
return NS_OK;
}
NS_IMETHODIMP
nsJSInspector::GetEventLoopNestLevel(PRUint32 *out)
{
*out = mNestedLoopLevel;
return NS_OK;
}
}
}
NS_DEFINE_NAMED_CID(JSINSPECTOR_CID);
static const mozilla::Module::CIDEntry kJSInspectorCIDs[] = {
{ &kJSINSPECTOR_CID, false, NULL, mozilla::jsinspector::nsJSInspectorConstructor },
{ NULL }
};
static const mozilla::Module::ContractIDEntry kJSInspectorContracts[] = {
{ JSINSPECTOR_CONTRACTID, &kJSINSPECTOR_CID },
{ NULL }
};
static const mozilla::Module kJSInspectorModule = {
mozilla::Module::kVersion,
kJSInspectorCIDs,
kJSInspectorContracts
};
NSMODULE_DEFN(jsinspector) = &kJSInspectorModule;

Просмотреть файл

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation <http://www.mozilla.org/>.
* Portions created by the Initial Developer are Copyright (C) 2009-2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef COMPONENTS_JSINSPECTOR_H
#define COMPONENTS_JSINSPECTOR_H
#include "nsIJSInspector.h"
namespace mozilla {
namespace jsinspector {
class nsJSInspector : public nsIJSInspector
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIJSINSPECTOR
nsJSInspector();
private:
~nsJSInspector();
PRUint32 mNestedLoopLevel;
};
}
}
#endif

Просмотреть файл

@ -0,0 +1,428 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is JS Debugger Server code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
/**
* Browser-specific actors.
*/
var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
function createRootActor(aConnection)
{
return new BrowserRootActor(aConnection);
}
/**
* Creates the root actor that client-server communications always start with.
* The root actor is responsible for the initial 'hello' packet and for
* responding to a 'listTabs' request that produces the list of currently open
* tabs.
*
* @param aConnection DebuggerServerConnection
* The conection to the client.
*/
function BrowserRootActor(aConnection)
{
this.conn = aConnection;
this._tabActors = new WeakMap();
this._tabActorPool = null;
this._actorFactories = null;
this.onTabClosed = this.onTabClosed.bind(this);
windowMediator.addListener(this);
}
BrowserRootActor.prototype = {
/**
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
*/
sayHello: function BRA_sayHello() {
return { from: "root",
applicationType: "browser",
traits: [] };
},
/**
* Disconnects the actor from the browser window.
*/
disconnect: function BRA_disconnect() {
windowMediator.removeListener(this);
// We may have registered event listeners on browser windows to
// watch for tab closes, remove those.
let e = windowMediator.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
let win = e.getNext();
this.unwatchWindow(win);
}
},
/**
* Handles the listTabs request. Builds a list of actors
* for the tabs running in the process. The actors will survive
* until at least the next listTabs request.
*/
onListTabs: function BRA_onListTabs() {
// Get actors for all the currently-running tabs (reusing
// existing actors where applicable), and store them in
// an ActorPool.
let actorPool = new ActorPool(this.conn);
let actorList = [];
// Walk over open browser windows.
let e = windowMediator.getEnumerator("navigator:browser");
let selected;
while (e.hasMoreElements()) {
let win = e.getNext();
// Watch the window for tab closes so we can invalidate
// actors as needed.
this.watchWindow(win);
// List the tabs in this browser.
let selectedBrowser = win.getBrowser().selectedBrowser;
let browsers = win.getBrowser().browsers;
for each (let browser in browsers) {
if (browser == selectedBrowser) {
selected = actorList.length;
}
let actor = this._tabActors.get(browser);
if (!actor) {
actor = new BrowserTabActor(this.conn, browser);
actor.parentID = this.actorID;
this._tabActors.set(browser, actor);
}
actorPool.addActor(actor);
actorList.push(actor);
}
}
// Now drop the old actorID -> actor map. Actors that still
// mattered were added to the new map, others will go
// away.
if (this._tabActorPool) {
this.conn.removeActorPool(this._tabActorPool);
}
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
return { "from": "root",
"selected": selected,
"tabs": [actor.grip()
for each (actor in actorList)] };
},
/**
* Watch a window that was visited during onListTabs for
* tab closures.
*/
watchWindow: function BRA_watchWindow(aWindow) {
aWindow.getBrowser().tabContainer.addEventListener("TabClose",
this.onTabClosed,
false);
},
/**
* Stop watching a window for tab closes.
*/
unwatchWindow: function BRA_unwatchWindow(aWindow) {
aWindow.getBrowser().tabContainer.removeEventListener("TabClose",
this.onTabClosed);
this.exitTabActor(aWindow);
},
/**
* When a tab is closed, exit its tab actor. The actor
* will be dropped at the next listTabs request.
*/
onTabClosed: function BRA_onTabClosed(aEvent) {
this.exitTabActor(aEvent.target.linkedBrowser);
},
/**
* Exit the tab actor of the specified tab.
*/
exitTabActor: function BRA_exitTabActor(aWindow) {
let actor = this._tabActors.get(aWindow);
if (actor) {
actor.exit();
}
},
// nsIWindowMediatorListener
onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { },
onOpenWindow: function BRA_onOpenWindow(aWindow) { },
onCloseWindow: function BRA_onCloseWindow(aWindow) {
if (aWindow.getBrowser) {
this.unwatchWindow(aWindow);
}
},
}
/**
* The request types this actor can handle.
*/
BrowserRootActor.prototype.requestTypes = {
"listTabs": BrowserRootActor.prototype.onListTabs
};
/**
* Creates a tab actor for handling requests to a browser tab, like attaching
* and detaching.
*
* @param aConnection DebuggerServerConnection
* The conection to the client.
* @param aBrowser browser
* The browser instance that contains this tab.
*/
function BrowserTabActor(aConnection, aBrowser)
{
this.conn = aConnection;
this._browser = aBrowser;
this._onWindowCreated = this.onWindowCreated.bind(this);
}
// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a
// *complete* mess, needs to be rethought asap.
BrowserTabActor.prototype = {
get browser() { return this._browser; },
get exited() { return !this.browser; },
get attached() { return !!this._attached },
_tabPool: null,
get tabActorPool() { return this._tabPool; },
_contextPool: null,
get contextActorPool() { return this._contextPool; },
actorPrefix: "tab",
grip: function BTA_grip() {
dbg_assert(!this.exited,
"grip() shouldn't be called on exited browser actor.");
dbg_assert(this.actorID,
"tab should have an actorID.");
return { actor: this.actorID,
title: this.browser.contentTitle,
url: this.browser.currentURI.spec }
},
/**
* Called when the actor is removed from the connection.
*/
disconnect: function BTA_disconnect() {
this._detach();
},
/**
* Called by the root actor when the underlying tab is closed.
*/
exit: function BTA_exit() {
if (this.exited) {
return;
}
if (this.attached) {
this._detach();
this.conn.send({ from: this.actorID,
type: "tabDetached" });
}
this._browser = null;
},
/**
* Does the actual work of attching to a tab.
*/
_attach: function BTA_attach() {
if (this._attached) {
return;
}
// Create a pool for tab-lifetime actors.
dbg_assert(!this._tabPool, "Shouldn't have a tab pool if we weren't attached.");
this._tabPool = new ActorPool(this.conn);
this.conn.addActorPool(this._tabPool);
// ... and a pool for context-lifetime actors.
this._pushContext();
// Watch for globals being created in this tab.
this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
this._attached = true;
},
/**
* Creates a thread actor and a pool for context-lifetime actors. It then sets
* up the content window for debugging.
*/
_pushContext: function BTA_pushContext() {
dbg_assert(!this._contextPool, "Can't push multiple contexts");
this._contextPool = new ActorPool(this.conn);
this.conn.addActorPool(this._contextPool);
this.threadActor = new ThreadActor(this);
this.threadActor.addDebuggee(this.browser.contentWindow.wrappedJSObject);
this._contextPool.addActor(this.threadActor);
},
/**
* Exits the current thread actor and removes the context-lifetime actor pool.
* The content window is no longer being debugged after this call.
*/
_popContext: function BTA_popContext() {
dbg_assert(!!this._contextPool, "No context to pop.");
this.conn.removeActorPool(this._contextPool);
this._contextPool = null;
this.threadActor.exit();
this.threadActor = null;
},
/**
* Does the actual work of detaching from a tab.
*/
_detach: function BTA_detach() {
if (!this.attached) {
return;
}
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
this._popContext();
// Shut down actors that belong to this tab's pool.
this.conn.removeActorPool(this._tabPool);
this._tabPool = null;
this._attached = false;
},
// Protocol Request Handlers
onAttach: function BTA_onAttach(aRequest) {
if (this.exited) {
return { type: "exited" };
}
this._attach();
return { type: "tabAttached", threadActor: this.threadActor.actorID };
},
onDetach: function BTA_onDetach(aRequest) {
if (!this.attached) {
return { error: "wrongState" };
}
this._detach();
return { type: "detached" };
},
/**
* Suppresses content-initiated events. Called right before entering the
* nested event loop.
*/
preNest: function BTA_preNest() {
this.browser.contentWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.suppressEventHandling(true);
},
/**
* Re-enables content-initiated events. Called right after exiting the
* nested event loop.
*/
postNest: function BTA_postNest(aNestData) {
this.browser.contentWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.suppressEventHandling(false);
},
/**
* Handle location changes, by sending a tabNavigated notification to the
* client.
*/
onWindowCreated: function BTA_onWindowCreated(evt) {
if (evt.target === this.browser.contentDocument) {
if (this._attached) {
this.conn.send({ from: this.actorID, type: "tabNavigated",
url: this.browser.contentDocument.URL });
}
}
},
};
/**
* The request types this actor can handle.
*/
BrowserTabActor.prototype.requestTypes = {
"attach": BrowserTabActor.prototype.onAttach,
"detach": BrowserTabActor.prototype.onDetach
};
/**
* Registers handlers for new request types defined dynamically. This is used
* for example by add-ons to augment the functionality of the tab actor.
*
* @param aName string
* The name of the new request type.
* @param aFunction function
* The handler for this request type.
*/
DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) {
BrowserTabActor.prototype.requestTypes[aName] = function(aRequest) {
if (!this.attached) {
return { error: "wrongState" };
}
return aFunction(this, aRequest);
}
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,474 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
/**
* Toolkit glue for the remote debugging protocol, loaded into the
* debugging global.
*/
const Ci = Components.interfaces;
const Cc = Components.classes;
const CC = Components.Constructor;
const Cu = Components.utils;
function dumpn(str) {
dump("DBG-SERVER: " + str + "\n");
}
function dbg_assert(cond, e) {
if (!cond) {
return e;
}
}
loadSubScript.call(this, "chrome://global/content/devtools/dbg-transport.js");
// XPCOM constructors
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
"nsIServerSocket",
"init");
/***
* Public API
*/
var DebuggerServer = {
_listener: null,
_transportInitialized: false,
xpcInspector: null,
/**
* Initialize the debugger server.
*/
init: function DH_init() {
if (this.initialized) {
return;
}
Cu.import("resource://gre/modules/jsdebugger.jsm");
this.xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
this.initTransport();
this.addActors("chrome://global/content/devtools/dbg-script-actors.js");
},
/**
* Initialize the debugger server's transport variables. This can be
* in place of init() for cases where the jsdebugger isn't needed.
*/
initTransport: function DH_initTransport() {
if (this._transportInitialized) {
return;
}
this._connections = {};
this._nextConnID = 0;
this._transportInitialized = true;
},
get initialized() { return !!this.xpcInspector; },
/**
* Load a subscript into the debugging global.
*
* @param aURL string A url that will be loaded as a subscript into the
* debugging global. The user must load at least one script
* that implements a createRootActor() function to create the
* server's root actor.
*/
addActors: function DH_addActors(aURL) {
loadSubScript.call(this, aURL);
},
/**
* Install Firefox-specific actors.
*/
addBrowserActors: function DH_addBrowserActors() {
this.addActors("chrome://global/content/devtools/dbg-browser-actors.js");
},
/**
* Listens on the given port for remote debugger connections.
*
* @param aPort int
* The port to listen on.
* @param aLocalOnly bool
* If true, server will listen on the loopback device.
*/
openListener: function DH_openListener(aPort, aLocalOnly) {
this._checkInit();
if (this._listener) {
throw "Debugging listener already open.";
}
try {
let socket = new ServerSocket(aPort, aLocalOnly, 4);
socket.asyncListen(this);
this._listener = socket;
} catch (e) {
dumpn("Could not start debugging listener on port " + aPort + ": " + e);
throw Cr.NS_ERROR_NOT_AVAILABLE;
}
return true;
},
/**
* Close a previously-opened TCP listener.
*/
closeListener: function DH_closeListener() {
this._checkInit();
if (!this._listener) {
return false;
}
this._listener.close();
this._listener = null;
return true;
},
/**
* Creates a new connection to the local debugger speaking over an
* nsIPipe.
*
* @returns a client-side DebuggerTransport for communicating with
* the newly-created connection.
*/
connectPipe: function DH_connectPipe() {
this._checkInit();
let toServer = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
toServer.init(true, true, 0, 0, null);
let toClient = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
toClient.init(true, true, 0, 0, null);
let serverTransport = new DebuggerTransport(toServer.inputStream,
toClient.outputStream);
this._onConnection(serverTransport);
return new DebuggerTransport(toClient.inputStream, toServer.outputStream);
},
// nsIServerSocketListener implementation
onSocketAccepted: function DH_onSocketAccepted(aSocket, aTransport) {
dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port);
try {
let input = aTransport.openInputStream(0, 0, 0);
let output = aTransport.openOutputStream(0, 0, 0);
let transport = new DebuggerTransport(input, output);
DebuggerServer._onConnection(transport);
} catch (e) {
dumpn("Couldn't initialize connection: " + e + " - " + e.stack);
}
},
onStopListening: function DH_onStopListening() { },
/**
* Raises an exception if the server has not been properly initialized.
*/
_checkInit: function DH_checkInit() {
if (!this._transportInitialized) {
throw "DebuggerServer has not been initialized.";
}
if (!this.createRootActor) {
throw "Use DebuggerServer.addActors() to add a root actor implementation.";
}
},
/**
* Create a new debugger connection for the given transport. Called
* after connectPipe() or after an incoming socket connection.
*/
_onConnection: function DH_onConnection(aTransport) {
let connID = "conn" + this._nextConnID++ + '.';
let conn = new DebuggerServerConnection(connID, aTransport);
this._connections[connID] = conn;
// Create a root actor for the connection and send the hello packet.
conn.rootActor = this.createRootActor(conn);
conn.addActor(conn.rootActor);
aTransport.send(conn.rootActor.sayHello());
aTransport.ready();
},
/**
* Remove the connection from the debugging server.
*/
_connectionClosed: function DH_connectionClosed(aConnection) {
delete this._connections[aConnection.prefix];
}
};
/**
* Construct an ActorPool.
*
* ActorPools are actorID -> actor mapping and storage. These are
* used to accumulate and quickly dispose of groups of actors that
* share a lifetime.
*/
function ActorPool(aConnection)
{
this.conn = aConnection;
this._cleanups = {};
this._actors = {};
}
ActorPool.prototype = {
/**
* Add an actor to the actor pool. If the actor doesn't have an ID,
* allocate one from the connection.
*
* @param aActor object
* The actor implementation. If the object has a
* 'disconnected' property, it will be called when the actor
* pool is cleaned up.
*/
addActor: function AP_addActor(aActor) {
aActor.conn = this.conn;
if (!aActor.actorID) {
aActor.actorID = this.conn.allocID(aActor.actorPrefix || undefined);
}
if (aActor.registeredPool) {
aActor.registeredPool.removeActor(aActor);
}
aActor.registeredPool = this;
this._actors[aActor.actorID] = aActor;
if (aActor.disconnect) {
this._cleanups[aActor.actorID] = aActor;
}
},
get: function AP_get(aActorID) {
return this._actors[aActorID];
},
has: function AP_has(aActorID) {
return aActorID in this._actors;
},
/**
* Remove an actor from the actor pool.
*/
removeActor: function AP_remove(aActorID) {
delete this._actors[aActorID];
delete this._cleanups[aActorID];
},
/**
* Run all cleanups previously registered with addCleanup.
*/
cleanup: function AP_cleanup() {
for each (let actor in this._cleanups) {
actor.disconnect();
}
this._cleanups = {};
}
}
/**
* Creates a DebuggerServerConnection.
*
* Represents a connection to this debugging global from a client.
* Manages a set of actors and actor pools, allocates actor ids, and
* handles incoming requests.
*
* @param aPrefix string
* All actor IDs created by this connection should be prefixed
* with aPrefix.
* @param aTransport transport
* Packet transport for the debugging protocol.
*/
function DebuggerServerConnection(aPrefix, aTransport)
{
this._prefix = aPrefix;
this._transport = aTransport;
this._transport.hooks = this;
this._nextID = 1;
this._actorPool = new ActorPool(this);
this._extraPools = [];
}
DebuggerServerConnection.prototype = {
_prefix: null,
get prefix() { return this._prefix },
_transport: null,
get transport() { return this._transport },
send: function DSC_send(aPacket) {
this.transport.send(aPacket);
},
allocID: function DSC_allocID(aPrefix) {
return this.prefix + (aPrefix || '') + this._nextID++;
},
/**
* Add a map of actor IDs to the connection.
*/
addActorPool: function DSC_addActorPool(aActorPool) {
this._extraPools.push(aActorPool);
},
/**
* Remove a previously-added pool of actors to the connection.
*/
removeActorPool: function DSC_removeActorPool(aActorPool) {
let index = this._extraPools.splice(this._extraPools.lastIndexOf(aActorPool), 1);
},
/**
* Add an actor to the default actor pool for this connection.
*/
addActor: function DSC_addActor(aActor) {
this._actorPool.addActor(aActor);
},
/**
* Remove an actor to the default actor pool for this connection.
*/
removeActor: function DSC_removeActor(aActor) {
this._actorPool.removeActor(aActor);
},
/**
* Add a cleanup to the default actor pool for this connection.
*/
addCleanup: function DSC_addCleanup(aCleanup) {
this._actorPool.addCleanup(aCleanup);
},
/**
* Look up an actor implementation for an actorID. Will search
* all the actor pools registered with the connection.
*
* @param aActorID string
* Actor ID to look up.
*/
getActor: function DSC_getActor(aActorID) {
if (this._actorPool.has(aActorID)) {
return this._actorPool.get(aActorID);
}
for each (let pool in this._extraPools) {
if (pool.has(aActorID)) {
return pool.get(aActorID);
}
}
if (aActorID === "root") {
return this.rootActor;
}
return null;
},
// Transport hooks.
/**
* Called by DebuggerTransport to dispatch incoming packets as appropriate.
*
* @param aPacket object
* The incoming packet.
*/
onPacket: function DSC_onPacket(aPacket) {
let actor = this.getActor(aPacket.to);
if (!actor) {
this.transport.send({ from: aPacket.to ? aPacket.to : "root",
error: "noSuchActor" });
return;
}
var ret = null;
// Dispatch the request to the actor.
if (actor.requestTypes && actor.requestTypes[aPacket.type]) {
try {
ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket);
} catch(e) {
dumpn(e);
ret = { error: "unknownError",
message: "An unknown error has occurred while processing request." };
}
} else {
ret = { error: "unrecognizedPacketType",
message: 'Actor "' + actor.actorID + '" does not recognize the packet type "' + aPacket.type + '"' };
}
if (!ret) {
// XXX: The actor wasn't ready to reply yet, don't process new
// requests until it does.
return;
}
if (!ret.from) {
ret.from = aPacket.to;
}
this.transport.send(ret);
},
/**
* Called by DebuggerTransport when the underlying stream is closed.
*
* @param aStatus nsresult
* The status code that corresponds to the reason for closing
* the stream.
*/
onClosed: function DSC_onClosed(aStatus) {
dumpn("Cleaning up connection.");
this._actorPool.cleanup();
this._actorPool = null;
this._extraPools.map(function(p) { p.cleanup(); });
this._extraPools = null;
DebuggerServer._connectionClosed(this);
}
};

Просмотреть файл

@ -0,0 +1,71 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
var EXPORTED_SYMBOLS = ["DebuggerServer"]
function loadSubScript(aURL)
{
try {
let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript(aURL, this);
} catch(e) {
dump("Error loading: " + aURL + ": " + e + " - " + e.stack + "\n");
throw e;
}
}
Cu.import("resource:///modules/devtools/dbg-client.jsm");
// Load the debugging server in a sandbox with its own compartment.
// Note that this is slated for elimination in bug 703718.
var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
.createInstance(Ci.nsIPrincipal);
var gGlobal = Cu.Sandbox(systemPrincipal);
gGlobal.importFunction(loadSubScript);
gGlobal.loadSubScript("chrome://global/content/devtools/dbg-server.js");
var DebuggerServer = gGlobal.DebuggerServer;

Просмотреть файл

@ -0,0 +1,50 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Dave Camp <dcamp@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = toolkit/devtools/debugger/tests
include $(DEPTH)/config/autoconf.mk
MODULE = test_debugger
XPCSHELL_TESTS = unit
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,99 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource:///modules/devtools/dbg-server.jsm");
Cu.import("resource:///modules/devtools/dbg-client.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function check_except(func)
{
try {
func();
} catch (e) {
do_check_true(true);
return;
}
dump("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);
Cu.evalInSandbox("this.__name = '" + aName + "'", sandbox);
return sandbox;
}
function addTestGlobal(aName)
{
let global = testGlobal(aName);
DebuggerServer.addTestGlobal(global);
return global;
}
function getTestGlobalContext(aClient, aName, aCallback) {
aClient.request({ "to": "root", "type": "listContexts" }, function(aResponse) {
for each (let context in aResponse.contexts) {
if (context.global == aName) {
aCallback(context);
return false;
}
}
aCallback(null);
});
}
function attachTestGlobalClient(aClient, aName, aCallback) {
getTestGlobalContext(aClient, aName, function(aContext) {
aClient.attachThread(aContext.actor, aCallback);
});
}
function attachTestGlobalClientAndResume(aClient, aName, aCallback) {
attachTestGlobalClient(aClient, aName, function(aResponse, aThreadClient) {
aThreadClient.resume(function(aResponse) {
aCallback(aResponse, aThreadClient);
});
})
}
/**
* Initialize the testing debugger server.
*/
function initTestDebuggerServer()
{
DebuggerServer.addActors("resource://test/testactors.js");
DebuggerServer.init();
}
function finishClient(aClient)
{
aClient.close(function() {
do_test_finished();
});
}
/**
* Returns the full path of the file with the specified name in a
* platform-independent and URL-like form.
*/
function getFilePath(aName)
{
let file = do_get_file(aName);
let path = Services.io.newFileURI(file).spec;
let filePrePath = "file://";
if ("nsILocalFileWin" in Ci &&
file instanceof Ci.nsILocalFileWin) {
filePrePath += "/";
}
return path.slice(filePrePath.length);
}

Просмотреть файл

@ -0,0 +1,42 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var gClient;
var gDebuggee;
function run_test()
{
DebuggerServer.addActors("resource://test/testactors.js");
DebuggerServer.init();
gDebuggee = testGlobal("test-1");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
getTestGlobalContext(gClient, "test-1", function(aContext) {
test_attach(aContext);
});
});
do_test_pending();
}
function test_attach(aContext)
{
gClient.attachThread(aContext.actor, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused");
aThreadClient.resume(function() {
cleanup();
});
});
}
function cleanup()
{
gClient.addListener("closed", function(aEvent) {
do_test_finished();
});
gClient.close();
}

Просмотреть файл

@ -0,0 +1,60 @@
/* 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;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function () {
attachTestGlobalClientAndResume(gClient, "test-stack", function (aResponse, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_breakpoint();
});
});
do_test_pending();
}
function test_simple_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-01.js');
gThreadClient.setBreakpoint({ url: path, line: gDebuggee.line0 + 3}, function (aResponse, bpClient) {
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, 1);
do_check_eq(gDebuggee.b, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume(function () {
});
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"var b = 2;\n"); // line0 + 3
}

Просмотреть файл

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/devtools/dbg-server.jsm");
Cu.import("resource:///modules/devtools/dbg-client.jsm");
var gClient;
var gDebuggee;
function run_test()
{
DebuggerServer.addActors("resource://test/testactors.js");
DebuggerServer.init();
gDebuggee = testGlobal("test-1");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.addListener("connected", function(aEvent, aType, aTraits) {
gClient.request({ to: "root", type: "listContexts" }, function(aResponse) {
do_check_true('contexts' in aResponse);
for each (let context in aResponse.contexts) {
if (context.global == "test-1") {
test_attach(context);
return false;
}
}
do_check_true(false);
});
});
gClient.connect();
do_test_pending();
}
function test_attach(aContext)
{
gClient.request({ to: aContext.actor, type: "attach" }, function(aResponse) {
do_check_eq(aResponse.type, "paused");
// Resume the thread and test the debugger statement.
gClient.request({ to: aContext.actor, type: "resume" }, function() {
test_debugger_statement(aContext);
});
});
}
function test_debugger_statement(aContext)
{
gClient.addListener("paused", function(aName, aPacket) {
// 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);
gClient.request({ to: aContext.actor, type: "resume" }, function() {
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, 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();
}

Просмотреть файл

@ -0,0 +1,77 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/devtools/dbg-server.jsm");
Cu.import("resource:///modules/devtools/dbg-client.jsm");
var gClient;
var gDebuggee;
function run_test()
{
DebuggerServer.addActors("resource://test/testactors.js");
DebuggerServer.init();
gDebuggee = testGlobal("test-1");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
getTestGlobalContext(gClient, "test-1", function(aContext) {
test_attach(aContext);
});
});
do_test_pending();
}
function test_attach(aContext)
{
gClient.attachThread(aContext.actor, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused");
do_check_eq(aThreadClient.actor, aContext.actor);
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(function() {
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();
}

Просмотреть файл

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/devtools/dbg-server.jsm");
Cu.import("resource:///modules/devtools/dbg-client.jsm");
function run_test()
{
// Should get an exception if we try to interact with DebuggerServer
// before we initialize it...
check_except(function() {
DebuggerServer.openListener(2929, true);
});
check_except(DebuggerServer.closeListener);
check_except(DebuggerServer.connectPipe);
DebuggerServer.init();
// These should still fail because we haven't added a createRootActor
// implementation yet.
check_except(function() {
DebuggerServer.openListener(2929, true);
});
check_except(DebuggerServer.closeListener);
check_except(DebuggerServer.connectPipe);
DebuggerServer.addActors("resource://test/testactors.js");
// Now they should work.
DebuggerServer.openListener(2929, true);
DebuggerServer.closeListener();
// 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();
}

Просмотреть файл

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/devtools/dbg-server.jsm");
Cu.import("resource:///modules/devtools/dbg-client.jsm");
function run_test()
{
DebuggerServer.init();
DebuggerServer.addActors("resource://test/testactors.js");
add_test(test_socket_conn);
add_test(test_socket_shutdown);
add_test(test_pipe_conn);
run_next_test();
}
function really_long() {
let ret = "0123456789";
for (let i = 0; i < 18; i++) {
ret += ret;
}
return ret;
}
function test_socket_conn()
{
DebuggerServer.openListener(2929, true);
let transport = debuggerSocketConnect("127.0.0.1", 2929);
transport.hooks = {
onPacket: function(aPacket) {
this.onPacket = function(aPacket) {
transport.close();
}
// Verify that things work correctly when bigger than the output
// transport buffers...
transport.send({to: "root",
type: "echo",
reallylong: really_long()});
do_check_eq(aPacket.from, "root");
},
onClosed: function(aStatus) {
run_next_test();
},
};
transport.ready();
}
function test_socket_shutdown()
{
DebuggerServer.closeListener();
let transport = debuggerSocketConnect("127.0.0.1", 2929);
transport.hooks = {
onPacket: function(aPacket) {
// Shouldn't reach this, should never connect.
do_check_true(false);
},
onClosed: function(aStatus) {
do_check_eq(aStatus, Cr.NS_ERROR_CONNECTION_REFUSED);
run_next_test();
}
};
transport.ready();
}
function test_pipe_conn()
{
let transport = DebuggerServer.connectPipe();
transport.hooks = {
onPacket: function(aPacket) {
do_check_eq(aPacket.from, "root");
transport.close();
},
onClosed: function(aStatus) {
run_next_test();
}
};
transport.ready();
}

Просмотреть файл

@ -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(function() {
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, 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.value.type, "object");
do_check_eq(aPacket.why.value["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});
} + ")()");
}

Просмотреть файл

@ -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(function() {
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, 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.exception, "failure");
gThreadClient.resume(function() {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("(" + function() {
function stopMe(arg1) { debugger; };
stopMe({obj: true});
} + ")()");
}

Просмотреть файл

@ -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(function() {
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, 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.exception.type, "object");
do_check_eq(aPacket.why.exception["class"], "Error");
gThreadClient.resume(function() {
finishClient(gClient);
});
});
});
});
gDebuggee.eval("(" + function() {
function stopMe(arg1) { debugger; };
stopMe({obj: true});
} + ")()");
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше