This commit is contained in:
Tim Taubert 2012-02-10 14:26:49 +01:00
Родитель 8fa7a50766 166a54fce4
Коммит 07f0680ff2
37 изменённых файлов: 1445 добавлений и 130 удалений

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

@ -77,10 +77,8 @@ let gBrowserThumbnails = {
},
_capture: function Thumbnails_capture(aBrowser) {
if (this._shouldCapture(aBrowser)) {
let canvas = this._pageThumbs.capture(aBrowser.contentWindow);
this._pageThumbs.store(aBrowser.currentURI.spec, canvas);
}
if (this._shouldCapture(aBrowser))
this._pageThumbs.captureAndStore(aBrowser);
},
_delayedCapture: function Thumbnails_delayedCapture(aBrowser) {

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

@ -1228,12 +1228,12 @@ function BrowserStartup() {
if ("arguments" in window && window.arguments[0])
uriToLoad = window.arguments[0];
var isLoadingBlank = uriToLoad == "about:blank";
var isLoadingBlank = isBlankPageURL(uriToLoad);
var mustLoadSidebar = false;
prepareForStartup();
if (uriToLoad && !isLoadingBlank) {
if (uriToLoad && uriToLoad != "about:blank") {
if (uriToLoad instanceof Ci.nsISupportsArray) {
let count = uriToLoad.Count();
let specs = [];

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

@ -72,11 +72,13 @@ let PageThumbs = {
},
/**
* Creates a canvas containing a thumbnail depicting the given window.
* Captures a thumbnail for the given window.
* @param aWindow The DOM window to capture a thumbnail from.
* @return The newly created canvas containing the image data.
* @param aCallback The function to be called when the thumbnail has been
* captured. The first argument will be the data stream
* containing the image data.
*/
capture: function PageThumbs_capture(aWindow) {
capture: function PageThumbs_capture(aWindow, aCallback) {
let telemetryCaptureTime = new Date();
let [sw, sh, scale] = this._determineCropSize(aWindow);
@ -94,48 +96,43 @@ let PageThumbs = {
// We couldn't draw to the canvas for some reason.
}
Services.telemetry.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
let telemetry = Services.telemetry;
telemetry.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
.add(new Date() - telemetryCaptureTime);
return canvas;
canvas.mozFetchAsStream(aCallback, this.contentType);
},
/**
* Stores the image data contained in the given canvas to the underlying
* storage.
* @param aKey The key to use for the storage.
* @param aCanvas The canvas containing the thumbnail's image data.
* @param aCallback The function to be called when the canvas data has been
* stored (optional).
* Captures a thumbnail for the given browser and stores it to the cache.
* @param aBrowser The browser to capture a thumbnail for.
* @param aCallback The function to be called when finished (optional).
*/
store: function PageThumbs_store(aKey, aCanvas, aCallback) {
let telemetryStoreTime = new Date();
captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
this.capture(aBrowser.contentWindow, function (aInputStream) {
let telemetryStoreTime = new Date();
function finish(aSuccessful) {
if (aSuccessful) {
Services.telemetry.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS")
.add(new Date() - telemetryStoreTime);
function finish(aSuccessful) {
if (aSuccessful) {
Services.telemetry.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS")
.add(new Date() - telemetryStoreTime);
}
if (aCallback)
aCallback(aSuccessful);
}
if (aCallback)
aCallback(aSuccessful);
}
// Get a writeable cache entry.
PageThumbsCache.getWriteEntry(aBrowser.currentURI.spec, function (aEntry) {
if (!aEntry) {
finish(false);
return;
}
let self = this;
// Get a writeable cache entry.
PageThumbsCache.getWriteEntry(aKey, function (aEntry) {
if (!aEntry) {
finish(false);
return;
}
// Extract image data from the canvas.
self._readImageData(aCanvas, function (aData) {
let outputStream = aEntry.openOutputStream(0);
// Write the image data to the cache entry.
NetUtil.asyncCopy(aData, outputStream, function (aResult) {
NetUtil.asyncCopy(aInputStream, outputStream, function (aResult) {
let success = Components.isSuccessCode(aResult);
if (success)
aEntry.markValid();
@ -147,21 +144,6 @@ let PageThumbs = {
});
},
/**
* Reads the image data from a given canvas and passes it to the callback.
* @param aCanvas The canvas to read the image data from.
* @param aCallback The function that the image data is passed to.
*/
_readImageData: function PageThumbs_readImageData(aCanvas, aCallback) {
let dataUri = aCanvas.toDataURL(PageThumbs.contentType, "");
let uri = Services.io.newURI(dataUri, "UTF8", null);
NetUtil.asyncFetch(uri, function (aData, aResult) {
if (Components.isSuccessCode(aResult) && aData && aData.available())
aCallback(aData);
});
},
/**
* Determines the crop size for a given content window.
* @param aWindow The content window.

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

@ -94,15 +94,12 @@ function whenLoaded(aElement, aCallback) {
* @param aMessage The info message to print when comparing the pixel color.
*/
function captureAndCheckColor(aRed, aGreen, aBlue, aMessage) {
let window = gBrowser.selectedTab.linkedBrowser.contentWindow;
let browser = gBrowser.selectedBrowser;
let key = Date.now();
let data = PageThumbs.capture(window);
// Store the thumbnail in the cache.
PageThumbs.store(key, data, function () {
// Capture the screenshot.
PageThumbs.captureAndStore(browser, function () {
let width = 100, height = 100;
let thumb = PageThumbs.getThumbnailURL(key, width, height);
let thumb = PageThumbs.getThumbnailURL(browser.currentURI.spec, width, height);
getXULDocument(function (aDocument) {
let htmlns = "http://www.w3.org/1999/xhtml";

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

@ -93,16 +93,16 @@ DebuggerView.Stackframes = {
let resume = document.getElementById("resume");
let status = document.getElementById("status");
// if we're paused, show a pause label and disable the resume button
// If we're paused, show a pause label and a resume label on the button.
if (aState === "paused") {
status.textContent = DebuggerView.getStr("pausedState");
resume.disabled = false;
resume.label = DebuggerView.getStr("resumeLabel");
} else if (aState === "attached") {
// if we're attached, do the opposite
// If we're attached, do the opposite.
status.textContent = DebuggerView.getStr("runningState");
resume.disabled = true;
resume.label = DebuggerView.getStr("pauseLabel");
} else {
// no valid state parameter
// No valid state parameter.
status.textContent = "";
}
},
@ -272,10 +272,14 @@ DebuggerView.Stackframes = {
},
/**
* Listener handling the resume button click event.
* Listener handling the pause/resume button click event.
*/
_onResumeButtonClick: function DVF__onResumeButtonClick() {
ThreadState.activeThread.resume();
if (ThreadState.activeThread.paused) {
ThreadState.activeThread.resume();
} else {
ThreadState.activeThread.interrupt();
}
},
/**
@ -1092,6 +1096,17 @@ DebuggerView.Scripts = {
return script;
},
/**
* Returns the list of URIs for scripts in the page.
*/
scriptLocations: function DVS_scriptLocations() {
let locations = [];
for (let i = 0; i < this._scripts.itemCount; i++) {
locations.push(this._scripts.getItemAtIndex(i).value);
}
return locations;
},
/**
* The cached click listener for the scripts container.
*/

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

@ -53,7 +53,7 @@
<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:button id="resume"/>
<xul:menulist id="scripts"/>
</xul:toolbar>
<div id="dbg-content" class="hbox flex">

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

@ -69,6 +69,7 @@ _BROWSER_TEST_FILES = \
browser_dbg_stack-04.js \
browser_dbg_location-changes.js \
browser_dbg_script-switching.js \
browser_dbg_pause-resume.js \
head.js \
$(NULL)

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

@ -0,0 +1,74 @@
/* 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;
testPause();
});
}
function testPause() {
is(gDebugger.StackFrames.activeThread.paused, false,
"Should be running after debug_tab_pane.");
let button = gDebugger.document.getElementById("resume");
is(button.label, gDebugger.DebuggerView.getStr("pauseLabel"),
"Button label should be pause when running.");
gPane.activeThread.addOneTimeListener("paused", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.Stackframes._frames;
let childNodes = frames.childNodes;
is(gDebugger.StackFrames.activeThread.paused, true,
"Should be paused after an interrupt request.");
is(button.label, gDebugger.DebuggerView.getStr("resumeLabel"),
"Button label should be resume when paused.");
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames when paused in the main loop.");
testResume();
}}, 0);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.getElementById("resume"),
gDebugger);
}
function testResume() {
gPane.activeThread.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: function() {
is(gDebugger.StackFrames.activeThread.paused, false,
"Should be paused after an interrupt request.");
let button = gDebugger.document.getElementById("resume");
is(button.label, gDebugger.DebuggerView.getStr("pauseLabel"),
"Button label should be pause when running.");
removeTab(gTab);
finish();
}}, 0);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.getElementById("resume"),
gDebugger);
}

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

@ -55,8 +55,10 @@ function testFrameParameters()
localNodes[1].expand();
// Poll every few milliseconds until the properties are retrieved.
// It's important to set the timer in the chrome window, because the
// content window timers are disabled while the debuggee is paused.
let count = 0;
let intervalID = content.setInterval(function(){
let intervalID = window.setInterval(function(){
if (++count > 50) {
ok(false, "Timed out while polling for the properties.");
resumeAndFinish();
@ -64,7 +66,7 @@ function testFrameParameters()
if (!localNodes[0].fetched || !localNodes[1].fetched) {
return;
}
content.clearInterval(intervalID);
window.clearInterval(intervalID);
is(localNodes[0].querySelector(".property > .title > .key")
.textContent, "__proto__ ",
"Should have the right property name for __proto__.");

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

@ -22,6 +22,7 @@
* Contributor(s):
* Mihai Sucan <mihai.sucan@gmail.com> (original author)
* Kenny Heaton <kennyheaton@gmail.com>
* Spyros Livathinos <livathinos.spyros@gmail.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
@ -75,6 +76,8 @@ const ORION_EVENTS = {
ContextMenu: "ContextMenu",
TextChanged: "ModelChanged",
Selection: "Selection",
Focus: "Focus",
Blur: "Blur",
};
/**

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

@ -21,6 +21,7 @@
*
* Contributor(s):
* Mihai Sucan <mihai.sucan@gmail.com> (original author)
* Spyros Livathinos <livathinos.spyros@gmail.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
@ -150,6 +151,16 @@ SourceEditor.EVENTS = {
* Both ranges are objects which hold two properties: start and end.
*/
SELECTION: "Selection",
/**
* The focus event is fired when the editor is focused.
*/
FOCUS: "Focus",
/**
* The blur event is fired when the editor goes out of focus.
*/
BLUR: "Blur",
};
/**

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

@ -54,6 +54,7 @@ _BROWSER_TEST_FILES = \
browser_bug695035_middle_click_paste.js \
browser_bug687160_line_api.js \
browser_bug650345_find.js \
browser_bug703692_focus_blur.js \
head.js \
libs:: $(_BROWSER_TEST_FILES)

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

@ -0,0 +1,71 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let tempScope = {};
Cu.import("resource:///modules/source-editor.jsm", tempScope);
let SourceEditor = tempScope.SourceEditor;
let testWin;
let editor;
function test()
{
waitForExplicitFinish();
const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
"<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
" title='Test for bug 703692' width='600' height='500'><hbox flex='1'/></window>";
const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
testWin.addEventListener("load", function onWindowLoad() {
testWin.removeEventListener("load", onWindowLoad, false);
waitForFocus(initEditor, testWin);
}, false);
}
function initEditor()
{
let hbox = testWin.document.querySelector("hbox");
editor = new SourceEditor();
editor.init(hbox, {}, editorLoaded);
}
function editorLoaded()
{
let focusHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.FOCUS, focusHandler);
editor.addEventListener(SourceEditor.EVENTS.BLUR, blurHandler);
ok(aEvent, "Focus event fired");
window.focus();
};
let blurHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.BLUR, blurHandler);
ok(aEvent, "Blur event fired");
executeSoon(testEnd);
}
editor.addEventListener(SourceEditor.EVENTS.FOCUS, focusHandler);
editor.focus();
}
function testEnd()
{
if (editor) {
editor.destroy();
}
if (testWin) {
testWin.close();
}
testWin = editor = null;
waitForFocus(finish, window);
}

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

@ -125,3 +125,139 @@ gcli.addCommand({
document.defaultView.InspectorUI.openInspectorUI(args.node);
}
});
let breakpoints = [];
/**
* 'break' command
*/
gcli.addCommand({
name: "break",
description: gcli.lookup("breakDesc"),
manual: gcli.lookup("breakManual")
});
/**
* 'break list' command
*/
gcli.addCommand({
name: "break list",
description: gcli.lookup("breaklistDesc"),
returnType: "html",
exec: function(args, context) {
if (breakpoints.length === 0) {
return gcli.lookup("breaklistNone");
}
let reply = gcli.lookup("breaklistIntro");
reply += "<ol>";
breakpoints.forEach(function(breakpoint) {
let text = gcli.lookupFormat("breaklistLineEntry",
[breakpoint.file, breakpoint.line]);
reply += "<li>" + text + "</li>";
});
reply += "</ol>";
return reply;
}
});
/**
* 'break add' command
*/
gcli.addCommand({
name: "break add",
description: gcli.lookup("breakaddDesc"),
manual: gcli.lookup("breakaddManual")
});
/**
* 'break add line' command
*/
gcli.addCommand({
name: "break add line",
description: gcli.lookup("breakaddlineDesc"),
params: [
{
name: "file",
type: {
name: "selection",
data: function() {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let files = [];
if (dbg) {
let scriptsView = dbg.frame.contentWindow.DebuggerView.Scripts;
for each (let script in scriptsView.scriptLocations()) {
files.push(script);
}
}
return files;
}
},
description: gcli.lookup("breakaddlineFileDesc")
},
{
name: "line",
type: { name: "number", min: 1, step: 10 },
description: gcli.lookup("breakaddlineLineDesc")
}
],
returnType: "html",
exec: function(args, context) {
args.type = "line";
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
var promise = context.createPromise();
let position = { url: args.file, line: args.line };
dbg.activeThread.setBreakpoint(position, function(aResponse, aBpClient) {
if (aResponse.error) {
promise.resolve(gcli.lookupFormat("breakaddFailed",
[ aResponse.error ]));
return;
}
args.client = aBpClient;
breakpoints.push(args);
promise.resolve(gcli.lookup("breakaddAdded"));
});
return promise;
}
});
/**
* 'break del' command
*/
gcli.addCommand({
name: "break del",
description: gcli.lookup("breakdelDesc"),
params: [
{
name: "breakid",
type: {
name: "number",
min: 0,
max: function() { return breakpoints.length - 1; }
},
description: gcli.lookup("breakdelBreakidDesc")
}
],
returnType: "html",
exec: function(args, context) {
let breakpoint = breakpoints.splice(args.breakid, 1)[0];
var promise = context.createPromise();
try {
breakpoint.client.remove(function(aResponse) {
promise.resolve(gcli.lookup("breakdelRemoved"));
});
} catch (ex) {
// If the debugger has been closed already, don't scare the user.
promise.resolve(gcli.lookup("breakdelRemoved"));
}
return promise;
}
});

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

@ -154,6 +154,7 @@ _BROWSER_TEST_FILES = \
browser_webconsole_bug_622303_persistent_filters.js \
browser_webconsole_window_zombie.js \
browser_cached_messages.js \
browser_gcli_break.js \
head.js \
$(NULL)
@ -228,6 +229,7 @@ _BROWSER_TEST_PAGES = \
test-bug-658368-time-methods.html \
test-webconsole-error-observer.html \
test-for-of.html \
browser_gcli_break.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

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

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Browser GCLI break command test</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
function firstCall() {
eval("window.line0 = Error().lineNumber; secondCall();");
}
function secondCall() {
eval("debugger;");
}
</script>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,104 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// For more information on GCLI see:
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
// - https://wiki.mozilla.org/DevTools/Features/GCLI
// Tests that the break command works as it should
let tempScope = {};
Components.utils.import("resource:///modules/gcli.jsm", tempScope);
let gcli = tempScope.gcli;
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser_gcli_break.html";
registerCleanupFunction(function() {
gcliterm = undefined;
requisition = undefined;
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", true);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", onLoad, false);
}
let gcliterm;
let requisition;
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
try {
openConsole();
let hud = HUDService.getHudByWindow(content);
gcliterm = hud.gcliterm;
requisition = gcliterm.opts.requisition;
testSetup();
testCreateCommands();
}
catch (ex) {
ok(false, "Caught exception: " + ex)
gcli._internal.console.error("Test Failure", ex);
closeConsole();
finishTest();
}
}
function testSetup() {
ok(gcliterm, "We have a GCLI term");
ok(requisition, "We have a Requisition");
}
function testCreateCommands() {
type("brea");
is(gcliterm.completeNode.textContent, " break", "Completion for 'brea'");
is(requisition.getStatus().toString(), "ERROR", "brea is ERROR");
type("break");
is(requisition.getStatus().toString(), "ERROR", "break is ERROR");
type("break add");
is(requisition.getStatus().toString(), "ERROR", "break add is ERROR");
type("break add line");
is(requisition.getStatus().toString(), "ERROR", "break add line is ERROR");
let pane = DebuggerUI.toggleDebugger();
pane.onConnected = function test_onConnected(aPane) {
// Wait for the initial resume.
aPane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
delete aPane.onConnected;
aPane.debuggerWindow.gClient.activeThread.addOneTimeListener("scriptsadded", function() {
type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0);
is(requisition.getStatus().toString(), "VALID", "break add line is VALID");
requisition.exec();
type("break list");
is(requisition.getStatus().toString(), "VALID", "break list is VALID");
requisition.exec();
aPane.debuggerWindow.gClient.activeThread.resume(function() {
type("break del 0");
is(requisition.getStatus().toString(), "VALID", "break del 0 is VALID");
requisition.exec();
closeConsole();
finishTest();
});
});
// Trigger newScript notifications using eval.
content.wrappedJSObject.firstCall();
});
}
}
function type(command) {
gcliterm.inputNode.value = command.slice(0, -1);
gcliterm.inputNode.focus();
EventUtils.synthesizeKey(command.slice(-1), {});
}

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

@ -19,12 +19,6 @@
- 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">

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

@ -6,6 +6,14 @@
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (pauseLabel): The label that is displayed on the pause
# button when the debugger is in a running state.
pauseLabel=Pause
# LOCALIZATION NOTE (resumeLabel): The label that is displayed on the pause
# button when the debugger is in a paused state.
resumeLabel=Resume
# LOCALIZATION NOTE (pausedState): The label that is displayed when the
# debugger is in a paused state.
pausedState=Paused

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

@ -56,6 +56,75 @@ inspectNodeDesc=CSS selector
# on what it does.
inspectNodeManual=A CSS selector for use with Document.querySelector which identifies a single element
# LOCALIZATION NOTE (breakDesc) A very short string used to describe the
# function of the break command.
breakDesc=Manage breakpoints
# LOCALIZATION NOTE (breakManual) A longer description describing the
# set of commands that control breakpoints.
breakManual=Commands to list, add and remove breakpoints
# LOCALIZATION NOTE (breaklistDesc) A very short string used to describe the
# function of the 'break list' command.
breaklistDesc=Display known breakpoints
# LOCALIZATION NOTE (breaklistLineEntry) Used in the output of the 'break list'
# command to display a single line breakpoint.
# %1$S=script URL, %2$S=line number
breaklistLineEntry=Line breakpoint at %1$S:%2$S
# LOCALIZATION NOTE (breaklistNone) Used in the output of the 'break list'
# command to explain that the list is empty.
breaklistNone=No breakpoints set
# LOCALIZATION NOTE (breaklistIntro) Used in the output of the 'break list'
# command to preface the list contents.
breaklistIntro=The following breakpoints are set:
# LOCALIZATION NOTE (breakaddAdded) Used in the output of the 'break add'
# command to explain that a breakpoint was added.
breakaddAdded=Added breakpoint
# LOCALIZATION NOTE (breakaddFailed) Used in the output of the 'break add'
# command to explain that a breakpoint could not be added.
breakaddFailed=Could not set breakpoint: %S
# LOCALIZATION NOTE (breakaddDesc) A very short string used to describe the
# function of the 'break add' command.
breakaddDesc=Add a breakpoint
# LOCALIZATION NOTE (breakaddManual) A longer description describing the
# set of commands that are responsible for adding breakpoints.
breakaddManual=Breakpoint types supported: line
# LOCALIZATION NOTE (breakaddDebuggerStopped) Used in the output of the
# 'break add' command to explain that the debugger must be opened first.
breakaddDebuggerStopped=The debugger must be opened before setting breakpoints
# LOCALIZATION NOTE (breakaddlineDesc) A very short string used to describe the
# function of the 'break add line' command.
breakaddlineDesc=Add a line breakpoint
# LOCALIZATION NOTE (breakaddlineFileDesc) A very short string used to describe
# the function of the file parameter in the 'break add line' command.
breakaddlineFileDesc=JS file URI
# LOCALIZATION NOTE (breakaddlineLineDesc) A very short string used to describe
# the function of the line parameter in the 'break add line' command.
breakaddlineLineDesc=Line number
# LOCALIZATION NOTE (breakdelDesc) A very short string used to describe the
# function of the 'break del' command.
breakdelDesc=Remove a breakpoint
# LOCALIZATION NOTE (breakdelBreakidDesc) A very short string used to describe
# the function of the index parameter in the 'break del' command.
breakdelBreakidDesc=Index of breakpoint
# LOCALIZATION NOTE (breakdelRemoved) Used in the output of the 'break del'
# command to explain that a breakpoint was removed.
breakdelRemoved=Breakpoint removed
# LOCALIZATION NOTE (consolecloseDesc) A very short description of the
# 'console close' command. This string is designed to be shown in a menu
# alongside the command name, which is why it should be as short as possible.

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

@ -172,7 +172,7 @@ PrivateBrowsingStorage.prototype = {
* Clears the storage and removes all values.
*/
clear: function PrivateBrowsingStorage_clear() {
this._data.listkeys().forEach(function (akey) {
this._data.listkeys().forEach(function (aKey) {
this._data.del(aKey);
}, this);
}

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

@ -194,6 +194,16 @@ const ThreadStateTypes = {
"detached": "detached"
};
/**
* Set of protocol messages that are sent by the server without a prior request
* by the client.
*/
const UnsolicitedNotifications = {
"newScript": "newScript",
"tabDetached": "tabDetached",
"tabNavigated": "tabNavigated"
};
/**
* Set of debug protocol request types that specify the protocol request being
* sent to the server.
@ -204,6 +214,7 @@ const DebugProtocolTypes = {
"delete": "delete",
"detach": "detach",
"frames": "frames",
"interrupt": "interrupt",
"listTabs": "listTabs",
"nameAndParameters": "nameAndParameters",
"ownPropertyNames": "ownPropertyNames",
@ -408,12 +419,15 @@ DebuggerClient.prototype = {
try {
if (!aPacket.from) {
dumpn("Server did not specify an actor, dropping packet: " + JSON.stringify(aPacket));
Cu.reportError("Server did not specify an actor, dropping packet: " +
JSON.stringify(aPacket));
return;
}
let onResponse;
if (aPacket.from in this._activeRequests) {
// Don't count unsolicited notifications as responses.
if (aPacket.from in this._activeRequests &&
!(aPacket.type in UnsolicitedNotifications)) {
onResponse = this._activeRequests[aPacket.from].onResponse;
delete this._activeRequests[aPacket.from];
}
@ -509,12 +523,13 @@ function ThreadClient(aClient, aActor) {
ThreadClient.prototype = {
_state: "paused",
get state() { return this._state; },
get paused() { return this._state === "paused"; },
_actor: null,
get actor() { return this._actor; },
_assertPaused: function TC_assertPaused(aCommand) {
if (this._state !== "paused") {
if (!this.paused) {
throw aCommand + " command sent while not paused.";
}
},
@ -545,6 +560,21 @@ ThreadClient.prototype = {
});
},
/**
* Interrupt a running thread.
*
* @param function aOnResponse
* Called with the response packet.
*/
interrupt: function TC_interrupt(aOnResponse) {
let packet = { to: this._actor, type: DebugProtocolTypes.interrupt };
this._client.request(packet, function(aResponse) {
if (aOnResponse) {
aOnResponse(aResponse);
}
});
},
/**
* Send a clientEvaluate packet to the debuggee. Response
* will be a resume packet.
@ -595,24 +625,49 @@ ThreadClient.prototype = {
* Request to set a breakpoint in the specified location.
*
* @param aLocation object
* The source location object where the breakpoint
* will be set.
* 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");
// A helper function that sets the breakpoint.
let doSetBreakpoint = function _doSetBreakpoint(aCallback) {
let packet = { to: this._actor, type: DebugProtocolTypes.setBreakpoint,
location: aLocation };
this._client.request(packet, function (aResponse) {
if (aOnResponse) {
if (aResponse.error) {
if (aCallback) {
aCallback(aOnResponse.bind(undefined, aResponse));
} else {
aOnResponse(aResponse);
}
return;
}
let bpClient = new BreakpointClient(this._client, aResponse.actor);
if (aCallback) {
aCallback(aOnResponse(aResponse, bpClient));
} else {
aOnResponse(aResponse, bpClient);
}
}
}.bind(this));
}.bind(this);
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);
}
});
// If the debuggee is paused, just set the breakpoint.
if (this.paused) {
doSetBreakpoint();
return;
}
// Otherwise, force a pause in order to set the breakpoint.
this.interrupt(function(aResponse) {
if (aResponse.error) {
// Can't set the breakpoint if pausing failed.
aOnResponse(aResponse);
return;
}
doSetBreakpoint(this.resume.bind(this));
}.bind(this));
},
/**
@ -696,8 +751,7 @@ ThreadClient.prototype = {
* true if there are more stack frames available on the server.
*/
get moreFrames() {
return this.state === "paused"
&& (!this._frameCache || this._frameCache.length == 0
return this.paused && (!this._frameCache || this._frameCache.length == 0
|| !this._frameCache[this._frameCache.length - 1].oldest);
},

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

@ -365,25 +365,25 @@ BrowserTabActor.prototype = {
},
/**
* Suppresses content-initiated events. Called right before entering the
* nested event loop.
* Prepare to enter a nested event loop by disabling debuggee events.
*/
preNest: function BTA_preNest() {
this.browser.contentWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.suppressEventHandling(true);
let windowUtils = this.browser.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.suppressEventHandling(true);
windowUtils.suspendTimeouts();
},
/**
* Re-enables content-initiated events. Called right after exiting the
* nested event loop.
* Prepare to exit a nested event loop by enabling debuggee events.
*/
postNest: function BTA_postNest(aNestData) {
this.browser.contentWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.suppressEventHandling(false);
let windowUtils = this.browser.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.resumeTimeouts();
windowUtils.suppressEventHandling(false);
},
/**

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

@ -49,8 +49,8 @@
* of debuggees.
*
* @param aHooks object
* An object with preNest and postNest methods that can be called when
* entering and exiting a nested event loop.
* An object with preNest and postNest methods for calling when entering
* and exiting a nested event loop.
*/
function ThreadActor(aHooks)
{
@ -176,7 +176,7 @@ ThreadActor.prototype = {
// now.
return null;
} catch(e) {
dumpn(e);
Cu.reportError(e);
return { error: "notAttached", message: e.toString() };
}
},
@ -286,10 +286,8 @@ ThreadActor.prototype = {
}
let location = aRequest.location;
// TODO: deal with actualLocation being different from the provided location
if (!this._scripts[location.url] || location.line < 0) {
return { from: this.actorID,
error: "noScript" };
return { error: "noScript" };
}
// Fetch the list of scripts in that url.
let scripts = this._scripts[location.url];
@ -307,19 +305,69 @@ ThreadActor.prototype = {
break;
}
}
if (!script) {
return { from: this.actorID,
error: "noScript" };
return { error: "noScript" };
}
script = this._getInnermostContainer(script, location.line);
let bpActor = new BreakpointActor(script, this);
this.breakpointActorPool.addActor(bpActor);
var offsets = script.getLineOffsets(location.line);
for (var i = 0; i < offsets.length; i++) {
let offsets = script.getLineOffsets(location.line);
let codeFound = false;
for (let i = 0; i < offsets.length; i++) {
script.setBreakpoint(offsets[i], bpActor);
codeFound = true;
}
let packet = { from: this.actorID,
actor: bpActor.actorID };
return packet;
let actualLocation;
if (offsets.length == 0) {
// No code at that line in any script, skipping forward.
let lines = script.getAllOffsets();
for (let line = location.line; line < lines.length; ++line) {
if (lines[line]) {
for (let i = 0; i < lines[line].length; i++) {
script.setBreakpoint(lines[line][i], bpActor);
codeFound = true;
}
actualLocation = location;
actualLocation.line = line;
break;
}
}
}
if (!codeFound) {
bpActor.onDelete();
return { error: "noCodeAtLineColumn" };
}
return { actor: bpActor.actorID, actualLocation: actualLocation };
},
/**
* Get the innermost script that contains this line, by looking through child
* scripts of the supplied script.
*
* @param aScript Debugger.Script
* The source script.
* @param aLine number
* The line number.
*/
_getInnermostContainer: function TA__getInnermostContainer(aScript, aLine) {
let children = aScript.getChildScripts();
if (children.length > 0) {
for (let i = 0; i < children.length; i++) {
let child = children[i];
// Stop when the first script that contains this location is found.
if (child.startLine <= aLine &&
child.startLine + child.lineCount > aLine) {
return this._getInnermostContainer(child, aLine);
}
}
}
// Location not found in children, this is the innermost containing script.
return aScript;
},
/**
@ -346,6 +394,46 @@ ThreadActor.prototype = {
return packet;
},
/**
* Handle a protocol request to pause the debuggee.
*/
onInterrupt: function TA_onScripts(aRequest) {
if (this.state == "exited") {
return { type: "exited" };
} else if (this.state == "paused") {
// TODO: return the actual reason for the existing pause.
return { type: "paused", why: { type: "alreadyPaused" } };
} else if (this.state != "running") {
return { error: "wrongState",
message: "Received interrupt request in " + this.state +
" state." };
}
try {
// Put ourselves in the paused state.
let packet = this._paused();
if (!packet) {
return { error: "notInterrupted" };
}
packet.why = { type: "interrupted" };
// Send the response to the interrupt request now (rather than
// returning it), because we're going to start a nested event loop
// here.
this.conn.send(packet);
// Start a nested event loop.
this._nest();
// We already sent a response to this request, don't send one
// now.
return null;
} catch(e) {
Cu.reportError(e);
return { error: "notInterrupted", message: e.toString() };
}
},
/**
* Return the Debug.Frame for a frame mentioned by the protocol.
*/
@ -626,7 +714,8 @@ ThreadActor.prototype = {
this.conn.send(packet);
return this._nest();
} catch(e) {
dumpn("Got an exception during onDebuggerStatement: " + e + ': ' + e.stack);
Cu.reportError("Got an exception during onDebuggerStatement: " + e +
": " + e.stack);
return undefined;
}
},
@ -645,10 +734,6 @@ ThreadActor.prototype = {
* The function object that the ew code is part of.
*/
onNewScript: function TA_onNewScript(aScript, aFunction) {
dumpn("Got a new script:" + aScript + ", url: " + aScript.url +
", startLine: " + aScript.startLine + ", lineCount: " +
aScript.lineCount + ", strictMode: " + aScript.strictMode +
", function: " + aFunction);
// Use a sparse array for storing the scripts for each URL in order to
// optimize retrieval. XXX: in case this is not fast enough for very large
// files with too many scripts, we could sort the hash of script locations
@ -670,6 +755,7 @@ ThreadActor.prototype.requestTypes = {
"resume": ThreadActor.prototype.onResume,
"clientEvaluate": ThreadActor.prototype.onClientEvaluate,
"frames": ThreadActor.prototype.onFrames,
"interrupt": ThreadActor.prototype.onInterrupt,
"releaseMany": ThreadActor.prototype.onReleaseMany,
"setBreakpoint": ThreadActor.prototype.onSetBreakpoint,
"scripts": ThreadActor.prototype.onScripts
@ -1079,7 +1165,7 @@ BreakpointActor.prototype = {
this.conn.send(packet);
return this.threadActor._nest();
} catch(e) {
dumpn("Got an exception during hit: " + e + ': ' + e.stack);
Cu.reportError("Got an exception during hit: " + e + ': ' + e.stack);
return undefined;
}
},
@ -1232,4 +1318,3 @@ EnvironmentActor.prototype.requestTypes = {
"assign": EnvironmentActor.prototype.onAssign,
"bindings": EnvironmentActor.prototype.onBindings
};

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

@ -432,7 +432,7 @@ DebuggerServerConnection.prototype = {
try {
ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket);
} catch(e) {
dumpn(e);
Cu.reportError(e);
ret = { error: "unknownError",
message: "An unknown error has occurred while processing request." };
}

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

@ -46,8 +46,7 @@ function test_simple_breakpoint()
});
// Continue until the breakpoint is hit.
gThreadClient.resume(function () {
});
gThreadClient.resume();
});

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

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting breakpoints when the debuggee is running works.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_breakpoint_running();
});
});
do_test_pending();
}
function test_breakpoint_running()
{
let path = getFilePath('test_breakpoint-01.js');
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"var a = 1;\n" + // line0 + 1
"var b = 2;\n"); // line0 + 2
// Setting the breakpoint later should interrupt the debuggee.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "interrupted");
});
gThreadClient.setBreakpoint({ url: path, line: gDebuggee.line0 + 3}, function(aResponse) {
// Eval scripts don't stick around long enough for the breakpoint to be set,
// so just make sure we got the expected response from the actor.
do_check_eq(aResponse.error, "noScript");
do_execute_soon(function() {
finishClient(gClient);
});
});
}

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

@ -0,0 +1,66 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code will skip forward.
*/
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_skip_breakpoint();
});
});
do_test_pending();
}
function test_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-03.js');
let location = { url: path, line: gDebuggee.line0 + 3};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.url, location.url);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.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();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"// A comment.\n" + // line0 + 3
"var b = 2;\n"); // line0 + 4
}

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

@ -0,0 +1,67 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line in a child script works.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_child_breakpoint();
});
});
do_test_pending();
}
function test_child_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-04.js');
let location = { url: path, line: gDebuggee.line0 + 3};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// actualLocation is not returned when breakpoints don't skip forward.
do_check_eq(aResponse.actualLocation, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, 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();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" this.b = 2;\n" + // line0 + 3
"}\n" + // line0 + 4
"debugger;\n" + // line0 + 5
"foo();\n"); // line0 + 6
}

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

