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 (thisinstanceof 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 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()
{ deletethis.get; deletethis.set; this.writable = false; this.value = undefined;
};
PropertyDescriptor.prototype.convertToAccessorDescriptor = function convertToAccessorDescriptor()
{ deletethis.writable; deletethis.value; this.get = undefined; this.set = undefined;
};
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": returnfalse; default:
assertEq(true, false, "bad field name: " + field);
}
}
function IsAccessorDescriptor(desc)
{ if (!desc) returnfalse; if (!("get" in desc) && !("set" in desc)) returnfalse; returntrue;
}
function IsDataDescriptor(desc)
{ if (!desc) returnfalse; if (!("value" in desc) && !("writable" in desc)) returnfalse; returntrue;
}
function IsGenericDescriptor(desc)
{ if (!desc) returnfalse; if (!IsAccessorDescriptor(desc) && !IsDataDescriptor(desc)) returntrue; returnfalse;
}
function CustomObject()
{ this.properties = {}; this.extensible = true;
}
CustomObject.prototype =
{
_reject: function _reject(throwing, msg)
{ if (throwing) thrownew TypeError(msg + "; rejected!"); returnfalse;
},
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) returnthis._reject(throwing, "object not extensible");
// 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 returntrue;
} while (false);
// Step 7. if (!examine(current, "configurable"))
{ if ("configurable" in desc && examine(desc, "configurable")) returnthis._reject(throwing, "can't make configurable again"); if ("enumerable" in desc &&
examine(current, "enumerable") !== examine(desc, "enumerable"))
{ returnthis._reject(throwing, "can't change enumerability");
}
}
// Step 8. if (IsGenericDescriptor(desc))
{ // do nothing
} // Step 9. elseif (IsDataDescriptor(current) !== IsDataDescriptor(desc))
{ // Step 9(a). if (!examine(current, "configurable")) returnthis._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. elseif (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"))
{ returnthis._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")))
{ returnthis._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")))
{ returnthis._reject(throwing, "can't change setter if not configurable");
} // Step 11(a).ii. if ("get" in desc &&
!SameValue(examine(desc, "get"), examine(current, "get")))
{ returnthis._reject(throwing, "can't change getter if not configurable");
}
}
}
// Step 12.
current.update(desc);
// Step 13. returntrue;
}
};
function IsCallable(v)
{ returntypeof 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()
{ returnnew 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) thrownew TypeError("get/set and value/writable"); if (!IsCallable(propdesc.get)) thrownew TypeError("get defined, uncallable"); if (!IsCallable(propdesc.set)) thrownew TypeError("set defined, uncallable");
} return obj.defineOwnProperty(propname, propdesc, true);
},
getDescriptor: function getDescriptor(obj, propname)
{ if (!(propname in obj.properties)) return undefined;
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) returnfalse;
// 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)) returnfalse; if (propdesc.set !== null && propdesc.set !== undefined && !IsCallable(propdesc.set)) returnfalse;
}
returntrue;
}
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;
}
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() + "...");
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 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;
}
// 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;
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"
: "");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.