blob: da6fe8f496816bfc4454bf686e067aba57149421 [file] [log] [blame]
// |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!");
}