@ -0,0 +1,70 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in a child script
* will skip forward.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_child_skip_breakpoint();
});
});
do_test_pending();
}
function test_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-05.js');
let location = { url: path, line: gDebuggee.line0 + 3};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.url, location.url);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.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();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n"); // line0 + 7
}

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

@ -0,0 +1,76 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in a deeply-nested
* child script will skip forward.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_nested_breakpoint();
});
});
do_test_pending();
}
function test_nested_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-06.js');
let location = { url: path, line: gDebuggee.line0 + 5};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.url, location.url);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.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();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" function bar() {\n" + // line0 + 2
" function baz() {\n" + // line0 + 3
" this.a = 1;\n" + // line0 + 4
" // A comment.\n" + // line0 + 5
" this.b = 2;\n" + // line0 + 6
" }\n" + // line0 + 7
" baz();\n" + // line0 + 8
" }\n" + // line0 + 9
" bar();\n" + // line0 + 10
"}\n" + // line0 + 11
"debugger;\n" + // line0 + 12
"foo();\n"); // line0 + 13
}

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

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in the second child
* script will skip forward.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_second_child_skip_breakpoint();
});
});
do_test_pending();
}
function test_second_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-07.js');
let location = { url: path, line: gDebuggee.line0 + 6};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.url, location.url);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.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();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" bar();\n" + // line0 + 2
"}\n" + // line0 + 3
"function bar() {\n" + // line0 + 4
" this.a = 1;\n" + // line0 + 5
" // A comment.\n" + // line0 + 6
" this.b = 2;\n" + // line0 + 7
"}\n" + // line0 + 8
"debugger;\n" + // line0 + 9
"foo();\n"); // line0 + 10
}

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

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in a child script
* will skip forward, in a file with two scripts.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_child_skip_breakpoint();
});
});
do_test_pending();
}
function test_child_skip_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-08.js');
let location = { url: path, line: gDebuggee.line0 + 3};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.url, location.url);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.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();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n"); // line0 + 5
gDebuggee.eval("var line1 = Error().lineNumber;\n" +
"debugger;\n" + // line1 + 1
"foo();\n"); // line1 + 2
}

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

