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