| // |reftest| skip -- not a test. |
| // Any copyright is dedicated to the Public Domain. |
| // http://creativecommons.org/licenses/publicdomain/ |
| |
| assertEq("defineProperty" in Object, true); |
| assertEq(Object.defineProperty.length, 3); |
| |
| /* |
| * Disable an assertion that is pathologically slow given the exhaustiveness of |
| * these tests. |
| */ |
| if (typeof enableStackWalkingAssertion === "function") |
| enableStackWalkingAssertion(false); |
| |
| if (!Object.prototype.toSource) |
| { |
| Object.defineProperty(Object.prototype, "toSource", |
| { |
| value: function toSource() |
| { |
| if (this instanceof RegExp) |
| { |
| var v = "new RegExp(" + uneval(this.source); |
| var f = (this.multiline ? "m" : "") + |
| (this.global ? "g" : "") + |
| (this.ignoreCase ? "i" : ""); |
| return v + (f ? ", '" + f + "'" : "") + ")"; |
| } |
| return JSON.stringify(this); |
| }, |
| enumerable: false, |
| configurable: true, |
| writable: true |
| }); |
| } |
| if (!("uneval" in this)) |
| { |
| Object.defineProperty(this, "uneval", |
| { |
| value: function uneval(v) |
| { |
| if (v === null) |
| return "null"; |
| if (typeof v === "object") |
| return v.toSource(); |
| if (typeof v === "string") |
| { |
| v = JSON.stringify({v:v}); |
| return v.substring(5, v.length - 1); |
| } |
| return "" + v; |
| }, |
| enumerable: false, |
| configurable: true, |
| writable: true |
| }); |
| } |
| |
| // reimplemented for the benefit of engines which don't have this helper |
| function assertEq(v1, v2, m) |
| { |
| if (!SameValue(v1, v2)) |
| { |
| throw "assertion failed: " + |
| "got " + uneval(v1) + ", expected " + uneval(v2) + |
| (m ? ": " + m : ""); |
| } |
| } |
| |
| function SameValue(v1, v2) |
| { |
| if (v1 === 0 && v2 === 0) |
| return 1 / v1 === 1 / v2; |
| if (v1 !== v1 && v2 !== v2) |
| return true; |
| return v1 === v2; |
| } |
| |
| function PropertyDescriptor(pd) |
| { |
| if (pd) |
| this.update(pd); |
| } |
| PropertyDescriptor.prototype.update = function update(pd) |
| { |
| if ("get" in pd) |
| this.get = pd.get; |
| if ("set" in pd) |
| this.set = pd.set; |
| if ("configurable" in pd) |
| this.configurable = pd.configurable; |
| if ("writable" in pd) |
| this.writable = pd.writable; |
| if ("enumerable" in pd) |
| this.enumerable = pd.enumerable; |
| if ("value" in pd) |
| this.value = pd.value; |
| }; |
| PropertyDescriptor.prototype.convertToDataDescriptor = function convertToDataDescriptor() |
| { |
| delete this.get; |
| delete this.set; |
| this.writable = false; |
| this.value = undefined; |
| }; |
| PropertyDescriptor.prototype.convertToAccessorDescriptor = function convertToAccessorDescriptor() |
| { |
| delete this.writable; |
| delete this.value; |
| this.get = undefined; |
| this.set = undefined; |
| }; |
| |
| function compareDescriptors(d1, d2) |
| { |
| if (d1 === undefined) |
| { |
| assertEq(d2, undefined, "non-descriptors"); |
| return; |
| } |
| if (d2 === undefined) |
| { |
| assertEq(true, false, "descriptor-equality mismatch: " + uneval(d1) + ", " + uneval(d2)); |
| return; |
| } |
| |
| var props = ["value", "get", "set", "enumerable", "configurable", "writable"]; |
| for (var i = 0, sz = props.length; i < sz; i++) |
| { |
| var p = props[i]; |
| assertEq(p in d1, p in d2, p + " different in d1/d2"); |
| if (p in d1) |
| assertEq(d1[p], d2[p], p); |
| } |
| } |
| |
| function examine(desc, field, allowDefault) |
| { |
| if (field in desc) |
| return desc[field]; |
| assertEq(allowDefault, true, "reimplementation error"); |
| switch (field) |
| { |
| case "value": |
| case "get": |
| case "set": |
| return undefined; |
| case "writable": |
| case "enumerable": |
| case "configurable": |
| return false; |
| default: |
| assertEq(true, false, "bad field name: " + field); |
| } |
| } |
| |
| function IsAccessorDescriptor(desc) |
| { |
| if (!desc) |
| return false; |
| if (!("get" in desc) && !("set" in desc)) |
| return false; |
| return true; |
| } |
| |
| function IsDataDescriptor(desc) |
| { |
| if (!desc) |
| return false; |
| if (!("value" in desc) && !("writable" in desc)) |
| return false; |
| return true; |
| } |
| |
| function IsGenericDescriptor(desc) |
| { |
| if (!desc) |
| return false; |
| if (!IsAccessorDescriptor(desc) && !IsDataDescriptor(desc)) |
| return true; |
| return false; |
| } |
| |
| |
| |
| function CustomObject() |
| { |
| this.properties = {}; |
| this.extensible = true; |
| } |
| CustomObject.prototype = |
| { |
| _reject: function _reject(throwing, msg) |
| { |
| if (throwing) |
| throw new TypeError(msg + "; rejected!"); |
| return false; |
| }, |
| defineOwnProperty: function defineOwnProperty(propname, desc, throwing) |
| { |
| assertEq(typeof propname, "string", "non-string propname"); |
| |
| // Step 1. |
| var current = this.properties[propname]; |
| |
| // Step 2. |
| var extensible = this.extensible; |
| |
| // Step 3. |
| if (current === undefined && !extensible) |
| return this._reject(throwing, "object not extensible"); |
| |
| // Step 4. |
| if (current === undefined && extensible) |
| { |
| var p; |
| // Step 4(a). |
| if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) |
| { |
| p = new PropertyDescriptor(); |
| p.value = examine(desc, "value", true); |
| p.writable = examine(desc, "writable", true); |
| p.enumerable = examine(desc, "enumerable", true); |
| p.configurable = examine(desc, "configurable", true); |
| } |
| // Step 4(b). |
| else |
| { |
| p = new PropertyDescriptor(); |
| p.get = examine(desc, "get", true); |
| p.set = examine(desc, "set", true); |
| p.enumerable = examine(desc, "enumerable", true); |
| p.configurable = examine(desc, "configurable", true); |
| } |
| |
| this.properties[propname] = p; |
| |
| // Step 4(c). |
| return true; |
| } |
| |
| // Step 5. |
| if (!("value" in desc) && !("get" in desc) && !("set" in desc) && |
| !("writable" in desc) && !("enumerable" in desc) && |
| !("configurable" in desc)) |
| { |
| return; |
| } |
| |
| // Step 6. |
| do |
| { |
| if ("value" in desc) |
| { |
| if (!("value" in current) || !SameValue(desc.value, current.value)) |
| break; |
| } |
| if ("get" in desc) |
| { |
| if (!("get" in current) || !SameValue(desc.get, current.get)) |
| break; |
| } |
| if ("set" in desc) |
| { |
| if (!("set" in current) || !SameValue(desc.set, current.set)) |
| break; |
| } |
| if ("writable" in desc) |
| { |
| if (!("writable" in current) || |
| !SameValue(desc.writable, current.writable)) |
| { |
| break; |
| } |
| } |
| if ("enumerable" in desc) |
| { |
| if (!("enumerable" in current) || |
| !SameValue(desc.enumerable, current.enumerable)) |
| { |
| break; |
| } |
| } |
| if ("configurable" in desc) |
| { |
| if (!("configurable" in current) || |
| !SameValue(desc.configurable, current.configurable)) |
| { |
| break; |
| } |
| } |
| |
| // all fields in desc also in current, with the same values |
| return true; |
| } |
| while (false); |
| |
| // Step 7. |
| if (!examine(current, "configurable")) |
| { |
| if ("configurable" in desc && examine(desc, "configurable")) |
| return this._reject(throwing, "can't make configurable again"); |
| if ("enumerable" in desc && |
| examine(current, "enumerable") !== examine(desc, "enumerable")) |
| { |
| return this._reject(throwing, "can't change enumerability"); |
| } |
| } |
| |
| // Step 8. |
| if (IsGenericDescriptor(desc)) |
| { |
| // do nothing |
| } |
| // Step 9. |
| else if (IsDataDescriptor(current) !== IsDataDescriptor(desc)) |
| { |
| // Step 9(a). |
| if (!examine(current, "configurable")) |
| return this._reject(throwing, "can't change unconfigurable descriptor's type"); |
| // Step 9(b). |
| if (IsDataDescriptor(current)) |
| current.convertToAccessorDescriptor(); |
| // Step 9(c). |
| else |
| current.convertToDataDescriptor(); |
| } |
| // Step 10. |
| else if (IsDataDescriptor(current) && IsDataDescriptor(desc)) |
| { |
| // Step 10(a) |
| if (!examine(current, "configurable")) |
| { |
| // Step 10(a).i. |
| if (!examine(current, "writable") && |
| "writable" in desc && examine(desc, "writable")) |
| { |
| return this._reject(throwing, "can't make data property writable again"); |
| } |
| // Step 10(a).ii. |
| if (!examine(current, "writable")) |
| { |
| if ("value" in desc && |
| !SameValue(examine(desc, "value"), examine(current, "value"))) |
| { |
| return this._reject(throwing, "can't change value if not writable"); |
| } |
| } |
| } |
| // Step 10(b). |
| else |
| { |
| assertEq(examine(current, "configurable"), true, |
| "spec bug step 10(b)"); |
| } |
| } |
| // Step 11. |
| else |
| { |
| assertEq(IsAccessorDescriptor(current) && IsAccessorDescriptor(desc), |
| true, |
| "spec bug"); |
| |
| // Step 11(a). |
| if (!examine(current, "configurable")) |
| { |
| // Step 11(a).i. |
| if ("set" in desc && |
| !SameValue(examine(desc, "set"), examine(current, "set"))) |
| { |
| return this._reject(throwing, "can't change setter if not configurable"); |
| } |
| // Step 11(a).ii. |
| if ("get" in desc && |
| !SameValue(examine(desc, "get"), examine(current, "get"))) |
| { |
| return this._reject(throwing, "can't change getter if not configurable"); |
| } |
| } |
| } |
| |
| // Step 12. |
| current.update(desc); |
| |
| // Step 13. |
| return true; |
| } |
| }; |
| |
| function IsCallable(v) |
| { |
| return typeof v === "undefined" || typeof v === "function"; |
| } |
| |
| var NativeTest = |
| { |
| newObject: function newObject() |
| { |
| return {}; |
| }, |
| defineProperty: function defineProperty(obj, propname, propdesc) |
| { |
| Object.defineProperty(obj, propname, propdesc); |
| }, |
| getDescriptor: function getDescriptor(obj, propname) |
| { |
| return Object.getOwnPropertyDescriptor(obj, propname); |
| } |
| }; |
| |
| var ReimplTest = |
| { |
| newObject: function newObject() |
| { |
| return new CustomObject(); |
| }, |
| defineProperty: function defineProperty(obj, propname, propdesc) |
| { |
| assertEq(obj instanceof CustomObject, true, "obj not instanceof CustomObject"); |
| if ("get" in propdesc || "set" in propdesc) |
| { |
| if ("value" in propdesc || "writable" in propdesc) |
| throw new TypeError("get/set and value/writable"); |
| if (!IsCallable(propdesc.get)) |
| throw new TypeError("get defined, uncallable"); |
| if (!IsCallable(propdesc.set)) |
| throw new TypeError("set defined, uncallable"); |
| } |
| return obj.defineOwnProperty(propname, propdesc, true); |
| }, |
| getDescriptor: function getDescriptor(obj, propname) |
| { |
| if (!(propname in obj.properties)) |
| return undefined; |
| |
| return new PropertyDescriptor(obj.properties[propname]); |
| } |
| }; |
| |
| var JSVAL_INT_MAX = Math.pow(2, 30) - 1; |
| var JSVAL_INT_MIN = -Math.pow(2, 30); |
| |
| |
| function isValidDescriptor(propdesc) |
| { |
| if ("get" in propdesc || "set" in propdesc) |
| { |
| if ("value" in propdesc || "writable" in propdesc) |
| return false; |
| |
| // We permit null here simply because this test's author believes the |
| // implementation may sometime be susceptible to making mistakes in this |
| // regard and would prefer to be cautious. |
| if (propdesc.get !== null && propdesc.get !== undefined && !IsCallable(propdesc.get)) |
| return false; |
| if (propdesc.set !== null && propdesc.set !== undefined && !IsCallable(propdesc.set)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| var OMIT = {}; |
| var VALUES = |
| [-Infinity, JSVAL_INT_MIN, -0, +0, 1.5, JSVAL_INT_MAX, Infinity, |
| NaN, "foo", "bar", null, undefined, true, false, {}, /a/, OMIT]; |
| var GETS = |
| [undefined, function get1() { return 1; }, function get2() { return 2; }, |
| null, 5, OMIT]; |
| var SETS = |
| [undefined, function set1() { return 1; }, function set2() { return 2; }, |
| null, 5, OMIT]; |
| var ENUMERABLES = [true, false, OMIT]; |
| var CONFIGURABLES = [true, false, OMIT]; |
| var WRITABLES = [true, false, OMIT]; |
| |
| function mapTestDescriptors(filter) |
| { |
| var descs = []; |
| var desc = {}; |
| |
| function put(field, value) |
| { |
| if (value !== OMIT) |
| desc[field] = value; |
| } |
| |
| VALUES.forEach(function(value) |
| { |
| GETS.forEach(function(get) |
| { |
| SETS.forEach(function(set) |
| { |
| ENUMERABLES.forEach(function(enumerable) |
| { |
| CONFIGURABLES.forEach(function(configurable) |
| { |
| WRITABLES.forEach(function(writable) |
| { |
| desc = {}; |
| put("value", value); |
| put("get", get); |
| put("set", set); |
| put("enumerable", enumerable); |
| put("configurable", configurable); |
| put("writable", writable); |
| if (filter(desc)) |
| descs.push(desc); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| return descs; |
| } |
| |
| var ALL_DESCRIPTORS = mapTestDescriptors(function(d) { return true; }); |
| var VALID_DESCRIPTORS = mapTestDescriptors(isValidDescriptor); |
| |
| function TestRunner() |
| { |
| this._logLines = []; |
| } |
| TestRunner.prototype = |
| { |
| // MAIN METHODS |
| |
| runFunctionLengthTests: function runFunctionLengthTests() |
| { |
| var self = this; |
| function functionLengthTests() |
| { |
| self._fullFunctionLengthTests(() => Function("one", "/* body */"), 1); |
| self._fullFunctionLengthTests(() => function(one, two, three=null) { }, 2); |
| self._fullFunctionLengthTests(() => (one, two, ...etc) => 0, 2); |
| self._fullFunctionLengthTests(() => ({method(){}}.method), 0); |
| self._fullFunctionLengthTests(() => Object.getOwnPropertyDescriptor({set x(v){}}, "x").set, 1); |
| } |
| |
| this._runTestSet(functionLengthTests, "Function length tests completed!"); |
| }, |
| |
| runNotPresentTests: function runNotPresentTests() |
| { |
| var self = this; |
| function notPresentTests() |
| { |
| print("Running not-present tests now..."); |
| |
| for (var i = 0, sz = ALL_DESCRIPTORS.length; i < sz; i++) |
| self._runSingleNotPresentTest(ALL_DESCRIPTORS[i]); |
| }; |
| |
| this._runTestSet(notPresentTests, "Not-present length tests completed!"); |
| }, |
| |
| runPropertyPresentTestsFraction: |
| function runPropertyPresentTestsFraction(part, parts) |
| { |
| var self = this; |
| function propertyPresentTests() |
| { |
| print("Running already-present tests now..."); |
| |
| var total = VALID_DESCRIPTORS.length; |
| var start = Math.floor((part - 1) / parts * total); |
| var end = Math.floor(part / parts * total); |
| |
| for (var i = start; i < end; i++) |
| { |
| var old = VALID_DESCRIPTORS[i]; |
| print("Starting test with old descriptor " + old.toSource() + "..."); |
| |
| for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++) |
| self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], []); |
| } |
| } |
| |
| this._runTestSet(propertyPresentTests, |
| "Property-present fraction " + part + " of " + parts + |
| " completed!"); |
| }, |
| |
| runNonTerminalPropertyPresentTestsFraction: |
| function runNonTerminalPropertyPresentTestsFraction(part, parts) |
| { |
| var self = this; |
| |
| /* |
| * A plain old property to define on the object before redefining the |
| * originally-added property, to test redefinition of a property that's |
| * not also lastProperty. NB: we could loop over every possible |
| * descriptor here if we wanted, even try adding more than one, but we'd |
| * hit cubic complexity and worse, and SpiderMonkey only distinguishes by |
| * the mere presence of the middle property, not its precise details. |
| */ |
| var middleDefines = |
| [{ |
| property: "middle", |
| descriptor: |
| { value: 17, writable: true, configurable: true, enumerable: true } |
| }]; |
| |
| function nonTerminalPropertyPresentTests() |
| { |
| print("Running non-terminal already-present tests now..."); |
| |
| var total = VALID_DESCRIPTORS.length; |
| var start = Math.floor((part - 1) / parts * total); |
| var end = Math.floor(part / parts * total); |
| |
| for (var i = start; i < end; i++) |
| { |
| var old = VALID_DESCRIPTORS[i]; |
| print("Starting test with old descriptor " + old.toSource() + "..."); |
| |
| for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++) |
| { |
| self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], |
| middleDefines); |
| } |
| } |
| } |
| |
| this._runTestSet(nonTerminalPropertyPresentTests, |
| "Non-terminal property-present fraction " + |
| part + " of " + parts + " completed!"); |
| }, |
| |
| runDictionaryPropertyPresentTestsFraction: |
| function runDictionaryPropertyPresentTestsFraction(part, parts) |
| { |
| var self = this; |
| |
| /* |
| * Add and readd properties such that the scope for the object is in |
| * dictionary mode. |
| */ |
| var middleDefines = |
| [ |
| { |
| property: "mid1", |
| descriptor: |
| { value: 17, writable: true, configurable: true, enumerable: true } |
| }, |
| { |
| property: "mid2", |
| descriptor: |
| { value: 17, writable: true, configurable: true, enumerable: true } |
| }, |
| { |
| property: "mid1", |
| descriptor: |
| { get: function g() { }, set: function s(v){}, configurable: false, |
| enumerable: true } |
| }, |
| ]; |
| |
| function dictionaryPropertyPresentTests() |
| { |
| print("Running dictionary already-present tests now..."); |
| |
| var total = VALID_DESCRIPTORS.length; |
| var start = Math.floor((part - 1) / parts * total); |
| var end = Math.floor(part / parts * total); |
| |
| for (var i = start; i < end; i++) |
| { |
| var old = VALID_DESCRIPTORS[i]; |
| print("Starting test with old descriptor " + old.toSource() + "..."); |
| |
| for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++) |
| { |
| self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], |
| middleDefines); |
| } |
| } |
| } |
| |
| this._runTestSet(dictionaryPropertyPresentTests, |
| "Dictionary property-present fraction " + |
| part + " of " + parts + " completed!"); |
| }, |
| |
| |
| // HELPERS |
| |
| runPropertyPresentTests: function runPropertyPresentTests() |
| { |
| print("Running already-present tests now..."); |
| |
| for (var i = 0, sz = VALID_DESCRIPTORS.length; i < sz; i++) |
| { |
| var old = VALID_DESCRIPTORS[i]; |
| print("Starting test with old descriptor " + old.toSource() + "..."); |
| |
| for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++) |
| this._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], []); |
| } |
| }, |
| _runTestSet: function _runTestSet(fun, completeMessage) |
| { |
| try |
| { |
| fun(); |
| |
| print(completeMessage); |
| } |
| catch (e) |
| { |
| print("ERROR, EXITING (line " + (e.lineNumber || -1) + "): " + e); |
| throw e; |
| } |
| finally |
| { |
| this._reportAllErrors(); |
| } |
| }, |
| _reportAllErrors: function _reportAllErrors() |
| { |
| var errorCount = this._logLines.length; |
| print("Full accumulated number of errors: " + errorCount); |
| if (errorCount > 0) |
| throw errorCount + " errors detected, FAIL"; |
| }, |
| _fullFunctionLengthTests: function _fullFunctionLengthTests(funFactory, len) |
| { |
| print("Running Function.length (" + funFactory + ") tests now..."); |
| |
| for (var i = 0, sz = VALID_DESCRIPTORS.length; i < sz; i++) |
| { |
| var desc = VALID_DESCRIPTORS[i]; |
| this._runSingleFunctionLengthTest(funFactory(), len, desc); |
| } |
| }, |
| _log: function _log(v) |
| { |
| var m = "" + v; |
| print(m); |
| this._logLines.push(m); |
| }, |
| _runSingleNotPresentTest: function _runSingleNotPresentTest(desc) |
| { |
| var nativeObj = NativeTest.newObject(); |
| var reimplObj = ReimplTest.newObject(); |
| |
| try |
| { |
| NativeTest.defineProperty(nativeObj, "foo", desc); |
| } |
| catch (e) |
| { |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "foo", desc); |
| } |
| catch (e2) |
| { |
| if (e.constructor !== e2.constructor) |
| { |
| this._log("Difference when comparing native/reimplementation " + |
| "behavior for new descriptor " + desc.toSource() + |
| ", native threw " + e + ", reimpl threw " + e2); |
| } |
| return; |
| } |
| this._log("Difference when comparing native/reimplementation " + |
| "behavior for new descriptor " + desc.toSource() + |
| ", error " + e); |
| return; |
| } |
| |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "foo", desc); |
| } |
| catch (e) |
| { |
| this._log("Reimpl threw defining new descriptor " + desc.toSource() + |
| ", error: " + e); |
| return; |
| } |
| |
| var nativeDesc = NativeTest.getDescriptor(nativeObj, "foo"); |
| var reimplDesc = ReimplTest.getDescriptor(reimplObj, "foo"); |
| try |
| { |
| compareDescriptors(nativeDesc, reimplDesc); |
| } |
| catch (e) |
| { |
| this._log("Difference comparing returned descriptors for new " + |
| "property defined with descriptor " + desc.toSource() + |
| "; error: " + e); |
| return; |
| } |
| }, |
| _runSinglePropertyPresentTest: |
| function _runSinglePropertyPresentTest(old, add, middleDefines) |
| { |
| var nativeObj = NativeTest.newObject(); |
| var reimplObj = ReimplTest.newObject(); |
| |
| try |
| { |
| NativeTest.defineProperty(nativeObj, "foo", old); |
| } |
| catch (e) |
| { |
| if (!SameValue(NativeTest.getDescriptor(nativeObj, "foo"), undefined)) |
| { |
| this._log("defining bad property descriptor: " + old.toSource()); |
| return; |
| } |
| |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "foo", old); |
| } |
| catch (e2) |
| { |
| if (!SameValue(ReimplTest.getDescriptor(reimplObj, "foo"), |
| undefined)) |
| { |
| this._log("defining bad property descriptor: " + old.toSource() + |
| "; reimplObj: " + uneval(reimplObj)); |
| } |
| |
| if (e.constructor !== e2.constructor) |
| { |
| this._log("Different errors defining bad property descriptor: " + |
| old.toSource() + "; native threw " + e + ", reimpl " + |
| "threw " + e2); |
| } |
| |
| return; |
| } |
| |
| this._log("Difference defining a property with descriptor " + |
| old.toSource() + ", error " + e); |
| return; |
| } |
| |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "foo", old); |
| } |
| catch (e) |
| { |
| this._log("Difference when comparing native/reimplementation " + |
| "behavior when adding descriptor " + add.toSource() + |
| ", error: " + e); |
| return; |
| } |
| |
| // Now add (or even readd) however many properties were specified between |
| // the original property to add and the new one, to test redefining |
| // non-last-properties and properties in scopes in dictionary mode. |
| for (var i = 0, sz = middleDefines.length; i < sz; i++) |
| { |
| var middle = middleDefines[i]; |
| var prop = middle.property; |
| var desc = middle.descriptor; |
| |
| try |
| { |
| NativeTest.defineProperty(nativeObj, prop, desc); |
| ReimplTest.defineProperty(reimplObj, prop, desc); |
| } |
| catch (e) |
| { |
| this._log("failure defining middle descriptor: " + desc.toSource() + |
| ", error " + e); |
| return; |
| } |
| |
| // Sanity check |
| var nativeDesc = NativeTest.getDescriptor(nativeObj, prop); |
| var reimplDesc = ReimplTest.getDescriptor(reimplObj, prop); |
| |
| compareDescriptors(nativeDesc, reimplDesc); |
| compareDescriptors(nativeDesc, desc); |
| } |
| |
| try |
| { |
| NativeTest.defineProperty(nativeObj, "foo", add); |
| } |
| catch (e) |
| { |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "foo", add); |
| } |
| catch (e2) |
| { |
| if (e.constructor !== e2.constructor) |
| { |
| this._log("Difference when comparing native/reimplementation " + |
| "behavior for descriptor " + add.toSource() + |
| " overwriting descriptor " + old.toSource() + "; " + |
| "native threw " + e + ", reimpl threw " + e2); |
| } |
| return; |
| } |
| this._log("Difference when comparing native/reimplementation " + |
| "behavior for added descriptor " + add.toSource() + ", " + |
| "initial was " + old.toSource() + "; error: " + e); |
| return; |
| } |
| |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "foo", add); |
| } |
| catch (e) |
| { |
| this._log("Difference when comparing native/reimplementation " + |
| "behavior for readded descriptor " + add.toSource() + ", " + |
| "initial was " + old.toSource() + "; native readd didn't " + |
| "throw, reimpl add did, error: " + e); |
| return; |
| } |
| |
| var nativeDesc = NativeTest.getDescriptor(nativeObj, "foo"); |
| var reimplDesc = ReimplTest.getDescriptor(reimplObj, "foo"); |
| try |
| { |
| compareDescriptors(nativeDesc, reimplDesc); |
| } |
| catch (e) |
| { |
| this._log("Difference comparing returned descriptors for readded " + |
| "property defined with descriptor " + add.toSource() + "; " + |
| "initial was " + old.toSource() + "; error: " + e); |
| return; |
| } |
| }, |
| _runSingleFunctionLengthTest: function _runSingleFunctionLengthTest(fun, len, desc) |
| { |
| var nativeObj = fun; |
| var reimplObj = ReimplTest.newObject(); |
| ReimplTest.defineProperty(reimplObj, "length", |
| { |
| value: len, |
| enumerable: false, |
| configurable: true, |
| writable: false |
| }); |
| |
| try |
| { |
| NativeTest.defineProperty(nativeObj, "length", desc); |
| } |
| catch (e) |
| { |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "length", desc); |
| } |
| catch (e2) |
| { |
| if (e.constructor !== e2.constructor) |
| { |
| this._log("Difference when comparing native/reimplementation " + |
| "behavior defining fun.length with " + desc.toSource() + |
| "; native threw " + e + ", reimpl threw " + e2); |
| } |
| return; |
| } |
| this._log("Difference when comparing Function.length native/reimpl " + |
| "behavior for descriptor " + desc.toSource() + |
| ", native impl threw error " + e); |
| return; |
| } |
| |
| try |
| { |
| ReimplTest.defineProperty(reimplObj, "length", desc); |
| } |
| catch (e) |
| { |
| this._log("Difference defining new Function.length descriptor: impl " + |
| "succeeded, reimpl threw for descriptor " + |
| desc.toSource() + ", error: " + e); |
| return; |
| } |
| |
| var nativeDesc = NativeTest.getDescriptor(nativeObj, "length"); |
| var reimplDesc = ReimplTest.getDescriptor(reimplObj, "length"); |
| try |
| { |
| compareDescriptors(nativeDesc, reimplDesc); |
| } |
| catch (e) |
| { |
| this._log("Difference comparing returned descriptors for " + |
| "Function.length with descriptor " + desc.toSource() + |
| "; error: " + e); |
| return; |
| } |
| } |
| }; |
| |
| function runDictionaryPropertyPresentTestsFraction(PART, PARTS) |
| { |
| var testfile = |
| '15.2.3.6-dictionary-redefinition-' + PART + '-of-' + PARTS + '.js'; |
| var BUGNUMBER = 560566; |
| var summary = |
| 'ES5 Object.defineProperty(O, P, Attributes): dictionary redefinition ' + |
| PART + ' of ' + PARTS; |
| |
| print(BUGNUMBER + ": " + summary); |
| |
| try |
| { |
| new TestRunner().runDictionaryPropertyPresentTestsFraction(PART, PARTS); |
| } |
| catch (e) |
| { |
| throw "Error thrown during testing: " + e + |
| " at line " + e.lineNumber + "\n" + |
| (e.stack |
| ? "Stack: " + e.stack.split("\n").slice(2).join("\n") + "\n" |
| : ""); |
| } |
| |
| if (typeof reportCompare === "function") |
| reportCompare(true, true); |
| |
| print("Tests complete!"); |
| } |
| |
| function runNonTerminalPropertyPresentTestsFraction(PART, PARTS) |
| { |
| var BUGNUMBER = 560566; |
| var summary = |
| 'ES5 Object.defineProperty(O, P, Attributes): middle redefinition ' + |
| PART + ' of ' + PARTS; |
| |
| print(BUGNUMBER + ": " + summary); |
| |
| |
| /************** |
| * BEGIN TEST * |
| **************/ |
| |
| try |
| { |
| new TestRunner().runNonTerminalPropertyPresentTestsFraction(PART, PARTS); |
| } |
| catch (e) |
| { |
| throw "Error thrown during testing: " + e + |
| " at line " + e.lineNumber + "\n" + |
| (e.stack |
| ? "Stack: " + e.stack.split("\n").slice(2).join("\n") + "\n" |
| : ""); |
| } |
| |
| /******************************************************************************/ |
| |
| if (typeof reportCompare === "function") |
| reportCompare(true, true); |
| |
| print("Tests complete!"); |
| } |