Source code

Revision control

Copy as Markdown

Other Tools

// Any copyright is dedicated to the Public Domain.
//-----------------------------------------------------------------------------
var BUGNUMBER = 715821;
var summary = "Implement __define[GS]etter__ using Object.defineProperty";
print(BUGNUMBER + ": " + summary);
/*************
* UTILITIES *
*************/
function s(desc)
{
if (typeof desc === "undefined")
return "<undefined>";
assertEq(typeof desc, "object");
assertEq(desc !== null, true);
var str = "<enumerable: <" + desc.enumerable + ">, " +
" configurable: <" + desc.configurable + ">,";
if (desc.hasOwnProperty("value"))
{
return str +
" value: <" + desc.value + ">," +
" writable: <" + desc.writable + ">>";
}
return str +
" get: <" + desc.get + ">," +
" set: <" + desc.set + ">>";
}
function checkField(field, desc, expected)
{
var present = desc.hasOwnProperty(field);
assertEq(present, expected.hasOwnProperty(field),
field + " presence mismatch (got " + s(desc) + ", expected " + s(expected) + ")");
if (present)
{
assertEq(desc[field], expected[field],
field + " value mismatch (got " + s(desc) + ", expected " + s(expected) + ")");
}
}
function check(obj, prop, expected)
{
var desc = Object.getOwnPropertyDescriptor(obj, prop);
assertEq(typeof desc, typeof expected,
"type mismatch (got " + s(desc) + ", expected " + s(expected) + ")");
assertEq(desc.hasOwnProperty("get"), desc.hasOwnProperty("set"),
"bad descriptor: " + s(desc));
assertEq(desc.hasOwnProperty("value"), desc.hasOwnProperty("writable"),
"bad descriptor: " + s(desc));
assertEq(desc.hasOwnProperty("get"), !desc.hasOwnProperty("value"),
"bad descriptor: " + s(desc));
checkField("get", desc, expected);
checkField("set", desc, expected);
checkField("value", desc, expected);
checkField("writable", desc, expected);
checkField("enumerable", desc, expected);
checkField("configurable", desc, expected);
}
function expectTypeError(f)
{
try
{
f();
throw new Error("no error thrown");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"wrong error thrown: got " + e + ", not a TypeError");
}
}
/**************
* BEGIN TEST *
**************/
// Adding a new getter, overwriting an existing one
function g1() { }
var gobj = {};
gobj.__defineGetter__("foo", g1);
check(gobj, "foo", { get: g1, set: undefined, enumerable: true, configurable: true });
function g2() { }
gobj.__defineGetter__("foo", g2);
check(gobj, "foo", { get: g2, set: undefined, enumerable: true, configurable: true });
/******************************************************************************/
// Adding a new setter, overwriting an existing one
function s1() { }
var sobj = {};
sobj.__defineSetter__("bar", s1);
check(sobj, "bar", { get: undefined, set: s1, enumerable: true, configurable: true });
function s2() { }
sobj.__defineSetter__("bar", s2);
check(sobj, "bar", { get: undefined, set: s2, enumerable: true, configurable: true });
/******************************************************************************/
// Adding a new getter, then adding a setter
// Changing an existing accessor's enumerability, then "null"-changing the accessor
// Changing an accessor's configurability, then "null"-changing and real-changing the accessor
function g3() { }
var gsobj = {};
gsobj.__defineGetter__("baz", g3);
check(gsobj, "baz", { get: g3, set: undefined, enumerable: true, configurable: true });
function s3() { }
gsobj.__defineSetter__("baz", s3);
check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: true });
Object.defineProperty(gsobj, "baz", { enumerable: false });
check(gsobj, "baz", { get: g3, set: s3, enumerable: false, configurable: true });
gsobj.__defineGetter__("baz", g3);
check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: true });
Object.defineProperty(gsobj, "baz", { enumerable: false });
check(gsobj, "baz", { get: g3, set: s3, enumerable: false, configurable: true });
gsobj.__defineSetter__("baz", s3);
check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: true });
Object.defineProperty(gsobj, "baz", { configurable: false });
expectTypeError(function() { gsobj.__defineSetter__("baz", s2); });
expectTypeError(function() { gsobj.__defineSetter__("baz", s3); });
check(gsobj, "baz", { get: g3, set: s3, enumerable: true, configurable: false });
/******************************************************************************/
// Adding a new setter, then adding a getter
// Changing an existing accessor's enumerability, then "null"-changing the accessor
// Changing an accessor's configurability, then "null"-changing and real-changing the accessor
function s4() { }
var sgobj = {};
sgobj.__defineSetter__("baz", s4);
check(sgobj, "baz", { get: undefined, set: s4, enumerable: true, configurable: true });
function g4() { }
sgobj.__defineGetter__("baz", g4);
check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: true });
Object.defineProperty(sgobj, "baz", { enumerable: false });
check(sgobj, "baz", { get: g4, set: s4, enumerable: false, configurable: true });
sgobj.__defineSetter__("baz", s4);
check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: true });
Object.defineProperty(sgobj, "baz", { enumerable: false });
check(sgobj, "baz", { get: g4, set: s4, enumerable: false, configurable: true });
sgobj.__defineSetter__("baz", s4);
check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: true });
Object.defineProperty(sgobj, "baz", { configurable: false });
expectTypeError(function() { sgobj.__defineGetter__("baz", g3); });
expectTypeError(function() { sgobj.__defineSetter__("baz", s4); });
check(sgobj, "baz", { get: g4, set: s4, enumerable: true, configurable: false });
/******************************************************************************/
// Adding a getter over a writable data property
function g5() { }
var gover = { quux: 17 };
check(gover, "quux", { value: 17, writable: true, enumerable: true, configurable: true });
gover.__defineGetter__("quux", g5);
check(gover, "quux", { get: g5, set: undefined, enumerable: true, configurable: true });
/******************************************************************************/
// Adding a setter over a writable data property
function s5() { }
var sover = { quux: 17 };
check(sover, "quux", { value: 17, writable: true, enumerable: true, configurable: true });
sover.__defineSetter__("quux", s5);
check(sover, "quux", { get: undefined, set: s5, enumerable: true, configurable: true });
/******************************************************************************/
// Adding a getter over a non-writable data property
function g6() { }
var gnover = { eit: 17 };
check(gnover, "eit", { value: 17, writable: true, enumerable: true, configurable: true });
Object.defineProperty(gnover, "eit", { writable: false });
check(gnover, "eit", { value: 17, writable: false, enumerable: true, configurable: true });
gnover.__defineGetter__("eit", g6);
check(gnover, "eit", { get: g6, set: undefined, enumerable: true, configurable: true });
/******************************************************************************/
// Adding a setter over a non-writable data property
function s6() { }
var snover = { eit: 17 };
check(snover, "eit", { value: 17, writable: true, enumerable: true, configurable: true });
Object.defineProperty(snover, "eit", { writable: false });
check(snover, "eit", { value: 17, writable: false, enumerable: true, configurable: true });
snover.__defineSetter__("eit", s6);
check(snover, "eit", { get: undefined, set: s6, enumerable: true, configurable: true });
/******************************************************************************/
// Adding a getter over a non-configurable, writable data property
function g7() { }
var gncover = { moo: 17 };
check(gncover, "moo", { value: 17, writable: true, enumerable: true, configurable: true });
Object.defineProperty(gncover, "moo", { configurable: false });
check(gncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false });
expectTypeError(function() { gncover.__defineGetter__("moo", g7); });
check(gncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false });
/******************************************************************************/
// Adding a setter over a non-configurable, writable data property
function s7() { }
var sncover = { moo: 17 };
check(sncover, "moo", { value: 17, writable: true, enumerable: true, configurable: true });
Object.defineProperty(sncover, "moo", { configurable: false });
check(sncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false });
expectTypeError(function() { sncover.__defineSetter__("moo", s7); });
check(sncover, "moo", { value: 17, writable: true, enumerable: true, configurable: false });
/******************************************************************************/
// Adding a getter over a non-configurable, non-writable data property
function g8() { }
var gncwover = { fwoosh: 17 };
check(gncwover, "fwoosh", { value: 17, writable: true, enumerable: true, configurable: true });
Object.defineProperty(gncwover, "fwoosh", { writable: false, configurable: false });
check(gncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false });
expectTypeError(function() { gncwover.__defineGetter__("fwoosh", g7); });
check(gncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false });
/******************************************************************************/
// Adding a setter over a non-configurable, non-writable data property
function s8() { }
var sncwover = { fwoosh: 17 };
check(sncwover, "fwoosh", { value: 17, writable: true, enumerable: true, configurable: true });
Object.defineProperty(sncwover, "fwoosh", { writable: false, configurable: false });
check(sncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false });
expectTypeError(function() { sncwover.__defineSetter__("fwoosh", s7); });
check(sncwover, "fwoosh", { value: 17, writable: false, enumerable: true, configurable: false });
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");