| // Any copyright is dedicated to the Public Domain. |
| // http://creativecommons.org/licenses/publicdomain/ |
| |
| //----------------------------------------------------------------------------- |
| 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"); |