@ -0,0 +1,76 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that removing a breakpoint works.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_remove_breakpoint();
});
});
do_test_pending();
}
function test_remove_breakpoint()
{
let done = false;
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-09.js');
let location = { url: path, line: gDebuggee.line0 + 1};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.a, undefined);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
done = true;
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// The breakpoint should not be hit again.
gThreadClient.resume(function () {
do_check_true(false);
});
});
gThreadClient.resume();
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo(stop) {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" if (stop) return;\n" + // line0 + 3
" delete this.a;\n" + // line0 + 4
" foo(true);\n" + // line0 + 5
"}\n" + // line0 + 6
"debugger;\n" + // line1 + 7
"foo();\n"); // line1 + 8
if (!done) {
do_check_true(false);
}
finishClient(gClient);
}

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

@ -0,0 +1,79 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line with multiple entry points
* triggers no matter which entry point we reach.
*/
var gDebuggee;
var gClient;
var gThreadClient;
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_child_breakpoint();
});
});
do_test_pending();
}
function test_child_breakpoint()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
let path = getFilePath('test_breakpoint-10.js');
let location = { url: path, line: gDebuggee.line0 + 3};
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
// actualLocation is not returned when breakpoints don't skip forward.
do_check_eq(aResponse.actualLocation, undefined);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.i, 0);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check the return value.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.why.type, "breakpoint");
do_check_eq(aPacket.why.actors[0], bpClient.actor);
// Check that the breakpoint worked.
do_check_eq(gDebuggee.i, 1);
// Remove the breakpoint.
bpClient.remove(function (aResponse) {
gThreadClient.resume(function () {
finishClient(gClient);
});
});
});
// Continue until the breakpoint is hit again.
gThreadClient.resume();
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a, i = 0;\n" + // line0 + 2
"for (i = 1; i <= 2; i++) {\n" + // line0 + 3
" a = i;\n" + // line0 + 4
"}\n"); // line0 + 5
}

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

@ -0,0 +1,54 @@
/* 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.paused, true);
aThreadClient.resume(function() {
test_interrupt();
});
});
}
function test_interrupt()
{
do_check_eq(gClient.activeThread.paused, false);
gClient.activeThread.interrupt(function(aResponse) {
do_check_eq(gClient.activeThread.paused, true);
gClient.activeThread.resume(function() {
do_check_eq(gClient.activeThread.paused, false);
cleanup();
});
});
}
function cleanup()
{
gClient.addListener("closed", function(aEvent) {
do_test_finished();
});
gClient.close();
}

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

@ -34,8 +34,18 @@ tail =
[test_eval-04.js]
[test_eval-05.js]
[test_breakpoint-01.js]
[test_breakpoint-02.js]
[test_breakpoint-03.js]
[test_breakpoint-04.js]
[test_breakpoint-05.js]
[test_breakpoint-06.js]
[test_breakpoint-07.js]
[test_breakpoint-08.js]
[test_breakpoint-09.js]
[test_breakpoint-10.js]
[test_listscripts-01.js]
[test_objectgrips-01.js]
[test_objectgrips-02.js]
[test_objectgrips-03.js]
[test_objectgrips-04.js]
[test_interrupt.js]