/* * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/licenses/publicdomain/ */ //----------------------------------------------------------------------------- var BUGNUMBER = 577325; var summary = 'Implement the ES5 algorithm for processing function statements'; print(BUGNUMBER + ": " + summary); /************** * BEGIN TEST * **************/ var outer, desc; var isInShell = !("Window" in this); /////////////////////////////////////////////////// // Function definitions over accessor properties // /////////////////////////////////////////////////// var getCalled, setCalled; // configurable properties get blown away getCalled = false, setCalled = false; Object.defineProperty(this, "acc1", { get: function() { getCalled = true; throw "FAIL get 1"; }, set: function(v) { setCalled = true; throw "FAIL set 1 " + v; }, configurable: true, enumerable: false }); // does not throw outer = undefined; eval("function acc1() { throw 'FAIL redefined 1'; } outer = acc1;"); assertEq(getCalled, false); assertEq(setCalled, false); assertEq(typeof acc1, "function"); assertEq(acc1, outer); desc = Object.getOwnPropertyDescriptor(this, "acc1"); assertEq(desc.value, acc1); assertEq(desc.writable, true); assertEq(desc.enumerable, true); assertEq(desc.configurable, true); getCalled = false, setCalled = false; Object.defineProperty(this, "acc2", { get: function() { getCalled = true; throw "FAIL get 2"; }, set: function(v) { setCalled = true; throw "FAIL set 2 " + v; }, configurable: true, enumerable: true }); // does not throw outer = undefined; eval("function acc2() { throw 'FAIL redefined 2'; } outer = acc2;"); assertEq(getCalled, false); assertEq(setCalled, false); assertEq(typeof acc2, "function"); assertEq(acc2, outer); desc = Object.getOwnPropertyDescriptor(this, "acc2"); assertEq(desc.value, acc2); assertEq(desc.writable, true); assertEq(desc.enumerable, true); assertEq(desc.configurable, true); // non-configurable properties produce a TypeError. We only test this in shell, // since defining non-configurable properties on Window instances throws. if (isInShell) { getCalled = false, setCalled = false; Object.defineProperty(this, "acc3", { get: function() { getCalled = true; throw "FAIL get 3"; }, set: function(v) { setCalled = true; throw "FAIL set 3 " + v; }, configurable: false, enumerable: true }); outer = undefined; try { eval("function acc3() { throw 'FAIL redefined 3'; }; outer = acc3"); throw new Error("should have thrown trying to redefine global function " + "over a non-configurable, enumerable accessor"); } catch (e) { assertEq(e instanceof TypeError, true, "global function definition, when that function would overwrite " + "a non-configurable, enumerable accessor, must throw a TypeError " + "per ES5+errata: " + e); desc = Object.getOwnPropertyDescriptor(this, "acc3"); assertEq(typeof desc.get, "function"); assertEq(typeof desc.set, "function"); assertEq(desc.enumerable, true); assertEq(desc.configurable, false); assertEq(outer, undefined); assertEq(getCalled, false); assertEq(setCalled, false); } getCalled = false, setCalled = false; Object.defineProperty(this, "acc4", { get: function() { getCalled = true; throw "FAIL get 4"; }, set: function(v) { setCalled = true; throw "FAIL set 4 " + v; }, configurable: false, enumerable: false }); outer = undefined; try { eval("function acc4() { throw 'FAIL redefined 4'; }; outer = acc4"); throw new Error("should have thrown trying to redefine global function " + "over a non-configurable, non-enumerable accessor"); } catch (e) { assertEq(e instanceof TypeError, true, "global function definition, when that function would overwrite " + "a non-configurable, non-enumerable accessor, must throw a " + "TypeError per ES5+errata: " + e); desc = Object.getOwnPropertyDescriptor(this, "acc4"); assertEq(typeof desc.get, "function"); assertEq(typeof desc.set, "function"); assertEq(desc.enumerable, false); assertEq(desc.configurable, false); assertEq(outer, undefined); assertEq(getCalled, false); assertEq(setCalled, false); } } /////////////////////////////////////////////// // Function definitions over data properties // /////////////////////////////////////////////// // configurable properties, regardless of other attributes, get blown away Object.defineProperty(this, "data1", { configurable: true, enumerable: true, writable: true, value: "data1" }); outer = undefined; eval("function data1() { return 'data1 function'; } outer = data1;"); assertEq(typeof data1, "function"); assertEq(data1, outer); desc = Object.getOwnPropertyDescriptor(this, "data1"); assertEq(desc.configurable, true); assertEq(desc.enumerable, true); assertEq(desc.writable, true); assertEq(desc.value, data1); Object.defineProperty(this, "data2", { configurable: true, enumerable: true, writable: false, value: "data2" }); outer = undefined; eval("function data2() { return 'data2 function'; } outer = data2;"); assertEq(typeof data2, "function"); assertEq(data2, outer); desc = Object.getOwnPropertyDescriptor(this, "data2"); assertEq(desc.configurable, true); assertEq(desc.enumerable, true); assertEq(desc.writable, true); assertEq(desc.value, data2); Object.defineProperty(this, "data3", { configurable: true, enumerable: false, writable: true, value: "data3" }); outer = undefined; eval("function data3() { return 'data3 function'; } outer = data3;"); assertEq(typeof data3, "function"); assertEq(data3, outer); desc = Object.getOwnPropertyDescriptor(this, "data3"); assertEq(desc.configurable, true); assertEq(desc.enumerable, true); assertEq(desc.writable, true); assertEq(desc.value, data3); Object.defineProperty(this, "data4", { configurable: true, enumerable: false, writable: false, value: "data4" }); outer = undefined; eval("function data4() { return 'data4 function'; } outer = data4;"); assertEq(typeof data4, "function"); assertEq(data4, outer); desc = Object.getOwnPropertyDescriptor(this, "data4"); assertEq(desc.value, data4); assertEq(desc.writable, true); assertEq(desc.enumerable, true); assertEq(desc.configurable, true); // non-configurable data properties are trickier. Again, we test these only in shell. if (isInShell) { Object.defineProperty(this, "data5", { configurable: false, enumerable: true, writable: true, value: "data5" }); outer = undefined; eval("function data5() { return 'data5 function'; } outer = data5;"); assertEq(typeof data5, "function"); assertEq(data5, outer); desc = Object.getOwnPropertyDescriptor(this, "data5"); assertEq(desc.configurable, false); assertEq(desc.enumerable, true); assertEq(desc.writable, true); assertEq(desc.value, data5); Object.defineProperty(this, "data6", { configurable: false, enumerable: true, writable: false, value: "data6" }); outer = undefined; try { eval("function data6() { return 'data6 function'; } outer = data6;"); throw new Error("should have thrown trying to redefine global function " + "over a non-configurable, enumerable, non-writable accessor"); } catch (e) { assertEq(e instanceof TypeError, true, "global function definition, when that function would overwrite " + "a non-configurable, enumerable, non-writable data property, must " + "throw a TypeError per ES5+errata: " + e); assertEq(data6, "data6"); assertEq(outer, undefined); desc = Object.getOwnPropertyDescriptor(this, "data6"); assertEq(desc.configurable, false); assertEq(desc.enumerable, true); assertEq(desc.writable, false); assertEq(desc.value, "data6"); } Object.defineProperty(this, "data7", { configurable: false, enumerable: false, writable: true, value: "data7" }); outer = undefined; try { eval("function data7() { return 'data7 function'; } outer = data7;"); throw new Error("should have thrown trying to redefine global function " + "over a non-configurable, non-enumerable, writable data" + "property"); } catch (e) { assertEq(e instanceof TypeError, true, "global function definition, when that function would overwrite " + "a non-configurable, non-enumerable, writable data property, must " + "throw a TypeError per ES5+errata: " + e); assertEq(data7, "data7"); assertEq(outer, undefined); desc = Object.getOwnPropertyDescriptor(this, "data7"); assertEq(desc.configurable, false); assertEq(desc.enumerable, false); assertEq(desc.writable, true); assertEq(desc.value, "data7"); } Object.defineProperty(this, "data8", { configurable: false, enumerable: false, writable: false, value: "data8" }); outer = undefined; try { eval("function data8() { return 'data8 function'; } outer = data8;"); throw new Error("should have thrown trying to redefine global function " + "over a non-configurable, non-enumerable, non-writable data" + "property"); } catch (e) { assertEq(e instanceof TypeError, true, "global function definition, when that function would overwrite " + "a non-configurable, non-enumerable, non-writable data property, " + "must throw a TypeError per ES5+errata: " + e); assertEq(data8, "data8"); assertEq(outer, undefined); desc = Object.getOwnPropertyDescriptor(this, "data8"); assertEq(desc.configurable, false); assertEq(desc.enumerable, false); assertEq(desc.writable, false); assertEq(desc.value, "data8"); } } /******************************************************************************/ if (typeof reportCompare === "function") reportCompare(true, true); print("All tests passed!");