mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 740825 - Implement conditional breakpoints, r=past
This commit is contained in:
parent
a81099530e
commit
ba651862ac
@ -374,6 +374,8 @@ StackFrames.prototype = {
|
||||
get activeThread() DebuggerController.activeThread,
|
||||
autoScopeExpand: false,
|
||||
currentFrame: null,
|
||||
currentBreakpointLocation: null,
|
||||
currentEvaluation: null,
|
||||
currentException: null,
|
||||
|
||||
/**
|
||||
@ -419,9 +421,19 @@ StackFrames.prototype = {
|
||||
* The response packet.
|
||||
*/
|
||||
_onPaused: function SF__onPaused(aEvent, aPacket) {
|
||||
// In case the pause was caused by an exception, store the exception value.
|
||||
if (aPacket.why.type == "exception") {
|
||||
this.currentException = aPacket.why.exception;
|
||||
switch (aPacket.why.type) {
|
||||
// If paused by a breakpoint, store the breakpoint location.
|
||||
case "breakpoint":
|
||||
this.currentBreakpointLocation = aPacket.frame.where;
|
||||
break;
|
||||
// If paused by a client evaluation, store the evaluated value.
|
||||
case "clientEvaluated":
|
||||
this.currentEvaluation = aPacket.why.frameFinished.return;
|
||||
break;
|
||||
// If paused by an exception, store the exception value.
|
||||
case "exception":
|
||||
this.currentException = aPacket.why.exception;
|
||||
break;
|
||||
}
|
||||
|
||||
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
|
||||
@ -445,6 +457,35 @@ StackFrames.prototype = {
|
||||
}
|
||||
DebuggerView.StackFrames.empty();
|
||||
|
||||
// Conditional breakpoints are { breakpoint, expression } tuples. The
|
||||
// boolean evaluation of the expression decides if the active thread
|
||||
// automatically resumes execution or not.
|
||||
if (this.currentBreakpointLocation) {
|
||||
let { url, line } = this.currentBreakpointLocation;
|
||||
let breakpointClient = DebuggerController.Breakpoints.getBreakpoint(url, line);
|
||||
let conditionalExpression = breakpointClient.conditionalExpression;
|
||||
if (conditionalExpression) {
|
||||
// Evaluating the current breakpoint's conditional expression will
|
||||
// cause the stack frames to be cleared and active thread to pause,
|
||||
// sending a 'clientEvaluated' packed and adding the frames again.
|
||||
this.evaluate("(" + conditionalExpression + ")", 0);
|
||||
this._isConditionalBreakpointEvaluation = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Got our evaluation of the current breakpoint's conditional expression.
|
||||
if (this._isConditionalBreakpointEvaluation) {
|
||||
this._isConditionalBreakpointEvaluation = false;
|
||||
|
||||
// If the breakpoint's conditional expression evaluation is falsy,
|
||||
// automatically resume execution.
|
||||
if (VariablesView.isFalsy({ value: this.currentEvaluation })) {
|
||||
this.activeThread.resume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (let frame of this.activeThread.cachedFrames) {
|
||||
this._addFrame(frame);
|
||||
}
|
||||
@ -461,6 +502,8 @@ StackFrames.prototype = {
|
||||
*/
|
||||
_onFramesCleared: function SF__onFramesCleared() {
|
||||
this.currentFrame = null;
|
||||
this.currentBreakpointLocation = null;
|
||||
this.currentEvaluation = null;
|
||||
this.currentException = null;
|
||||
// After each frame step (in, over, out), framescleared is fired, which
|
||||
// forces the UI to be emptied and rebuilt on framesadded. Most of the times
|
||||
@ -654,7 +697,6 @@ StackFrames.prototype = {
|
||||
if (!aArguments) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let argument of aArguments) {
|
||||
let name = Object.getOwnPropertyNames(argument)[0];
|
||||
let argRef = aScope.addVar(name, argument[name]);
|
||||
@ -675,7 +717,6 @@ StackFrames.prototype = {
|
||||
if (!aVariables) {
|
||||
return;
|
||||
}
|
||||
|
||||
let variableNames = Object.keys(aVariables);
|
||||
|
||||
// Sort all of the variables before adding them if preferred.
|
||||
@ -778,10 +819,7 @@ StackFrames.prototype = {
|
||||
|
||||
let startText = StackFrameUtils.getFrameTitle(aFrame);
|
||||
let endText = SourceUtils.getSourceLabel(url) + ":" + line;
|
||||
|
||||
DebuggerView.StackFrames.addFrame(startText, endText, depth, {
|
||||
attachment: aFrame
|
||||
});
|
||||
DebuggerView.StackFrames.addFrame(startText, endText, depth);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -798,9 +836,11 @@ StackFrames.prototype = {
|
||||
*
|
||||
* @param string aExpression
|
||||
* The expression to evaluate.
|
||||
* @param number aFrame [optional]
|
||||
* The frame depth used for evaluation.
|
||||
*/
|
||||
evaluate: function SF_evaluate(aExpression) {
|
||||
let frame = this.activeThread.cachedFrames[this.currentFrame];
|
||||
evaluate: function SF_evaluate(aExpression, aFrame = this.currentFrame) {
|
||||
let frame = this.activeThread.cachedFrames[aFrame];
|
||||
this.activeThread.eval(frame.actor, aExpression);
|
||||
}
|
||||
};
|
||||
@ -1107,7 +1147,10 @@ Breakpoints.prototype = {
|
||||
updateEditorBreakpoints: function BP_updateEditorBreakpoints() {
|
||||
for each (let breakpointClient in this.store) {
|
||||
if (DebuggerView.Sources.selectedValue == breakpointClient.location.url) {
|
||||
this._showBreakpoint(breakpointClient, { noPaneUpdate: true });
|
||||
this._showBreakpoint(breakpointClient, {
|
||||
noPaneUpdate: true,
|
||||
noPaneHighlight: true
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1120,7 +1163,10 @@ Breakpoints.prototype = {
|
||||
updatePaneBreakpoints: function BP_updatePaneBreakpoints() {
|
||||
for each (let breakpointClient in this.store) {
|
||||
if (DebuggerView.Sources.containsValue(breakpointClient.location.url)) {
|
||||
this._showBreakpoint(breakpointClient, { noEditorUpdate: true });
|
||||
this._showBreakpoint(breakpointClient, {
|
||||
noEditorUpdate: true,
|
||||
noPaneHighlight: true
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1140,8 +1186,11 @@ Breakpoints.prototype = {
|
||||
* - aResponseError: if there was any error
|
||||
* @param object aFlags [optional]
|
||||
* An object containing some of the following boolean properties:
|
||||
* - conditionalExpression: tells this breakpoint's conditional expression
|
||||
* - openPopup: tells if the expression popup should be shown
|
||||
* - noEditorUpdate: tells if you want to skip editor updates
|
||||
* - noPaneUpdate: tells if you want to skip breakpoint pane updates
|
||||
* - noPaneHighlight: tells if you don't want to highlight the breakpoint
|
||||
*/
|
||||
addBreakpoint:
|
||||
function BP_addBreakpoint(aLocation, aCallback, aFlags = {}) {
|
||||
@ -1182,6 +1231,9 @@ Breakpoints.prototype = {
|
||||
// Remember the breakpoint client in the store.
|
||||
this.store[aBreakpointClient.actor] = aBreakpointClient;
|
||||
|
||||
// Attach any specified conditional expression to the breakpoint client.
|
||||
aBreakpointClient.conditionalExpression = aFlags.conditionalExpression;
|
||||
|
||||
// Preserve some information about the breakpoint's source url and line
|
||||
// to display in the breakpoints pane.
|
||||
aBreakpointClient.lineText = DebuggerView.getEditorLine(line - 1);
|
||||
@ -1205,9 +1257,7 @@ Breakpoints.prototype = {
|
||||
* callback is invoked with one argument
|
||||
* - aBreakpointClient: the breakpoint location (url and line)
|
||||
* @param object aFlags [optional]
|
||||
* An object containing some of the following boolean properties:
|
||||
* - noEditorUpdate: tells if you want to skip editor updates
|
||||
* - noPaneUpdate: tells if you want to skip breakpoint pane updates
|
||||
* @see DebuggerController.Breakpoints.addBreakpoint
|
||||
*/
|
||||
removeBreakpoint:
|
||||
function BP_removeBreakpoint(aBreakpointClient, aCallback, aFlags = {}) {
|
||||
@ -1237,14 +1287,13 @@ Breakpoints.prototype = {
|
||||
* @param object aBreakpointClient
|
||||
* The BreakpointActor client object to show.
|
||||
* @param object aFlags [optional]
|
||||
* An object containing some of the following boolean properties:
|
||||
* - noEditorUpdate: tells if you want to skip editor updates
|
||||
* - noPaneUpdate: tells if you want to skip breakpoint pane updates
|
||||
* @see DebuggerController.Breakpoints.addBreakpoint
|
||||
*/
|
||||
_showBreakpoint: function BP__showBreakpoint(aBreakpointClient, aFlags = {}) {
|
||||
let currentSourceUrl = DebuggerView.Sources.selectedValue;
|
||||
let { url, line } = aBreakpointClient.location;
|
||||
|
||||
// Update the editor if required.
|
||||
if (!aFlags.noEditorUpdate) {
|
||||
if (url == currentSourceUrl) {
|
||||
this._skipEditorBreakpointCallbacks = true;
|
||||
@ -1252,10 +1301,18 @@ Breakpoints.prototype = {
|
||||
this._skipEditorBreakpointCallbacks = false;
|
||||
}
|
||||
}
|
||||
// Update the breakpoints pane if required.
|
||||
if (!aFlags.noPaneUpdate) {
|
||||
let { lineText, lineInfo } = aBreakpointClient;
|
||||
let actor = aBreakpointClient.actor;
|
||||
DebuggerView.Breakpoints.addBreakpoint(lineInfo, lineText, url, line, actor);
|
||||
let { lineText, lineInfo, actor } = aBreakpointClient;
|
||||
let conditionalFlag = aBreakpointClient.conditionalExpression !== undefined;
|
||||
let openPopupFlag = aFlags.openPopup;
|
||||
|
||||
DebuggerView.Breakpoints.addBreakpoint(
|
||||
url, line, actor, lineInfo, lineText, conditionalFlag, openPopupFlag);
|
||||
}
|
||||
// Highlight the breakpoint in the pane if required.
|
||||
if (!aFlags.noPaneHighlight) {
|
||||
DebuggerView.Breakpoints.highlightBreakpoint(url, line);
|
||||
}
|
||||
},
|
||||
|
||||
@ -1265,14 +1322,13 @@ Breakpoints.prototype = {
|
||||
* @param object aBreakpointClient
|
||||
* The BreakpointActor client object to hide.
|
||||
* @param object aFlags [optional]
|
||||
* An object containing some of the following boolean properties:
|
||||
* - noEditorUpdate: tells if you want to skip editor updates
|
||||
* - noPaneUpdate: tells if you want to skip breakpoint pane updates
|
||||
* @see DebuggerController.Breakpoints.addBreakpoint
|
||||
*/
|
||||
_hideBreakpoint: function BP__hideBreakpoint(aBreakpointClient, aFlags = {}) {
|
||||
let currentSourceUrl = DebuggerView.Sources.selectedValue;
|
||||
let { url, line } = aBreakpointClient.location;
|
||||
|
||||
// Update the editor if required.
|
||||
if (!aFlags.noEditorUpdate) {
|
||||
if (url == currentSourceUrl) {
|
||||
this._skipEditorBreakpointCallbacks = true;
|
||||
@ -1280,6 +1336,7 @@ Breakpoints.prototype = {
|
||||
this._skipEditorBreakpointCallbacks = false;
|
||||
}
|
||||
}
|
||||
// Update the breakpoints pane if required.
|
||||
if (!aFlags.noPaneUpdate) {
|
||||
DebuggerView.Breakpoints.removeBreakpoint(url, line);
|
||||
}
|
||||
|
@ -50,12 +50,9 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
|
||||
* Details to be displayed in the list.
|
||||
* @param number aDepth
|
||||
* The frame depth specified by the debugger.
|
||||
* @param object aOptions [optional]
|
||||
* Additional options or flags supported by this operation:
|
||||
* - attachment: any kind of primitive/object to attach
|
||||
*/
|
||||
addFrame:
|
||||
function DVSF_addFrame(aFrameName, aFrameDetails, aDepth, aOptions = {}) {
|
||||
function DVSF_addFrame(aFrameName, aFrameDetails, aDepth) {
|
||||
// Stackframes are UI elements which benefit from visible panes.
|
||||
DebuggerView.showPanesSoon();
|
||||
|
||||
@ -64,7 +61,9 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
|
||||
forced: true,
|
||||
unsorted: true,
|
||||
relaxed: true,
|
||||
attachment: aOptions.attachment
|
||||
attachment: {
|
||||
depth: aDepth
|
||||
}
|
||||
});
|
||||
|
||||
// Check if stackframe was already appended.
|
||||
@ -154,8 +153,16 @@ function BreakpointsView() {
|
||||
MenuContainer.call(this);
|
||||
this._createItemView = this._createItemView.bind(this);
|
||||
this._onBreakpointRemoved = this._onBreakpointRemoved.bind(this);
|
||||
this._onClick = this._onClick.bind(this);
|
||||
this._onEditorLoad = this._onEditorLoad.bind(this);
|
||||
this._onEditorUnload = this._onEditorUnload.bind(this);
|
||||
this._onEditorSelection = this._onEditorSelection.bind(this);
|
||||
this._onEditorContextMenu = this._onEditorContextMenu.bind(this);
|
||||
this._onBreakpointClick = this._onBreakpointClick.bind(this);
|
||||
this._onCheckboxClick = this._onCheckboxClick.bind(this);
|
||||
this._onConditionalPopupShowing = this._onConditionalPopupShowing.bind(this);
|
||||
this._onConditionalPopupShown = this._onConditionalPopupShown.bind(this);
|
||||
this._onConditionalPopupHiding = this._onConditionalPopupHiding.bind(this);
|
||||
this._onConditionalTextboxKeyPress = this._onConditionalTextboxKeyPress.bind(this);
|
||||
}
|
||||
|
||||
create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
@ -165,12 +172,22 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
initialize: function DVB_initialize() {
|
||||
dumpn("Initializing the BreakpointsView");
|
||||
this._container = new StackList(document.getElementById("breakpoints"));
|
||||
this._commandset = document.getElementById("debuggerCommands");
|
||||
this._popupset = document.getElementById("debuggerPopupset");
|
||||
this._cbPanel = document.getElementById("conditional-breakpoint-panel");
|
||||
this._cbTextbox = document.getElementById("conditional-breakpoint-textbox");
|
||||
|
||||
this._container.emptyText = L10N.getStr("emptyBreakpointsText");
|
||||
this._container.itemFactory = this._createItemView;
|
||||
this._container.uniquenessQualifier = 2;
|
||||
this._container.addEventListener("click", this._onClick, false);
|
||||
|
||||
window.addEventListener("Debugger:EditorLoaded", this._onEditorLoad, false);
|
||||
window.addEventListener("Debugger:EditorUnloaded", this._onEditorUnload, false);
|
||||
this._container.addEventListener("click", this._onBreakpointClick, false);
|
||||
this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false)
|
||||
this._cbPanel.addEventListener("popupshown", this._onConditionalPopupShown, false)
|
||||
this._cbPanel.addEventListener("popuphiding", this._onConditionalPopupHiding, false)
|
||||
this._cbTextbox.addEventListener("keypress", this._onConditionalTextboxKeyPress, false);
|
||||
|
||||
this._cache = new Map();
|
||||
},
|
||||
@ -180,43 +197,55 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
*/
|
||||
destroy: function DVB_destroy() {
|
||||
dumpn("Destroying the BreakpointsView");
|
||||
this._container.removeEventListener("click", this._onClick, false);
|
||||
window.removeEventListener("Debugger:EditorLoaded", this._onEditorLoad, false);
|
||||
window.removeEventListener("Debugger:EditorUnloaded", this._onEditorUnload, false);
|
||||
this._container.removeEventListener("click", this._onBreakpointClick, false);
|
||||
this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShowing, false);
|
||||
this._cbPanel.removeEventListener("popupshown", this._onConditionalPopupShown, false);
|
||||
this._cbPanel.removeEventListener("popuphiding", this._onConditionalPopupHiding, false)
|
||||
this._cbTextbox.removeEventListener("keypress", this._onConditionalTextboxKeyPress, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a breakpoint in this breakpoints container.
|
||||
*
|
||||
* @param string aLineInfo
|
||||
* Line information (parent source etc.) to be displayed in the list.
|
||||
* @param string aLineText
|
||||
* Line text to be displayed in the list.
|
||||
* @param string aSourceLocation
|
||||
* The breakpoint source location specified by the debugger controller.
|
||||
* @param number aLineNumber
|
||||
* The breakpoint line number specified by the debugger controller.
|
||||
* @parm string aId
|
||||
* A breakpoint identifier specified by the debugger controller.
|
||||
* @param string aActor
|
||||
* A breakpoint identifier specified by the debugger controller.
|
||||
* @param string aLineInfo
|
||||
* Line information (parent source etc.) to be displayed in the list.
|
||||
* @param string aLineText
|
||||
* Line text to be displayed in the list.
|
||||
* @param boolean aConditionalFlag [optional]
|
||||
* A flag specifying if this is a conditional breakpoint.
|
||||
* @param boolean aOpenPopupFlag [optional]
|
||||
* A flag specifying if the expression popup should be shown.
|
||||
*/
|
||||
addBreakpoint:
|
||||
function DVB_addBreakpoint(aLineInfo, aLineText, aSourceLocation, aLineNumber, aId) {
|
||||
addBreakpoint: function DVB_addBreakpoint(aSourceLocation, aLineNumber,
|
||||
aActor, aLineInfo, aLineText,
|
||||
aConditionalFlag, aOpenPopupFlag) {
|
||||
// Append a breakpoint item to this container.
|
||||
let breakpointItem = this.push(aLineInfo.trim(), aLineText.trim(), {
|
||||
forced: true,
|
||||
attachment: {
|
||||
enabled: true,
|
||||
sourceLocation: aSourceLocation,
|
||||
lineNumber: aLineNumber
|
||||
lineNumber: aLineNumber,
|
||||
isConditional: aConditionalFlag
|
||||
}
|
||||
});
|
||||
|
||||
// Check if breakpoint was already appended.
|
||||
if (!breakpointItem) {
|
||||
this.enableBreakpoint(aSourceLocation, aLineNumber, { id: aId });
|
||||
this.enableBreakpoint(aSourceLocation, aLineNumber, { id: aActor });
|
||||
return;
|
||||
}
|
||||
|
||||
let element = breakpointItem.target;
|
||||
element.id = "breakpoint-" + aId;
|
||||
element.id = "breakpoint-" + aActor;
|
||||
element.className = "dbg-breakpoint list-item";
|
||||
element.infoNode.className = "dbg-breakpoint-info plain";
|
||||
element.textNode.className = "dbg-breakpoint-text plain";
|
||||
@ -224,6 +253,12 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
|
||||
breakpointItem.finalize = this._onBreakpointRemoved;
|
||||
this._cache.set(this._key(aSourceLocation, aLineNumber), breakpointItem);
|
||||
|
||||
// If this is a conditional breakpoint, display the panes and a panel
|
||||
// to input the corresponding conditional expression.
|
||||
if (aConditionalFlag && aOpenPopupFlag) {
|
||||
this.highlightBreakpoint(aSourceLocation, aLineNumber, { openPopup: true });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -267,6 +302,7 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
if (aOptions.id) {
|
||||
breakpointItem.target.id = "breakpoint-" + aOptions.id;
|
||||
}
|
||||
|
||||
// Update the checkbox state if necessary.
|
||||
if (!aOptions.silent) {
|
||||
breakpointItem.target.checkbox.setAttribute("checked", "true");
|
||||
@ -330,13 +366,47 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
* The breakpoint source location.
|
||||
* @param number aLineNumber
|
||||
* The breakpoint line number.
|
||||
* @param object aFlags [optional]
|
||||
* An object containing some of the following boolean properties:
|
||||
* - updateEditor: true if editor updates should be allowed
|
||||
* - openPopup: true if the expression popup should be shown
|
||||
*/
|
||||
highlightBreakpoint: function DVB_highlightBreakpoint(aSourceLocation, aLineNumber) {
|
||||
highlightBreakpoint:
|
||||
function DVB_highlightBreakpoint(aSourceLocation, aLineNumber, aFlags = {}) {
|
||||
let breakpointItem = this.getBreakpoint(aSourceLocation, aLineNumber);
|
||||
if (breakpointItem) {
|
||||
// Update the editor source location and line number if necessary.
|
||||
if (aFlags.updateEditor) {
|
||||
DebuggerView.updateEditor(aSourceLocation, aLineNumber, { noDebug: true });
|
||||
}
|
||||
|
||||
// If the breakpoint requires a new conditional expression, display
|
||||
// the panes and the panel to input the corresponding expression.
|
||||
if (aFlags.openPopup && breakpointItem.attachment.isConditional) {
|
||||
let { sourceLocation: url, lineNumber: line } = breakpointItem.attachment;
|
||||
let breakpointClient = DebuggerController.Breakpoints.getBreakpoint(url, line);
|
||||
|
||||
// The conditional expression popup can only be shown with visible panes.
|
||||
DebuggerView.showPanesSoon(function() {
|
||||
// Verify if the breakpoint wasn't removed before the panes were shown.
|
||||
if (this.getBreakpoint(aSourceLocation, aLineNumber)) {
|
||||
this._cbTextbox.value = breakpointClient.conditionalExpression || "";
|
||||
this._cbPanel.openPopup(breakpointItem.target,
|
||||
BREAKPOINT_CONDITIONAL_POPUP_POSITION,
|
||||
BREAKPOINT_CONDITIONAL_POPUP_OFFSET);
|
||||
}
|
||||
}.bind(this));
|
||||
} else {
|
||||
this._cbPanel.hidePopup();
|
||||
}
|
||||
|
||||
// Breakpoint is now highlighted.
|
||||
this._container.selectedItem = breakpointItem.target;
|
||||
} else {
|
||||
}
|
||||
// Can't find a breakpoint at the requested source location and line number.
|
||||
else {
|
||||
this._container.selectedIndex = -1;
|
||||
this._cbPanel.hidePopup();
|
||||
}
|
||||
},
|
||||
|
||||
@ -363,6 +433,19 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
return this._cache.get(this._key(aSourceLocation, aLineNumber));
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the currently selected breakpoint client.
|
||||
* @return object
|
||||
*/
|
||||
get selectedClient() {
|
||||
let selectedItem = this.selectedItem;
|
||||
if (selectedItem) {
|
||||
let { sourceLocation: url, lineNumber: line } = selectedItem.attachment;
|
||||
return DebuggerController.Breakpoints.getBreakpoint(url, line);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Customization function for creating an item's UI.
|
||||
*
|
||||
@ -392,6 +475,7 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
|
||||
let state = document.createElement("vbox");
|
||||
state.className = "state";
|
||||
state.setAttribute("pack", "center");
|
||||
state.appendChild(checkbox);
|
||||
|
||||
let content = document.createElement("vbox");
|
||||
@ -435,12 +519,14 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
createMenuItem.call(this, "disableOthers");
|
||||
createMenuItem.call(this, "deleteOthers");
|
||||
createMenuSeparator();
|
||||
createMenuItem.call(this, "setConditional");
|
||||
createMenuSeparator();
|
||||
createMenuItem.call(this, "enableSelf", true);
|
||||
createMenuItem.call(this, "disableSelf");
|
||||
createMenuItem.call(this, "deleteSelf");
|
||||
|
||||
this._popupset.appendChild(menupopup);
|
||||
document.documentElement.appendChild(commandset);
|
||||
this._commandset.appendChild(commandset);
|
||||
|
||||
aElementNode.commandset = commandset;
|
||||
aElementNode.menupopup = menupopup;
|
||||
@ -510,19 +596,151 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
this._destroyContextMenu(aItem.target);
|
||||
},
|
||||
|
||||
/**
|
||||
* The load listener for the source editor.
|
||||
*/
|
||||
_onEditorLoad: function DVB__onEditorLoad({ detail: editor }) {
|
||||
editor.addEventListener("Selection", this._onEditorSelection, false);
|
||||
editor.addEventListener("ContextMenu", this._onEditorContextMenu, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* The unload listener for the source editor.
|
||||
*/
|
||||
_onEditorUnload: function DVB__onEditorUnload({ detail: editor }) {
|
||||
editor.removeEventListener("Selection", this._onEditorSelection, false);
|
||||
editor.removeEventListener("ContextMenu", this._onEditorContextMenu, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* The selection listener for the source editor.
|
||||
*/
|
||||
_onEditorSelection: function DVB__onEditorSelection(e) {
|
||||
let { start, end } = e.newValue;
|
||||
|
||||
let sourceLocation = DebuggerView.Sources.selectedValue;
|
||||
let lineStart = DebuggerView.editor.getLineAtOffset(start) + 1;
|
||||
let lineEnd = DebuggerView.editor.getLineAtOffset(end) + 1;
|
||||
|
||||
if (this.getBreakpoint(sourceLocation, lineStart) && lineStart == lineEnd) {
|
||||
this.highlightBreakpoint(sourceLocation, lineStart);
|
||||
} else {
|
||||
this.unhighlightBreakpoint();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The context menu listener for the source editor.
|
||||
*/
|
||||
_onEditorContextMenu: function DVB__onEditorContextMenu({ x, y }) {
|
||||
let offset = DebuggerView.editor.getOffsetAtLocation(x, y);
|
||||
let line = DebuggerView.editor.getLineAtOffset(offset);
|
||||
this._editorContextMenuLineNumber = line;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the add breakpoint key sequence was pressed.
|
||||
*/
|
||||
_onCmdAddBreakpoint: function BP__onCmdAddBreakpoint() {
|
||||
// If this command was executed via the context menu, add the breakpoint
|
||||
// on the currently hovered line in the source editor.
|
||||
if (this._editorContextMenuLineNumber >= 0) {
|
||||
DebuggerView.editor.setCaretPosition(this._editorContextMenuLineNumber);
|
||||
}
|
||||
// Avoid placing breakpoints incorrectly when using key shortcuts.
|
||||
this._editorContextMenuLineNumber = -1;
|
||||
|
||||
let url = DebuggerView.Sources.selectedValue;
|
||||
let line = DebuggerView.editor.getCaretPosition().line + 1;
|
||||
let breakpointItem = this.getBreakpoint(url, line);
|
||||
|
||||
// If a breakpoint already existed, remove it now.
|
||||
if (breakpointItem) {
|
||||
let breakpointClient = DebuggerController.Breakpoints.getBreakpoint(url, line)
|
||||
DebuggerController.Breakpoints.removeBreakpoint(breakpointClient);
|
||||
DebuggerView.Breakpoints.unhighlightBreakpoint();
|
||||
}
|
||||
// No breakpoint existed at the required location, add one now.
|
||||
else {
|
||||
let breakpointLocation = { url: url, line: line };
|
||||
DebuggerController.Breakpoints.addBreakpoint(breakpointLocation);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the add conditional breakpoint key sequence was pressed.
|
||||
*/
|
||||
_onCmdAddConditionalBreakpoint: function BP__onCmdAddConditionalBreakpoint() {
|
||||
// If this command was executed via the context menu, add the breakpoint
|
||||
// on the currently hovered line in the source editor.
|
||||
if (this._editorContextMenuLineNumber >= 0) {
|
||||
DebuggerView.editor.setCaretPosition(this._editorContextMenuLineNumber);
|
||||
}
|
||||
// Avoid placing breakpoints incorrectly when using key shortcuts.
|
||||
this._editorContextMenuLineNumber = -1;
|
||||
|
||||
let url = DebuggerView.Sources.selectedValue;
|
||||
let line = DebuggerView.editor.getCaretPosition().line + 1;
|
||||
let breakpointItem = this.getBreakpoint(url, line);
|
||||
|
||||
// If a breakpoint already existed or wasn't a conditional, morph it now.
|
||||
if (breakpointItem) {
|
||||
breakpointItem.attachment.isConditional = true;
|
||||
this.selectedClient.conditionalExpression = "";
|
||||
this.highlightBreakpoint(url, line, { openPopup: true });
|
||||
}
|
||||
// No breakpoint existed at the required location, add one now.
|
||||
else {
|
||||
DebuggerController.Breakpoints.addBreakpoint({ url: url, line: line }, null, {
|
||||
conditionalExpression: "",
|
||||
openPopup: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The popup showing listener for the breakpoints conditional expression panel.
|
||||
*/
|
||||
_onConditionalPopupShowing: function DVB__onConditionalPopupShowing() {
|
||||
this._popupShown = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* The popup shown listener for the breakpoints conditional expression panel.
|
||||
*/
|
||||
_onConditionalPopupShown: function DVB__onConditionalPopupShown() {
|
||||
this._cbTextbox.focus();
|
||||
this._cbTextbox.select();
|
||||
},
|
||||
|
||||
/**
|
||||
* The popup hiding listener for the breakpoints conditional expression panel.
|
||||
*/
|
||||
_onConditionalPopupHiding: function DVB__onConditionalPopupHiding() {
|
||||
this._popupShown = false;
|
||||
this.selectedClient.conditionalExpression = this._cbTextbox.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* The keypress listener for the breakpoints conditional expression textbox.
|
||||
*/
|
||||
_onConditionalTextboxKeyPress: function DVB__onConditionalTextboxKeyPress(e) {
|
||||
if (e.keyCode == e.DOM_VK_RETURN || e.keyCode == e.DOM_VK_ENTER) {
|
||||
this._cbPanel.hidePopup();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The click listener for the breakpoints container.
|
||||
*/
|
||||
_onClick: function DVB__onClick(e) {
|
||||
_onBreakpointClick: function DVB__onBreakpointClick(e) {
|
||||
let breakpointItem = this.getItemForElement(e.target);
|
||||
if (!breakpointItem) {
|
||||
// The container is empty or we didn't click on an actual item.
|
||||
return;
|
||||
}
|
||||
let { sourceLocation: url, lineNumber: line } = breakpointItem.attachment;
|
||||
|
||||
DebuggerView.updateEditor(url, line, { noDebug: true });
|
||||
this.highlightBreakpoint(url, line);
|
||||
this.highlightBreakpoint(url, line, { updateEditor: true, openPopup: e.button == 0 });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -535,14 +753,28 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
return;
|
||||
}
|
||||
let { sourceLocation: url, lineNumber: line, enabled } = breakpointItem.attachment;
|
||||
this[enabled ? "disableBreakpoint" : "enableBreakpoint"](url, line, { silent: true });
|
||||
|
||||
// Don't update the editor location.
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
this[enabled
|
||||
? "disableBreakpoint"
|
||||
: "enableBreakpoint"](url, line, { silent: true });
|
||||
/**
|
||||
* Listener handling the "setConditional" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element node.
|
||||
*/
|
||||
_onSetConditional: function DVB__onSetConditional(aTarget) {
|
||||
if (!aTarget) {
|
||||
return;
|
||||
}
|
||||
let breakpointItem = this.getItemForElement(aTarget);
|
||||
let { sourceLocation: url, lineNumber: line } = breakpointItem.attachment;
|
||||
|
||||
breakpointItem.attachment.isConditional = true;
|
||||
this.highlightBreakpoint(url, line, { openPopup: true });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -684,7 +916,12 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
},
|
||||
|
||||
_popupset: null,
|
||||
_cache: null
|
||||
_commandset: null,
|
||||
_cbPanel: null,
|
||||
_cbTextbox: null,
|
||||
_popupShown: false,
|
||||
_cache: null,
|
||||
_editorContextMenuLineNumber: -1
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,8 @@ const SOURCE_URL_MAX_LENGTH = 64; // chars
|
||||
const SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE = 1048576; // 1 MB in bytes
|
||||
const PANES_APPEARANCE_DELAY = 50; // ms
|
||||
const BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH = 1000; // chars
|
||||
const BREAKPOINT_CONDITIONAL_POPUP_POSITION = "after_start";
|
||||
const BREAKPOINT_CONDITIONAL_POPUP_OFFSET = 50; // px
|
||||
const GLOBAL_SEARCH_LINE_MAX_LENGTH = 300; // chars
|
||||
const GLOBAL_SEARCH_EXPAND_MAX_RESULTS = 50;
|
||||
const GLOBAL_SEARCH_ACTION_DELAY = 150; // ms
|
||||
@ -177,6 +179,7 @@ let DebuggerView = {
|
||||
dumpn("Finished loading the DebuggerView editor");
|
||||
|
||||
DebuggerController.Breakpoints.initialize();
|
||||
window.dispatchEvent("Debugger:EditorLoaded", this.editor);
|
||||
this.editor.focus();
|
||||
},
|
||||
|
||||
@ -188,6 +191,7 @@ let DebuggerView = {
|
||||
dumpn("Destroying the DebuggerView editor");
|
||||
|
||||
DebuggerController.Breakpoints.destroy();
|
||||
window.dispatchEvent("Debugger:EditorUnloaded", this.editor);
|
||||
this.editor = null;
|
||||
},
|
||||
|
||||
@ -237,7 +241,7 @@ let DebuggerView = {
|
||||
* The source object coming from the active thread.
|
||||
* @param object aOptions [optional]
|
||||
* Additional options for showing the source. Supported options:
|
||||
* - targetLine: place the caret position at the given line number
|
||||
* - caretLine: place the caret position at the given line number
|
||||
* - debugLine: place the debug location at the given line number
|
||||
* - callback: function called when the source is shown
|
||||
*/
|
||||
@ -264,21 +268,25 @@ let DebuggerView = {
|
||||
}
|
||||
// If the source is already loaded, display it immediately.
|
||||
else {
|
||||
if (aSource.text.length < SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) {
|
||||
this.setEditorMode(aSource.url, aSource.contentType, aSource.text);
|
||||
} else {
|
||||
this.editor.setMode(SourceEditor.MODES.TEXT);
|
||||
if (this._editorSource != aSource) {
|
||||
// Avoid setting the editor mode for very large files.
|
||||
if (aSource.text.length < SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) {
|
||||
this.setEditorMode(aSource.url, aSource.contentType, aSource.text);
|
||||
} else {
|
||||
this.editor.setMode(SourceEditor.MODES.TEXT);
|
||||
}
|
||||
this.editor.setText(aSource.text);
|
||||
this.editor.resetUndo();
|
||||
}
|
||||
this.editor.setText(aSource.text);
|
||||
this.editor.resetUndo();
|
||||
this._editorSource = aSource;
|
||||
this.updateEditor();
|
||||
|
||||
DebuggerView.Sources.selectedValue = aSource.url;
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
|
||||
// Handle any additional options for showing the source.
|
||||
if (aOptions.targetLine) {
|
||||
editor.setCaretPosition(aOptions.targetLine - 1);
|
||||
if (aOptions.caretLine) {
|
||||
editor.setCaretPosition(aOptions.caretLine - 1);
|
||||
}
|
||||
if (aOptions.debugLine) {
|
||||
editor.setDebugLocation(aOptions.debugLine - 1);
|
||||
@ -382,10 +390,12 @@ let DebuggerView = {
|
||||
* An object containing some of the following boolean properties:
|
||||
* - visible: true if the pane should be shown, false for hidden
|
||||
* - animated: true to display an animation on toggle
|
||||
* - callback: a function to invoke when the panes toggle finishes
|
||||
*/
|
||||
togglePanes: function DV__togglePanes(aFlags = {}) {
|
||||
// Avoid useless toggles.
|
||||
if (aFlags.visible == !this.panesHidden) {
|
||||
aFlags.callback && aFlags.callback();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -414,23 +424,29 @@ let DebuggerView = {
|
||||
|
||||
window.addEventListener("transitionend", function onEvent() {
|
||||
window.removeEventListener("transitionend", onEvent, false);
|
||||
aFlags.callback && aFlags.callback();
|
||||
self.updateEditor();
|
||||
}, false);
|
||||
} else {
|
||||
this._stackframesAndBreakpoints.removeAttribute("animated");
|
||||
this._variables.removeAttribute("animated");
|
||||
aFlags.callback && aFlags.callback();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets all the panes visible after a short period of time.
|
||||
*
|
||||
* @param function aCallback
|
||||
* A function to invoke when the panes toggle finishes.
|
||||
*/
|
||||
showPanesSoon: function DV__showPanesSoon() {
|
||||
showPanesSoon: function DV__showPanesSoon(aCallback) {
|
||||
// Try to keep animations as smooth as possible, so wait a few cycles.
|
||||
window.setTimeout(function() {
|
||||
DebuggerView.togglePanes({
|
||||
visible: true,
|
||||
animated: true
|
||||
animated: true,
|
||||
callback: aCallback
|
||||
});
|
||||
}, PANES_APPEARANCE_DELAY);
|
||||
},
|
||||
@ -448,11 +464,13 @@ let DebuggerView = {
|
||||
this.GlobalSearch.clearCache();
|
||||
this.StackFrames.empty();
|
||||
this.Breakpoints.empty();
|
||||
this.Breakpoints.unhighlightBreakpoint();
|
||||
this.Variables.empty();
|
||||
SourceUtils.clearLabelsCache();
|
||||
|
||||
if (this.editor) {
|
||||
this.editor.setText("");
|
||||
this._editorSource = null;
|
||||
}
|
||||
},
|
||||
|
||||
@ -466,6 +484,7 @@ let DebuggerView = {
|
||||
GlobalSearch: null,
|
||||
Variables: null,
|
||||
_editor: null,
|
||||
_editorSource: null,
|
||||
_togglePanesButton: null,
|
||||
_stackframesAndBreakpoints: null,
|
||||
_variables: null,
|
||||
|
@ -43,6 +43,10 @@
|
||||
oncommand="DebuggerView.Filtering._doGlobalSearch()"/>
|
||||
<command id="variableSearchCommand"
|
||||
oncommand="DebuggerView.Filtering._doVariableSearch()"/>
|
||||
<command id="addBreakpointCommand"
|
||||
oncommand="DebuggerView.Breakpoints._onCmdAddBreakpoint()"/>
|
||||
<command id="addConditionalBreakpointCommand"
|
||||
oncommand="DebuggerView.Breakpoints._onCmdAddConditionalBreakpoint()"/>
|
||||
<command id="togglePauseOnExceptions"
|
||||
oncommand="DebuggerView.Options._togglePauseOnExceptions()"/>
|
||||
<command id="toggleShowPanesOnStartup"
|
||||
@ -56,6 +60,15 @@
|
||||
<popupset id="debuggerPopupset">
|
||||
<menupopup id="sourceEditorContextMenu"
|
||||
onpopupshowing="goUpdateSourceEditorMenuItems()">
|
||||
<menuitem id="se-dbg-cMenu-addBreakpoint"
|
||||
label="&debuggerUI.seMenuBreak;"
|
||||
key="addBreakpointKey"
|
||||
command="addBreakpointCommand"/>
|
||||
<menuitem id="se-dbg-cMenu-addConditionalBreakpoint"
|
||||
label="&debuggerUI.seMenuCondBreak;"
|
||||
key="addConditionalBreakpointKey"
|
||||
command="addConditionalBreakpointCommand"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="se-cMenu-copy"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="se-cMenu-selectAll"/>
|
||||
@ -128,6 +141,14 @@
|
||||
key="V"
|
||||
modifiers="control shift"
|
||||
command="variableSearchCommand"/>
|
||||
<key id="addBreakpointKey"
|
||||
key="B"
|
||||
modifiers="accel"
|
||||
command="addBreakpointCommand"/>
|
||||
<key id="addConditionalBreakpointKey"
|
||||
key="B"
|
||||
modifiers="accel shift"
|
||||
command="addConditionalBreakpointCommand"/>
|
||||
</keyset>
|
||||
|
||||
<vbox id="body" flex="1">
|
||||
@ -201,6 +222,16 @@
|
||||
</vbox>
|
||||
</panel>
|
||||
|
||||
<panel id="conditional-breakpoint-panel"
|
||||
type="arrow"
|
||||
noautofocus="true"
|
||||
position="after_start">
|
||||
<vbox>
|
||||
<label class="description" value="&debuggerUI.condBreakPanelTitle;"/>
|
||||
<textbox id="conditional-breakpoint-textbox"/>
|
||||
</vbox>
|
||||
</panel>
|
||||
|
||||
<vbox id="dbg-content" flex="1">
|
||||
<vbox id="globalsearch" hidden="true"/>
|
||||
<splitter id="globalsearch-splitter"
|
||||
|
@ -72,6 +72,8 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
browser_dbg_clean-exit.js \
|
||||
browser_dbg_bug723069_editor-breakpoints.js \
|
||||
browser_dbg_bug723071_editor-breakpoints-pane.js \
|
||||
browser_dbg_bug740825_conditional-breakpoints-01.js \
|
||||
browser_dbg_bug740825_conditional-breakpoints-02.js \
|
||||
browser_dbg_bug731394_editor-contextmenu.js \
|
||||
browser_dbg_bug786070_hide_nonenums.js \
|
||||
browser_dbg_displayName.js \
|
||||
@ -105,6 +107,7 @@ MOCHITEST_BROWSER_PAGES = \
|
||||
browser_dbg_with-frame.html \
|
||||
browser_dbg_pause-exceptions.html \
|
||||
browser_dbg_breakpoint-new-script.html \
|
||||
browser_dbg_conditional-breakpoints.html \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
|
||||
|
@ -0,0 +1,381 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 740825: test the debugger conditional breakpoints.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_conditional-breakpoints.html";
|
||||
|
||||
let gPane = null;
|
||||
let gTab = null;
|
||||
let gDebuggee = null;
|
||||
let gDebugger = null;
|
||||
let gScripts = null;
|
||||
let gEditor = null;
|
||||
let gBreakpoints = null;
|
||||
let gBreakpointsPane = null;
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
|
||||
gBreakpointsPane = gDebugger.DebuggerView.Breakpoints;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.ermahgerd(); // ermahgerd!!
|
||||
});
|
||||
});
|
||||
|
||||
function onScriptShown(aEvent)
|
||||
{
|
||||
scriptShown = aEvent.detail.url.indexOf("conditional-breakpoints") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
|
||||
window.addEventListener("Debugger:SourceShown", onScriptShown);
|
||||
|
||||
function startTest()
|
||||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
window.removeEventListener("Debugger:SourceShown", onScriptShown);
|
||||
testStarted = true;
|
||||
Services.tm.currentThread.dispatch({ run: addBreakpoints }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function performTest()
|
||||
{
|
||||
gScripts = gDebugger.DebuggerView.Sources;
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(gScripts._container.itemCount, 1, "Found the expected number of scripts.");
|
||||
|
||||
gEditor = gDebugger.editor;
|
||||
|
||||
isnot(gEditor.getText().indexOf("ermahgerd"), -1,
|
||||
"The correct script was loaded initially.");
|
||||
is(gScripts.selectedValue, gScripts.values[0],
|
||||
"The correct script is selected");
|
||||
|
||||
gBreakpoints = gPane.breakpoints;
|
||||
is(Object.keys(gBreakpoints).length, 13, "thirteen breakpoints");
|
||||
ok(!gPane.getBreakpoint("foo", 3), "getBreakpoint('foo', 3) returns falsey");
|
||||
|
||||
is(gEditor.getBreakpoints().length, 13, "thirteen breakpoints in the editor");
|
||||
|
||||
gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
|
||||
executeSoon(test1);
|
||||
}
|
||||
|
||||
function test1(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 14, test2);
|
||||
}
|
||||
|
||||
function test2(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 15, test3);
|
||||
}
|
||||
|
||||
function test3(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 16, test4);
|
||||
}
|
||||
|
||||
function test4(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 17, test5);
|
||||
}
|
||||
|
||||
function test5(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 18, test6);
|
||||
}
|
||||
|
||||
function test6(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 19, test7);
|
||||
}
|
||||
|
||||
function test7(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 21, test8);
|
||||
}
|
||||
|
||||
function test8(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 22, test9);
|
||||
}
|
||||
|
||||
function test9(callback)
|
||||
{
|
||||
resumeAndTestBreakpoint(gScripts.selectedValue, 23, test10);
|
||||
}
|
||||
|
||||
function test10(callback)
|
||||
{
|
||||
resume(null, function() {
|
||||
is(gBreakpointsPane.selectedItem, null,
|
||||
"There should be no selected breakpoint in the breakpoints pane.")
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
is(gDebugger.DebuggerController.activeThread.state, "attached",
|
||||
"Should have finished going through all the breakpoints.");
|
||||
|
||||
is(gDebugger.DebuggerView.StackFrames.visibleItems, 0,
|
||||
"There should be no visible stackframes.");
|
||||
is(gDebugger.DebuggerView.Breakpoints.visibleItems, 13,
|
||||
"There should be thirteen visible breakpoints.");
|
||||
|
||||
testReload();
|
||||
});
|
||||
}
|
||||
|
||||
function resumeAndTestBreakpoint(url, line, callback)
|
||||
{
|
||||
resume(line, function() {
|
||||
waitForCaretPos(line - 1, function() {
|
||||
testBreakpoint(gBreakpointsPane.selectedItem, gBreakpointsPane.selectedClient, url, line, true);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testBreakpoint(aBreakpointItem, aBreakpointClient, url, line, editor)
|
||||
{
|
||||
is(aBreakpointItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The breakpoint on line " + line + " wasn't added on the correct source.");
|
||||
is(aBreakpointItem.attachment.lineNumber, line,
|
||||
"The breakpoint on line " + line + " wasn't found.");
|
||||
is(aBreakpointItem.attachment.enabled, true,
|
||||
"The breakpoint on line " + line + " should be enabled.");
|
||||
is(aBreakpointItem.attachment.isConditional, true,
|
||||
"The breakpoint on line " + line + " should be conditional.");
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
|
||||
is(aBreakpointClient.location.url, url,
|
||||
"The breakpoint's client url is correct");
|
||||
is(aBreakpointClient.location.line, line,
|
||||
"The breakpoint's client line is correct");
|
||||
isnot(aBreakpointClient.conditionalExpression, undefined,
|
||||
"The breakpoint on line " + line + " should have a conditional expression.");
|
||||
|
||||
if (editor) {
|
||||
is(gEditor.getCaretPosition().line + 1, line,
|
||||
"The editor caret position is not situated on the proper line.");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The editor caret position is not situated on the proper column.");
|
||||
}
|
||||
}
|
||||
|
||||
function addBreakpoints(callback)
|
||||
{
|
||||
let currentUrl = gDebugger.DebuggerView.Sources.selectedValue;
|
||||
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 12 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 13 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 14 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 15 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 16 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 17 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 18 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 19 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 20 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 21 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 22 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 23 }, function() {
|
||||
gPane.addBreakpoint({ url: currentUrl, line: 24 }, function() {
|
||||
performTest();
|
||||
}, {
|
||||
conditionalExpression: "b"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "a !== null"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "a !== undefined"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "a"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "(function() { return false; })()"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "function() {}"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "{}"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "/regexp/"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "'nasu'"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "true"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "42"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "null"
|
||||
});
|
||||
}, {
|
||||
conditionalExpression: "undefined"
|
||||
});
|
||||
}
|
||||
|
||||
function testReload()
|
||||
{
|
||||
function _get(url, line) {
|
||||
return [
|
||||
gDebugger.DebuggerView.Breakpoints.getBreakpoint(url, line),
|
||||
gDebugger.DebuggerController.Breakpoints.getBreakpoint(url, line),
|
||||
url, line, false
|
||||
];
|
||||
}
|
||||
|
||||
waitForBreakpoints(13, function() {
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 14));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 15));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 16));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 17));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 18));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 19));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 21));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 22));
|
||||
testBreakpoint.apply(this, _get(gScripts.selectedValue, 23));
|
||||
|
||||
is(gBreakpointsPane.selectedItem, null,
|
||||
"There should be no selected item in the breakpoints pane.");
|
||||
is(gBreakpointsPane.selectedClient, null,
|
||||
"There should be no selected client in the breakpoints pane.");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
});
|
||||
|
||||
finalCheck();
|
||||
gDebuggee.location.reload();
|
||||
}
|
||||
|
||||
function finalCheck() {
|
||||
isnot(gEditor.getText().indexOf("ermahgerd"), -1,
|
||||
"The correct script is still loaded.");
|
||||
is(gScripts.selectedValue, gScripts.values[0],
|
||||
"The correct script is still selected");
|
||||
}
|
||||
|
||||
function resume(expected, callback) {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
waitForBreakpoint(expected, callback);
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
gDebugger.document.getElementById("resume"),
|
||||
gDebugger);
|
||||
}
|
||||
|
||||
let bogusClient = {
|
||||
location: {
|
||||
url: null,
|
||||
line: null
|
||||
}
|
||||
};
|
||||
|
||||
function waitForBreakpoint(expected, callback) {
|
||||
// Poll every few milliseconds until expected breakpoint is hit.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the breakpoint.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if ((gBreakpointsPane.selectedClient !== expected) &&
|
||||
(gBreakpointsPane.selectedClient || bogusClient).location.line !== expected) {
|
||||
return;
|
||||
}
|
||||
// We arrived at the expected line, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function waitForBreakpoints(total, callback)
|
||||
{
|
||||
// Poll every few milliseconds until the breakpoints are retrieved.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the breakpoints.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if (gBreakpointsPane.visibleItems != total) {
|
||||
return;
|
||||
}
|
||||
// We got all the breakpoints, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function waitForCaretPos(number, callback)
|
||||
{
|
||||
// Poll every few milliseconds until the source editor line is active.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the line.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if (gEditor.getCaretPosition().line != number) {
|
||||
return;
|
||||
}
|
||||
// We got the source editor at the expected line, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gScripts = null;
|
||||
gEditor = null;
|
||||
gBreakpoints = null;
|
||||
gBreakpointsPane = null;
|
||||
});
|
||||
}
|
@ -0,0 +1,510 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 740825: test the debugger conditional breakpoints.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_conditional-breakpoints.html";
|
||||
|
||||
let gPane = null;
|
||||
let gTab = null;
|
||||
let gDebuggee = null;
|
||||
let gDebugger = null;
|
||||
let gScripts = null;
|
||||
let gEditor = null;
|
||||
let gBreakpoints = null;
|
||||
let gBreakpointsPane = null;
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function test()
|
||||
{
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/source-editor.jsm", tempScope);
|
||||
let SourceEditor = tempScope.SourceEditor;
|
||||
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
|
||||
gBreakpointsPane = gDebugger.DebuggerView.Breakpoints;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.ermahgerd(); // ermahgerd!!
|
||||
});
|
||||
});
|
||||
|
||||
function onScriptShown(aEvent)
|
||||
{
|
||||
scriptShown = aEvent.detail.url.indexOf("conditional-breakpoints") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
|
||||
window.addEventListener("Debugger:SourceShown", onScriptShown);
|
||||
|
||||
function startTest()
|
||||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
window.removeEventListener("Debugger:SourceShown", onScriptShown);
|
||||
testStarted = true;
|
||||
Services.tm.currentThread.dispatch({ run: performTest }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function performTest()
|
||||
{
|
||||
gScripts = gDebugger.DebuggerView.Sources;
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(gScripts._container.itemCount, 1, "Found the expected number of scripts.");
|
||||
|
||||
gEditor = gDebugger.editor;
|
||||
|
||||
isnot(gEditor.getText().indexOf("ermahgerd"), -1,
|
||||
"The correct script was loaded initially.");
|
||||
is(gScripts.selectedValue, gScripts.values[0],
|
||||
"The correct script is selected");
|
||||
|
||||
gBreakpoints = gPane.breakpoints;
|
||||
is(Object.keys(gBreakpoints), 0, "no breakpoints");
|
||||
ok(!gPane.getBreakpoint("foo", 3), "getBreakpoint('foo', 3) returns falsey");
|
||||
|
||||
is(gEditor.getBreakpoints().length, 0, "no breakpoints in the editor");
|
||||
|
||||
gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
|
||||
executeSoon(addBreakpoint1);
|
||||
}
|
||||
|
||||
function addBreakpoint1()
|
||||
{
|
||||
gPane.addBreakpoint({ url: gScripts.selectedValue, line: 12 });
|
||||
|
||||
waitForBreakpoint(12, function() {
|
||||
waitForCaretPos(10, function() {
|
||||
waitForPopup(false, function() {
|
||||
testBreakpoint(gBreakpointsPane.selectedItem,
|
||||
gBreakpointsPane.selectedClient,
|
||||
gScripts.selectedValue, 12, false, false, false);
|
||||
|
||||
executeSoon(addBreakpoint2);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addBreakpoint2()
|
||||
{
|
||||
gBreakpointsPane._editorContextMenuLineNumber = 12;
|
||||
gBreakpointsPane._onCmdAddBreakpoint();
|
||||
|
||||
waitForBreakpoint(13, function() {
|
||||
waitForCaretPos(12, function() {
|
||||
waitForPopup(false, function() {
|
||||
testBreakpoint(gBreakpointsPane.selectedItem,
|
||||
gBreakpointsPane.selectedClient,
|
||||
gScripts.selectedValue, 13, false, false, true);
|
||||
|
||||
executeSoon(modBreakpoint2);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function modBreakpoint2()
|
||||
{
|
||||
gBreakpointsPane._editorContextMenuLineNumber = 12;
|
||||
gBreakpointsPane._onCmdAddConditionalBreakpoint();
|
||||
|
||||
waitForBreakpoint(13, function() {
|
||||
waitForCaretPos(12, function() {
|
||||
waitForPopup(true, function() {
|
||||
testBreakpoint(gBreakpointsPane.selectedItem,
|
||||
gBreakpointsPane.selectedClient,
|
||||
gScripts.selectedValue, 13, true, true, true);
|
||||
|
||||
executeSoon(addBreakpoint3);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addBreakpoint3()
|
||||
{
|
||||
gBreakpointsPane._editorContextMenuLineNumber = 13;
|
||||
gBreakpointsPane._onCmdAddConditionalBreakpoint();
|
||||
|
||||
waitForBreakpoint(14, function() {
|
||||
waitForCaretPos(13, function() {
|
||||
waitForPopup(true, function() {
|
||||
testBreakpoint(gBreakpointsPane.selectedItem,
|
||||
gBreakpointsPane.selectedClient,
|
||||
gScripts.selectedValue, 14, true, true, true);
|
||||
|
||||
executeSoon(modBreakpoint3);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function modBreakpoint3()
|
||||
{
|
||||
write("bamboocha");
|
||||
EventUtils.sendKey("RETURN");
|
||||
|
||||
waitForBreakpoint(14, function() {
|
||||
waitForCaretPos(13, function() {
|
||||
waitForPopup(false, function() {
|
||||
is(gBreakpointsPane.selectedClient.conditionalExpression, "bamboocha",
|
||||
"The bamboocha expression wasn't fonud on the conditional breakpoint");
|
||||
|
||||
executeSoon(testHighlights1);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testHighlights1()
|
||||
{
|
||||
isnot(gBreakpointsPane.selectedItem, null,
|
||||
"There should be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The selected breakpoint should have the correct location.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.lineNumber, 14,
|
||||
"The selected breakpoint should have the correct line number.");
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
is(gEditor.getCaretPosition().line, 13,
|
||||
"The source editor caret position should be at line 13");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
gEditor.setCaretPosition(12);
|
||||
|
||||
waitForCaretPos(12, function() {
|
||||
waitForPopup(false, function() {
|
||||
isnot(gBreakpointsPane.selectedItem, null,
|
||||
"There should be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The selected breakpoint should have the correct location.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.lineNumber, 13,
|
||||
"The selected breakpoint should have the correct line number.");
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
is(gEditor.getCaretPosition().line, 12,
|
||||
"The source editor caret position should be at line 12");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
gEditor.setCaretPosition(11);
|
||||
|
||||
waitForCaretPos(11, function() {
|
||||
waitForPopup(false, function() {
|
||||
isnot(gBreakpointsPane.selectedItem, null,
|
||||
"There should be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The selected breakpoint should have the correct location.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.lineNumber, 12,
|
||||
"The selected breakpoint should have the correct line number.");
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
is(gEditor.getCaretPosition().line, 11,
|
||||
"The source editor caret position should be at line 11");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
gEditor.setCaretPosition(10);
|
||||
|
||||
waitForCaretPos(10, function() {
|
||||
waitForPopup(false, function() {
|
||||
is(gBreakpointsPane.selectedItem, null,
|
||||
"There should not be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
is(gEditor.getCaretPosition().line, 10,
|
||||
"The source editor caret position should be at line 10");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
gEditor.setCaretPosition(14);
|
||||
|
||||
waitForCaretPos(14, function() {
|
||||
waitForPopup(false, function() {
|
||||
is(gBreakpointsPane.selectedItem, null,
|
||||
"There should not be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
is(gEditor.getCaretPosition().line, 14,
|
||||
"The source editor caret position should be at line 14");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
executeSoon(testHighlights2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testHighlights2()
|
||||
{
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gBreakpointsPane._container.getItemAtIndex(2),
|
||||
gDebugger);
|
||||
|
||||
waitForCaretPos(13, function() {
|
||||
waitForPopup(true, function() {
|
||||
isnot(gBreakpointsPane.selectedItem, null,
|
||||
"There should be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The selected breakpoint should have the correct location.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.lineNumber, 14,
|
||||
"The selected breakpoint should have the correct line number.");
|
||||
is(gBreakpointsPane._popupShown, true,
|
||||
"The breakpoint conditional expression popup should be shown.");
|
||||
is(gEditor.getCaretPosition().line, 13,
|
||||
"The source editor caret position should be at line 13");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gBreakpointsPane._container.getItemAtIndex(1),
|
||||
gDebugger);
|
||||
|
||||
waitForCaretPos(12, function() {
|
||||
waitForPopup(true, function() {
|
||||
isnot(gBreakpointsPane.selectedItem, null,
|
||||
"There should be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The selected breakpoint should have the correct location.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.lineNumber, 13,
|
||||
"The selected breakpoint should have the correct line number.");
|
||||
is(gBreakpointsPane._popupShown, true,
|
||||
"The breakpoint conditional expression popup should be shown.");
|
||||
is(gEditor.getCaretPosition().line, 12,
|
||||
"The source editor caret position should be at line 12");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gBreakpointsPane._container.getItemAtIndex(0),
|
||||
gDebugger);
|
||||
|
||||
waitForCaretPos(11, function() {
|
||||
waitForPopup(false, function() {
|
||||
isnot(gBreakpointsPane.selectedItem, null,
|
||||
"There should be a selected breakpoint in the breakpoints pane.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The selected breakpoint should have the correct location.");
|
||||
is(gBreakpointsPane.selectedItem.attachment.lineNumber, 12,
|
||||
"The selected breakpoint should have the correct line number.");
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should be shown.");
|
||||
is(gEditor.getCaretPosition().line, 11,
|
||||
"The source editor caret position should be at line 11");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The source editor caret position should be at column 0");
|
||||
|
||||
executeSoon(delBreakpoint2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function delBreakpoint2()
|
||||
{
|
||||
gBreakpointsPane._editorContextMenuLineNumber = 12;
|
||||
gBreakpointsPane._onCmdAddBreakpoint();
|
||||
|
||||
waitForBreakpoint(null, function() {
|
||||
waitForPopup(false, function() {
|
||||
is(gBreakpointsPane.selectedItem, null,
|
||||
"There should be no selected breakpoint in the breakpoints pane.")
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
|
||||
executeSoon(delBreakpoint3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function delBreakpoint3()
|
||||
{
|
||||
gBreakpointsPane._editorContextMenuLineNumber = 13;
|
||||
gBreakpointsPane._onCmdAddBreakpoint();
|
||||
|
||||
waitForBreakpoint(null, function() {
|
||||
waitForPopup(false, function() {
|
||||
is(gBreakpointsPane.selectedItem, null,
|
||||
"There should be no selected breakpoint in the breakpoints pane.")
|
||||
is(gBreakpointsPane._popupShown, false,
|
||||
"The breakpoint conditional expression popup should not be shown.");
|
||||
|
||||
executeSoon(testBreakpoints);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testBreakpoints()
|
||||
{
|
||||
is(Object.keys(gBreakpoints).length, 1, "one breakpoint");
|
||||
ok(!gPane.getBreakpoint("foo", 3), "getBreakpoint('foo', 3) returns falsey");
|
||||
|
||||
is(gEditor.getBreakpoints().length, 1, "one breakpoint in the editor");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
}
|
||||
|
||||
function testBreakpoint(aBreakpointItem, aBreakpointClient, url, line, conditional, popup, editor)
|
||||
{
|
||||
is(aBreakpointItem.attachment.sourceLocation, gScripts.selectedValue,
|
||||
"The breakpoint on line " + line + " wasn't added on the correct source.");
|
||||
is(aBreakpointItem.attachment.lineNumber, line,
|
||||
"The breakpoint on line " + line + " wasn't found.");
|
||||
is(aBreakpointItem.attachment.enabled, true,
|
||||
"The breakpoint on line " + line + " should be enabled.");
|
||||
is(aBreakpointItem.attachment.isConditional, conditional,
|
||||
"The breakpoint on line " + line + " should " + (conditional ? "" : "not ") + "be conditional.");
|
||||
is(gBreakpointsPane._popupShown, conditional,
|
||||
"The breakpoint conditional expression popup should" + (conditional ? "" : "not ") + "be shown.");
|
||||
|
||||
is(aBreakpointClient.location.url, url,
|
||||
"The breakpoint's client url is correct");
|
||||
is(aBreakpointClient.location.line, line,
|
||||
"The breakpoint's client line is correct");
|
||||
|
||||
if (conditional) {
|
||||
isnot(aBreakpointClient.conditionalExpression, undefined,
|
||||
"The breakpoint on line " + line + " should have a conditional expression.");
|
||||
} else {
|
||||
is(aBreakpointClient.conditionalExpression, undefined,
|
||||
"The breakpoint on line " + line + " should not have a conditional expression.");
|
||||
}
|
||||
|
||||
if (editor) {
|
||||
is(gEditor.getCaretPosition().line + 1, line,
|
||||
"The editor caret position is not situated on the proper line.");
|
||||
is(gEditor.getCaretPosition().col, 0,
|
||||
"The editor caret position is not situated on the proper column.");
|
||||
}
|
||||
}
|
||||
|
||||
let bogusClient = {
|
||||
location: {
|
||||
url: null,
|
||||
line: null
|
||||
}
|
||||
};
|
||||
|
||||
function waitForBreakpoint(expected, callback) {
|
||||
// Poll every few milliseconds until expected breakpoint is hit.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the breakpoint.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if ((gBreakpointsPane.selectedClient !== expected) &&
|
||||
(gBreakpointsPane.selectedClient || bogusClient).location.line !== expected) {
|
||||
return;
|
||||
}
|
||||
// We arrived at the expected line, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function waitForCaretPos(number, callback)
|
||||
{
|
||||
// Poll every few milliseconds until the source editor line is active.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the line.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if (gEditor.getCaretPosition().line != number) {
|
||||
return;
|
||||
}
|
||||
// We got the source editor at the expected line, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function waitForPopup(state, callback)
|
||||
{
|
||||
// Poll every few milliseconds until the expression popup is shown.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the popup.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if (gBreakpointsPane._popupShown != state) {
|
||||
return;
|
||||
}
|
||||
// We got the expression popup at the expected state, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function clear() {
|
||||
gBreakpointsPane._cbTextbox.focus();
|
||||
gBreakpointsPane._cbTextbox.value = "";
|
||||
}
|
||||
|
||||
function write(text) {
|
||||
clear();
|
||||
append(text);
|
||||
}
|
||||
|
||||
function append(text) {
|
||||
gBreakpointsPane._cbTextbox.focus();
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
EventUtils.sendChar(text[i]);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gScripts = null;
|
||||
gEditor = null;
|
||||
gBreakpoints = null;
|
||||
gBreakpointsPane = null;
|
||||
});
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>Browser Debugger Conditional Breakpoints Test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
function ermahgerd() {
|
||||
var a = {};
|
||||
debugger;
|
||||
console.log("undefined");
|
||||
console.log("null");
|
||||
console.log("42");
|
||||
console.log("true");
|
||||
console.log("'nasu'");
|
||||
console.log("/regexp/");
|
||||
console.log("{}");
|
||||
console.log("function() {}");
|
||||
console.log("(function { return false; })()");
|
||||
console.log("a");
|
||||
console.log("a !== undefined");
|
||||
console.log("a !== null");
|
||||
console.log("b");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -1486,7 +1486,34 @@ VariablesView.isPrimitive = function VV_isPrimitive(aDescriptor) {
|
||||
|
||||
// For convenience, undefined and null are both considered types.
|
||||
let type = grip.type;
|
||||
if (["undefined", "null"].indexOf(type + "") != -1) {
|
||||
if (type == "undefined" || type == "null") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the descriptor represents a falsy value.
|
||||
*
|
||||
* @param object aDescriptor
|
||||
* The variable's descriptor.
|
||||
*/
|
||||
VariablesView.isFalsy = function VV_isFalsy(aDescriptor) {
|
||||
if (!aDescriptor || typeof aDescriptor != "object") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// As described in the remote debugger protocol, the value grip
|
||||
// must be contained in a 'value' property.
|
||||
let grip = aDescriptor.value;
|
||||
if (typeof grip != "object") {
|
||||
return !grip;
|
||||
}
|
||||
|
||||
// For convenience, undefined and null are both considered types.
|
||||
let type = grip.type;
|
||||
if (type == "undefined" || type == "null") {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -63,3 +63,16 @@
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.searchPanelTitle): This is the text that
|
||||
- appears in the filter panel popup as a description. -->
|
||||
<!ENTITY debuggerUI.searchPanelTitle "Operators">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.condBreakPanelTitle): This is the text that
|
||||
- appears in the conditional breakpoint panel popup as a description. -->
|
||||
<!ENTITY debuggerUI.condBreakPanelTitle "This breakpoint will stop execution only if the following expression is true">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.seMenuBreak): This is the text that
|
||||
- appears in the source editor context menu for adding a breakpoint. -->
|
||||
<!ENTITY debuggerUI.seMenuBreak "Add breakpoint">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.seMenuCondBreak): This is the text that
|
||||
- appears in the source editor context menu for adding a conditional
|
||||
- breakpoint. -->
|
||||
<!ENTITY debuggerUI.seMenuCondBreak "Add conditional breakpoint">
|
||||
|
@ -134,6 +134,7 @@ searchPanelVariable=Filter variables (%S)
|
||||
|
||||
# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that
|
||||
# are displayed in the breakpoints menu item popup.
|
||||
breakpointMenuItem.setConditional=Configure conditional breakpoint
|
||||
breakpointMenuItem.enableSelf=Enable breakpoint
|
||||
breakpointMenuItem.disableSelf=Disable breakpoint
|
||||
breakpointMenuItem.deleteSelf=Remove breakpoint
|
||||
|
@ -136,7 +136,7 @@
|
||||
|
||||
#stackframes {
|
||||
background-color: white;
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-stackframe {
|
||||
@ -154,14 +154,18 @@
|
||||
|
||||
#breakpoints {
|
||||
background-color: white;
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
#breakpoints > vbox:not(:empty) {
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.dbg-breakpoint:not(:last-child) {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-info {
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -170,6 +174,14 @@
|
||||
font: 8pt monospace;
|
||||
}
|
||||
|
||||
#conditional-breakpoint-panel .description {
|
||||
margin: -6px 0 8px 0;
|
||||
}
|
||||
|
||||
#conditional-breakpoint-panel textbox {
|
||||
margin: 0 0 -2px 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables view
|
||||
*/
|
||||
|
@ -138,7 +138,7 @@
|
||||
|
||||
#stackframes {
|
||||
background-color: white;
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-stackframe {
|
||||
@ -156,14 +156,18 @@
|
||||
|
||||
#breakpoints {
|
||||
background-color: white;
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
#breakpoints > vbox:not(:empty) {
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.dbg-breakpoint:not(:last-child) {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-info {
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -172,6 +176,14 @@
|
||||
font: 8pt monospace;
|
||||
}
|
||||
|
||||
#conditional-breakpoint-panel .description {
|
||||
margin: -6px 0 8px 0;
|
||||
}
|
||||
|
||||
#conditional-breakpoint-panel textbox {
|
||||
margin: 0 0 -2px 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables view
|
||||
*/
|
||||
|
@ -144,7 +144,7 @@
|
||||
|
||||
#stackframes {
|
||||
background-color: white;
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-stackframe {
|
||||
@ -162,14 +162,18 @@
|
||||
|
||||
#breakpoints {
|
||||
background-color: white;
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
#breakpoints > vbox:not(:empty) {
|
||||
min-height: 30px;
|
||||
min-height: 10px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.dbg-breakpoint:not(:last-child) {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-info {
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -178,6 +182,14 @@
|
||||
font: 8pt monospace;
|
||||
}
|
||||
|
||||
#conditional-breakpoint-panel .description {
|
||||
margin: -6px 0 8px 0;
|
||||
}
|
||||
|
||||
#conditional-breakpoint-panel textbox {
|
||||
margin: 0 0 -2px 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables view
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user