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