Bug 760370 - Visually distinguish non-extensible objects; r=vporof

This commit is contained in:
Nick Fitzgerald 2013-05-29 19:47:00 +03:00
Родитель 816e6cfe91
Коммит 914800933b
12 изменённых файлов: 377 добавлений и 29 удалений

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

@ -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()

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

@ -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, {});
} + "())");
}

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

@ -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, {});
} + "())");
}

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

@ -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]