mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Bug 760370 - Visually distinguish non-extensible objects; r=vporof
This commit is contained in:
parent
816e6cfe91
commit
914800933b
@ -33,6 +33,7 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
browser_dbg_propertyview-09.js \
|
||||
browser_dbg_propertyview-10.js \
|
||||
browser_dbg_propertyview-11.js \
|
||||
browser_dbg_propertyview-12.js \
|
||||
browser_dbg_propertyview-edit-value.js \
|
||||
browser_dbg_propertyview-edit-watch.js \
|
||||
browser_dbg_propertyview-data-big.js \
|
||||
|
@ -0,0 +1,95 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// This test checks that we properly set the frozen, sealed, and non-extensbile
|
||||
// attributes on variables so that the F/S/N is shown in the variables view.
|
||||
|
||||
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.panelWin;
|
||||
|
||||
testFSN();
|
||||
});
|
||||
}
|
||||
|
||||
function testFSN() {
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function _onFetchedVariables() {
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", _onFetchedVariables, false);
|
||||
runTest();
|
||||
}, false);
|
||||
|
||||
gDebuggee.eval("(" + function () {
|
||||
var frozen = Object.freeze({});
|
||||
var sealed = Object.seal({});
|
||||
var nonExtensible = Object.preventExtensions({});
|
||||
var extensible = {};
|
||||
var string = "foo bar baz";
|
||||
|
||||
debugger;
|
||||
} + "())");
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
let hasNoneTester = function (aVariable) {
|
||||
ok(!aVariable.hasAttribute("frozen"),
|
||||
"The variable should not be frozen");
|
||||
ok(!aVariable.hasAttribute("sealed"),
|
||||
"The variable should not be sealed");
|
||||
ok(!aVariable.hasAttribute("non-extensible"),
|
||||
"The variable should be extensible");
|
||||
};
|
||||
|
||||
let testers = {
|
||||
frozen: function (aVariable) {
|
||||
ok(aVariable.hasAttribute("frozen"),
|
||||
"The variable should be frozen")
|
||||
},
|
||||
sealed: function (aVariable) {
|
||||
ok(aVariable.hasAttribute("sealed"),
|
||||
"The variable should be sealed")
|
||||
},
|
||||
nonExtensible: function (aVariable) {
|
||||
ok(aVariable.hasAttribute("non-extensible"),
|
||||
"The variable should be non-extensible")
|
||||
},
|
||||
extensible: hasNoneTester,
|
||||
string: hasNoneTester,
|
||||
arguments: hasNoneTester,
|
||||
this: hasNoneTester
|
||||
};
|
||||
|
||||
let variables = gDebugger.DebuggerView.Variables._parent
|
||||
.querySelectorAll(".variable-or-property");
|
||||
|
||||
for (let v of variables) {
|
||||
let name = v.querySelector(".name").getAttribute("value");
|
||||
let tester = testers[name];
|
||||
delete testers[name];
|
||||
ok(tester, "We should have a tester for the '" + name + "' variable.");
|
||||
tester(v);
|
||||
}
|
||||
|
||||
is(Object.keys(testers).length, 0,
|
||||
"We should have run and removed all the testers.");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
});
|
@ -2364,21 +2364,15 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
|
||||
let tooltip = document.createElement("tooltip");
|
||||
tooltip.id = "tooltip-" + this._idString;
|
||||
|
||||
let configurableLabel = document.createElement("label");
|
||||
let enumerableLabel = document.createElement("label");
|
||||
let writableLabel = document.createElement("label");
|
||||
let safeGetterLabel = document.createElement("label");
|
||||
configurableLabel.setAttribute("value", "configurable");
|
||||
enumerableLabel.setAttribute("value", "enumerable");
|
||||
writableLabel.setAttribute("value", "writable");
|
||||
safeGetterLabel.setAttribute("value", "native-getter");
|
||||
|
||||
tooltip.setAttribute("orient", "horizontal");
|
||||
tooltip.appendChild(configurableLabel);
|
||||
tooltip.appendChild(enumerableLabel);
|
||||
tooltip.appendChild(writableLabel);
|
||||
tooltip.appendChild(safeGetterLabel);
|
||||
|
||||
let labels = ["configurable", "enumerable", "writable", "native-getter",
|
||||
"frozen", "sealed", "non-extensible"];
|
||||
for (let label of labels) {
|
||||
let labelElement = document.createElement("label");
|
||||
labelElement.setAttribute("value", label);
|
||||
tooltip.appendChild(labelElement);
|
||||
}
|
||||
|
||||
this._target.appendChild(tooltip);
|
||||
this._target.setAttribute("tooltip", tooltip.id);
|
||||
@ -2408,14 +2402,27 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
if (this.ownerView.eval) {
|
||||
this._target.setAttribute("editable", "");
|
||||
}
|
||||
if (!descriptor.null && !descriptor.configurable) {
|
||||
this._target.setAttribute("non-configurable", "");
|
||||
}
|
||||
if (!descriptor.null && !descriptor.enumerable) {
|
||||
this._target.setAttribute("non-enumerable", "");
|
||||
}
|
||||
if (!descriptor.null && !descriptor.writable && !this.ownerView.getter && !this.ownerView.setter) {
|
||||
this._target.setAttribute("non-writable", "");
|
||||
if (!descriptor.null) {
|
||||
if (!descriptor.configurable) {
|
||||
this._target.setAttribute("non-configurable", "");
|
||||
}
|
||||
if (!descriptor.enumerable) {
|
||||
this._target.setAttribute("non-enumerable", "");
|
||||
}
|
||||
if (!descriptor.writable && !this.ownerView.getter && !this.ownerView.setter) {
|
||||
this._target.setAttribute("non-writable", "");
|
||||
}
|
||||
if (descriptor.value && typeof descriptor.value == "object") {
|
||||
if (descriptor.value.frozen) {
|
||||
this._target.setAttribute("frozen", "");
|
||||
}
|
||||
if (descriptor.value.sealed) {
|
||||
this._target.setAttribute("sealed", "");
|
||||
}
|
||||
if (!descriptor.value.extensible) {
|
||||
this._target.setAttribute("non-extensible", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (descriptor && "getterValue" in descriptor) {
|
||||
this._target.setAttribute("safe-getter", "");
|
||||
|
@ -531,6 +531,21 @@
|
||||
text-shadow: 0 0 8px #fcc;
|
||||
}
|
||||
|
||||
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
|
||||
content: "N";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.variable-or-property[sealed]:not([non-writable]) > .title:after {
|
||||
content: "S";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.variable-or-property[frozen]:not([non-writable]) > .title:after {
|
||||
content: "F";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Variables and properties tooltips */
|
||||
|
||||
.variable-or-property > tooltip > label {
|
||||
@ -543,7 +558,10 @@
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter] {
|
||||
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter],
|
||||
.variable-or-property:not([non-extensible]) > tooltip > label[value=non-extensible],
|
||||
.variable-or-property:not([frozen]) > tooltip > label[value=frozen],
|
||||
.variable-or-property:not([sealed]) > tooltip > label[value=sealed] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -531,6 +531,21 @@
|
||||
text-shadow: 0 0 8px #fcc;
|
||||
}
|
||||
|
||||
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
|
||||
content: "N";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.variable-or-property[sealed]:not([non-writable]) > .title:after {
|
||||
content: "S";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.variable-or-property[frozen]:not([non-writable]) > .title:after {
|
||||
content: "F";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Variables and properties tooltips */
|
||||
|
||||
.variable-or-property > tooltip > label {
|
||||
@ -543,7 +558,10 @@
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter] {
|
||||
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter],
|
||||
.variable-or-property:not([non-extensible]) > tooltip > label[value=non-extensible],
|
||||
.variable-or-property:not([frozen]) > tooltip > label[value=frozen],
|
||||
.variable-or-property:not([sealed]) > tooltip > label[value=sealed] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -534,6 +534,21 @@
|
||||
text-shadow: 0 0 8px #fcc;
|
||||
}
|
||||
|
||||
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
|
||||
content: "N";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.variable-or-property[sealed]:not([non-writable]) > .title:after {
|
||||
content: "S";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.variable-or-property[frozen]:not([non-writable]) > .title:after {
|
||||
content: "F";
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Variables and properties tooltips */
|
||||
|
||||
.variable-or-property > tooltip > label {
|
||||
@ -546,7 +561,10 @@
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter] {
|
||||
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter],
|
||||
.variable-or-property:not([non-extensible]) > tooltip > label[value=non-extensible],
|
||||
.variable-or-property:not([frozen]) > tooltip > label[value=frozen],
|
||||
.variable-or-property:not([sealed]) > tooltip > label[value=sealed] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -1437,6 +1437,10 @@ GripClient.prototype = {
|
||||
|
||||
valid: true,
|
||||
|
||||
get isFrozen() this._grip.frozen,
|
||||
get isSealed() this._grip.sealed,
|
||||
get isExtensible() this._grip.extensible,
|
||||
|
||||
/**
|
||||
* Request the names of a function's formal parameters.
|
||||
*
|
||||
|
@ -1481,9 +1481,14 @@ ObjectActor.prototype = {
|
||||
* Returns a grip for this actor for returning in a protocol message.
|
||||
*/
|
||||
grip: function OA_grip() {
|
||||
let g = { "type": "object",
|
||||
"class": this.obj.class,
|
||||
"actor": this.actorID };
|
||||
let g = {
|
||||
"type": "object",
|
||||
"class": this.obj.class,
|
||||
"actor": this.actorID,
|
||||
"extensible": this.obj.isExtensible(),
|
||||
"frozen": this.obj.isFrozen(),
|
||||
"sealed": this.obj.isSealed()
|
||||
};
|
||||
|
||||
// Add additional properties for functions.
|
||||
if (this.obj.class === "Function") {
|
||||
@ -1780,7 +1785,7 @@ ObjectActor.prototype.requestTypes = {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a pause-scoped actor for the specified object.
|
||||
* Creates a pause-scoped actor for the specified object.
|
||||
* @see ObjectActor
|
||||
*/
|
||||
function PauseScopedObjectActor()
|
||||
|
57
toolkit/devtools/server/tests/unit/test_objectgrips-05.js
Normal file
57
toolkit/devtools/server/tests/unit/test_objectgrips-05.js
Normal file
@ -0,0 +1,57 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* This test checks that frozen objects report themselves as frozen in their
|
||||
* grip.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-grips");
|
||||
gDebuggee.eval(function stopMe(arg1, arg2) {
|
||||
debugger;
|
||||
}.toString());
|
||||
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestTabAndResume(gClient, "test-grips", function(aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_object_grip();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_object_grip()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let obj1 = aPacket.frame.arguments[0];
|
||||
do_check_true(obj1.frozen);
|
||||
|
||||
let obj1Client = gThreadClient.pauseGrip(obj1);
|
||||
do_check_true(obj1Client.isFrozen);
|
||||
|
||||
let obj2 = aPacket.frame.arguments[1];
|
||||
do_check_false(obj2.frozen);
|
||||
|
||||
let obj2Client = gThreadClient.pauseGrip(obj2);
|
||||
do_check_false(obj2Client.isFrozen);
|
||||
|
||||
gThreadClient.resume(_ => {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function () {
|
||||
let obj1 = {};
|
||||
Object.freeze(obj1);
|
||||
stopMe(obj1, {});
|
||||
} + "())");
|
||||
}
|
||||
|
57
toolkit/devtools/server/tests/unit/test_objectgrips-06.js
Normal file
57
toolkit/devtools/server/tests/unit/test_objectgrips-06.js
Normal file
@ -0,0 +1,57 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* This test checks that sealed objects report themselves as sealed in their
|
||||
* grip.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-grips");
|
||||
gDebuggee.eval(function stopMe(arg1, arg2) {
|
||||
debugger;
|
||||
}.toString());
|
||||
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestTabAndResume(gClient, "test-grips", function(aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_object_grip();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_object_grip()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let obj1 = aPacket.frame.arguments[0];
|
||||
do_check_true(obj1.sealed);
|
||||
|
||||
let obj1Client = gThreadClient.pauseGrip(obj1);
|
||||
do_check_true(obj1Client.isSealed);
|
||||
|
||||
let obj2 = aPacket.frame.arguments[1];
|
||||
do_check_false(obj2.sealed);
|
||||
|
||||
let obj2Client = gThreadClient.pauseGrip(obj2);
|
||||
do_check_false(obj2Client.isSealed);
|
||||
|
||||
gThreadClient.resume(_ => {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function () {
|
||||
let obj1 = {};
|
||||
Object.seal(obj1);
|
||||
stopMe(obj1, {});
|
||||
} + "())");
|
||||
}
|
||||
|
65
toolkit/devtools/server/tests/unit/test_objectgrips-07.js
Normal file
65
toolkit/devtools/server/tests/unit/test_objectgrips-07.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* This test checks that objects which are not extensible report themselves as
|
||||
* such.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-grips");
|
||||
gDebuggee.eval(function stopMe(arg1, arg2, arg3, arg4) {
|
||||
debugger;
|
||||
}.toString());
|
||||
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestTabAndResume(gClient, "test-grips", function(aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_object_grip();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_object_grip()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let [f, s, ne, e] = aPacket.frame.arguments;
|
||||
let [fClient, sClient, neClient, eClient] = aPacket.frame.arguments.map(
|
||||
a => gThreadClient.pauseGrip(a));
|
||||
|
||||
do_check_false(f.extensible);
|
||||
do_check_false(fClient.isExtensible);
|
||||
|
||||
do_check_false(s.extensible);
|
||||
do_check_false(sClient.isExtensible);
|
||||
|
||||
do_check_false(ne.extensible);
|
||||
do_check_false(neClient.isExtensible);
|
||||
|
||||
do_check_true(e.extensible);
|
||||
do_check_true(eClient.isExtensible);
|
||||
|
||||
gThreadClient.resume(_ => {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function () {
|
||||
let f = {};
|
||||
Object.freeze(f);
|
||||
let s = {};
|
||||
Object.seal(s);
|
||||
let ne = {};
|
||||
Object.preventExtensions(ne);
|
||||
stopMe(f, s, ne, {});
|
||||
} + "())");
|
||||
}
|
||||
|
@ -95,6 +95,9 @@ reason = bug 820380
|
||||
[test_objectgrips-02.js]
|
||||
[test_objectgrips-03.js]
|
||||
[test_objectgrips-04.js]
|
||||
[test_objectgrips-05.js]
|
||||
[test_objectgrips-06.js]
|
||||
[test_objectgrips-07.js]
|
||||
[test_interrupt.js]
|
||||
[test_stepping-01.js]
|
||||
[test_stepping-02.js]
|
||||
|
Loading…
Reference in New Issue
Block a user