//------------------------------------------------------------------------------------------------------- | |
// Copyright (C) Microsoft. All rights reserved. | |
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. | |
//------------------------------------------------------------------------------------------------------- | |
var helpers = function helpers() { | |
//private | |
var undefinedAsString = "undefined"; | |
var isInBrowser = function isInBrowser() { | |
return typeof (document) !== undefinedAsString; | |
}; | |
return { | |
// public | |
getDummyObject: function () { | |
//return isInBrowser() ? document : {}; | |
return {}; | |
}, | |
writeln: function writeln() { | |
var line = "", i; | |
for (i = 0; i < arguments.length; i += 1) { | |
line = line.concat(arguments[i]) | |
} | |
if (!isInBrowser()) { | |
WScript.Echo(line); | |
} else { | |
document.writeln(line); | |
document.writeln("<br/>"); | |
} | |
}, | |
printObject: function printObject(o) { | |
var name; | |
for (name in o) { | |
this.writeln(name, o.hasOwnProperty(name) ? "" : " (inherited)", ": ", o[name]); | |
} | |
} | |
} | |
} (); // helpers module. | |
var testRunner = function testRunner() { | |
var executedTestCount = 0; | |
var passedTestCount = 0; | |
var passName; | |
return { | |
// Runs provided tests. | |
// passes is a collection of {name, prep}, where prep is a function to prepare for the pass. | |
// The 'testsToRun' is an object that has enumerable properties, | |
// each property is an object that has 'name' and 'body' properties. | |
runTests: function runTests(passes, testsToRun) { | |
for (var p in passes) { | |
var pass = passes[p]; | |
passName = pass.name; | |
if (pass.prep) { | |
pass.prep(); | |
} | |
for (var i in testsToRun) { | |
var test = tests[i]; | |
// | |
// * If test.disabled (e.g., temp bug), skip it. | |
// * If test.pass specifies a pass name, only run it for that pass. | |
// * If test.pass not defined, run it for any non "runonce" pass. | |
// | |
if (!test.disabled && (test.pass === passName || (!test.pass && !pass.runonce))) { | |
this.runTest(i, test.name, test.body); | |
} | |
} | |
} | |
helpers.writeln("Summary of tests: total executed: ", executedTestCount, | |
"; passed: ", passedTestCount, "; failed: ", executedTestCount - passedTestCount); | |
}, | |
// Runs test body catching all exceptions. | |
// Result: prints PASSED/FAILED to the output. | |
runTest: function runTest(testIndex, testName, testBody) { | |
helpers.writeln("*** ", passName, " (", testIndex, "): ", testName); | |
var isSuccess = true; | |
try { | |
testBody(); | |
} catch (ex) { | |
var message = ex.message !== undefined ? ex.message : ex; | |
helpers.writeln("Test threw exception: ", message); | |
isSuccess = false; | |
} | |
if (isSuccess) { | |
helpers.writeln("PASSED"); | |
++passedTestCount; | |
} else { | |
helpers.writeln("FAILED"); | |
} | |
++executedTestCount; | |
} | |
} | |
}(); // testRunner. | |
var assert = function assert() { | |
// private | |
var isObject = function isObject(x) { | |
return x instanceof Object && typeof x !== "function"; | |
}; | |
var compare = function compare(expected, actual) { | |
if (isObject(expected)) { | |
if (!isObject(actual)) return "actual is not an object"; | |
var expectedFieldCount = 0, actualFieldCount = 0; | |
for (var i in expected) { | |
var compareResult = compare(expected[i], actual[i]); | |
if (compareResult !== true) return compareResult; | |
++expectedFieldCount; | |
} | |
for (var i in actual) { | |
++actualFieldCount; | |
} | |
if (expectedFieldCount !== actualFieldCount) { | |
return "actual has different number of fields than expected"; | |
} | |
return true; | |
} else { | |
if (isObject(actual)) return "actual is an object"; | |
if (expected === actual) return true; | |
return "expected: " + expected + " actual: " + actual; | |
} | |
}; | |
var addMessage = function addMessage(baseMessage, message) { | |
if (message !== undefined) { | |
baseMessage += ": " + message; | |
} | |
return baseMessage; | |
} | |
return { | |
// Performs deep comparison of arguments. | |
// This works for objects and simple types. | |
// TODO: account for other types? | |
// TODO: account for missing vs undefined fields. | |
areEqual: function areEqual(expected, actual, message) { | |
var compareResult = compare(expected, actual); | |
if (compareResult !== true) { | |
throw addMessage("assert.areEqual failed: " + compareResult, message); | |
} | |
}, | |
areNotEqual: function areNotEqual(expected, actual, message) { | |
var compareResult = compare(expected, actual); | |
if (compareResult === true) { | |
throw addMessage("assert.areNotEqual failed", message); | |
} | |
}, | |
// Makes sure that the function specified by the 'testFunction' parameter | |
// throws the exception specified by the 'expectedException' parameter. | |
// Note: currently we check only for specific exception and not "all exceptions derived from specified". | |
// Example: | |
// assert.throws(function() { eval("{"); }, SyntaxError, "expected SyntaxError") | |
throws: function throws(testFunction, expectedException, message) { | |
var exception = null; | |
try { | |
testFunction(); | |
} catch (ex) { | |
exception = ex; | |
} | |
if (!(exception instanceof Object && exception.constructor === expectedException)) { | |
var expectedString = expectedException.toString().replace(/\n/g, "").replace(/.*function (.*)\(.*/g, "$1"); | |
throw addMessage("assert.throws failed: expected: " + expectedString + ", actual: " + exception, message); | |
} | |
}, | |
// Can be used to fail the test. | |
fail: function fail(message) { | |
throw message; | |
} | |
} | |
}(); // assert. | |
var tests = { | |
// Note: each test has name (string) and body (function) properties. | |
// Success is when the body does not throw, failure -- when it throws. | |
//---------------------- normal identifier property names ------------------------------- | |
test01: { | |
name: "8.12.9.4.a (variation 1): define generic property, check default attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo02"; | |
var pd = {}; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: undefined, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test02: { | |
name: "8.12.9.4.a (variation 2): define data property, check default attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo03"; | |
var pd = { value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 0, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test03: { | |
name: "8.12.9.4.a (variation 3): define generic property by specifying some attributes, check attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo02"; | |
var pd = { configurable: true, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: undefined, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test04: { | |
name: "8.12.9.4.b: define accessor property, check default attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo04"; | |
var getter = function () { return this.Value }; | |
var pd = { get: getter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test05: { | |
name: "8.12.9.5: re-define property: use descriptor with all fields absent, check that nothing happens to previous descriptor", | |
body: function () { | |
var propertyName = "foo05"; | |
var o = { foo05: 1 }; | |
var pd = {}; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: true, value: 1, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test06: { | |
name: "8.12.9.6: re-define property: use equal descriptor with data field, check that nothing happens to previous descriptor", | |
body: function () { | |
var propertyName = "foo06"; | |
var o = { foo06: 1 }; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: true, value: 1, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
test07: { | |
name: "8.12.9.7.a: re-define property: current descriptor is not configurable and descriptor is configurable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo07"; | |
var pd = { value: 0, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, configurable: true }; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test08: { | |
name: "8.12.9.7.b (variation 1): re-define property: current descriptor is not configurable and descriptor enumerable is specified and it's negation of current enumerable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo08"; | |
var pd = { value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, enumerable: true }; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test09: { | |
name: "8.12.9.7.b (variation 2): re-define property: current descriptor is not configurable and descriptor enumerable is not specified, check that it does not throw", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo09"; | |
var pd = { value: 0, writable: true }; // set writable to true to avoid throw code path. | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test10: { | |
name: "8.12.9.7.b (variation 3): re-define property: current descriptor is not configurable and descriptor enumerable is same as current enumerable, check that it does not throw", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo10"; | |
var pd = { value: 0, writable: true }; // set writable to true to avoid throw code path. | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, enumerable: false, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test11: { | |
name: "8.12.9.8: re-define property: descriptor is not empty, generic and is different from current", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo11"; | |
var pd = { value: 0, configurable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { enumerable: true }; // change enumerable to make sure that descriptor is different from current. | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 0, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
// - descriptor.IsData != current.IsData | |
test12: { | |
name: "8.12.9.9.a: re-define property: descriptor.IsData != current.IsData and current is not configurable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo12"; | |
var pd = { value: 0, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: function () { return this.Value; } }; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test13: { | |
name: "8.12.9.9.b (variation 1): re-define property: convert from data to accessor descriptor, check that configurable/enumerable (true) are preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo13"; | |
var pd = { value: 0, configurable: true, enumerable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
var getter = function() { return this.Value; }; | |
pd = { get: getter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test14: { | |
name: "8.12.9.9.b (variation 2): re-define property: convert from data to accessor descriptor, check that enumerable (false) is preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo14"; | |
var pd = { value: 0, configurable: true, enumerable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var getter = function () { return this.Value; }; | |
pd = { get: getter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test15: { | |
name: "8.12.9.9.b (variation 3): re-define property: convert from data to accessor descriptor, check that configurable/enumerable not preserved when specified by descriptor", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo15"; | |
var pd = { value: 0, configurable: true, enumerable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
var getter = function () { return this.Value; }; | |
pd = { get: getter, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: false, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test16: { | |
name: "8.12.9.9.c (variation 1): re-define property: convert from accessor to data descriptor, check that configurable/enumerable (true) are preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo16"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: true | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test17: { | |
name: "8.12.9.9.c (variation 2): re-define property: convert from accessor to data descriptor, check that enumerable (false) is preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo17"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: false | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test18: { | |
name: "8.12.9.9.c (variation 3): re-define property: convert from accessor to data descriptor, check that configurable/enumerable (true/false) not preserved when specified by descriptor (false/absent)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo18"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: false | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
// expected: configurable/enumerable = false/false. | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test19: { | |
name: "8.12.9.9.c (variation 4): re-define property: convert from accessor to data descriptor, check that configurable/enumerable (true/true) not preserved when specified by descriptor (absent/false)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo19"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: true | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, enumerable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
// expected: configurable/enumerable = true/false. | |
var expected = { writable: false, value: 1, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
// - descriptor is data, current is data | |
test20: { | |
name: "8.12.9.10.a (variation 1): re-define data property: current is not configurable/not writable and descriptor writable is absent/value is same", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo20"; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test21: { | |
name: "8.12.9.10.a.i: re-define data property: current is not configurable/not writable and descriptor is writable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo21"; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 2, writable: true }; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
return true; | |
} | |
}, | |
test22: { | |
name: "8.12.9.10.a.ii: re-define data property: current is not configurable/not writable and descriptor writable is false and value is different, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo22"; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 2, writable: false }; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test23: { | |
name: "8.12.9.10.a (variation 2): re-define data property: current is configurable", | |
body: function () { | |
var propertyName = "foo23"; | |
var o = { foo23: 1 }; | |
var pd = { value: 2, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 2, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
// - descriptor is accessor, current is accessor | |
test24: { | |
name: "Test: 8.12.9.11 (variation 1): re-define accessor property: current configurable is true: valid case", | |
body: function () { | |
var propertyName = "foo24"; | |
var o = { | |
get foo24() { return this.Value; }, | |
set foo24(arg) { helpers.writeln("old setter"); this.Value = arg; } | |
}; | |
var newGetter = function() { return 2; }; | |
var newSetter = function(arg) { helpers.writeln("new setter"); } | |
var pd = { get: newGetter, set: newSetter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: newGetter, set: newSetter, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test25: { | |
name: "8.12.9.11.a.i: re-define accessor property: current configurable is false, descriptor specifies setter as different, expect TypeError", | |
body: function () { | |
var propertyName = "foo25"; | |
var o = helpers.getDummyObject(); | |
var pd = { set: function(arg) { helpers.writeln("old setter"); this.Value = arg; } }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { set: function(arg) { helpers.writeln("new setter"); } }; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test26: { | |
name: "8.12.9.11.a.ii: re-define accessor property: current configurable is false, descriptor specifies getter as different, expect TypeError", | |
body: function () { | |
var propertyName = "foo26"; | |
var o = helpers.getDummyObject(); | |
var pd = { get: function() { return this.Value; }, }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: function() { helpers.writeln("new getter"); return 2; } }; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test27: { | |
name: "8.12.9.11 (variation 2): re-define accessor property: current configurable is true and no getter, descriptor specifies getter as undefined, setter as same", | |
body: function () { | |
var propertyName = "foo27"; | |
var o = helpers.getDummyObject(); | |
var setter = function(arg) { helpers.writeln("setter") }; | |
var pd = { set: setter }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: undefined, set: setter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: undefined, set: setter, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test28: { | |
name: "Re-define property from data to accessor property. Make sure that setter is called when setting the value.", | |
body: function () { | |
// define a data property. | |
var propertyName = "foo28"; | |
var o = helpers.getDummyObject(); | |
var pd = { value: 1, configurable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
// re-define the property to be accessor property. | |
var log = ""; | |
var getter = function() { log += "getter was called."; return this.Value; } | |
var setter = function(arg) { log += "setter was called."; this.Value = arg; }; | |
pd = { get: getter, set: setter }; | |
Object.defineProperty(o, propertyName, pd); | |
// set the value and get it. | |
var newValue = 2; | |
o[propertyName] = newValue; | |
var actualValue = o[propertyName]; | |
// validate. | |
var expected = { get: getter, set: setter, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
assert.areEqual("setter was called.getter was called.", log, "wrong log"); | |
assert.areEqual(newValue, actualValue, "wrong value"); | |
} | |
}, | |
test29: { | |
name: "Define property 'length' as accessor property on array: check that it throws TypeError.", | |
body: function () { | |
assert.throws( | |
function() { Object.defineProperty([], "length", {configurable: false, get: function() {return 2;}}); }, | |
TypeError); | |
assert.throws( | |
function() { Object.defineProperty(Array.prototype, "length", {configurable: false, get: function() {return 2;}}); }, | |
TypeError); | |
} | |
}, | |
// Where we are: some tests for specific issues. | |
test30: { | |
name: "Define property with getter specified as undefined, then access the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo30"; | |
var pd = { get: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
assert.areEqual(undefined, o[propertyName]); | |
} | |
}, | |
test31: { | |
name: "Define property with setter specified as undefined, then set the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo31"; | |
var pd = { set: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
o[propertyName] = 1; // Make sure this does not throw. | |
assert.areEqual(undefined, o[propertyName]); // Just in case try to access the property. | |
} | |
}, | |
test32: { | |
name: "Convert data to accessor property with getter specified as undefined, then access the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo32"; | |
var pd = { configurable: true, value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
assert.areEqual(undefined, o[propertyName]); | |
} | |
}, | |
test33: { | |
name: "Convert data to accessor property with setter specified as undefined, then set the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "foo33"; | |
var pd = { configurable: true, value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { set: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
o[propertyName] = 1; // Make sure this does not throw. | |
assert.areEqual(undefined, o[propertyName]); // Just in case try to access the property. | |
} | |
}, | |
// Note: this test irreversibly changes the dummy object (that's important when dummy object is document/window), | |
// it should in the very end. | |
test34: { | |
name: "8.12.9.3: define property for non-extensible object, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
Object.preventExtensions(o); | |
var propertyName = "foo01"; | |
var pd = {}; | |
assert.throws(function() { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
//---------------------- numeric property names ------------------------------- | |
test_101: { | |
name: "8.12.9.4.a (variation 1): define generic property, check default attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "2"; | |
var pd = {}; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: undefined, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_102: { | |
name: "8.12.9.4.a (variation 2): define data property, check default attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "3"; | |
var pd = { value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 0, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_103: { | |
name: "8.12.9.4.a (variation 3): define generic property by specifying some attributes, check attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "2"; | |
var pd = { configurable: true, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: undefined, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_104: { | |
name: "8.12.9.4.b: define accessor property, check default attrbitues", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "4"; | |
var getter = function () { return this.Value }; | |
var pd = { get: getter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_105: { | |
name: "8.12.9.5: re-define property: use descriptor with all fields absent, check that nothing happens to previous descriptor", | |
body: function () { | |
var propertyName = "5"; | |
var o = { 5: 1 }; | |
var pd = {}; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: true, value: 1, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_106: { | |
name: "8.12.9.6: re-define property: use equal descriptor with data field, check that nothing happens to previous descriptor", | |
body: function () { | |
var propertyName = "6"; | |
var o = { 6: 1 }; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: true, value: 1, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
test_107: { | |
name: "8.12.9.7.a: re-define property: current descriptor is not configurable and descriptor is configurable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "7"; | |
var pd = { value: 0, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, configurable: true }; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test_108: { | |
name: "8.12.9.7.b (variation 1): re-define property: current descriptor is not configurable and descriptor enumerable is specified and it's negation of current enumerable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "8"; | |
var pd = { value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, enumerable: true }; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test_109: { | |
name: "8.12.9.7.b (variation 2): re-define property: current descriptor is not configurable and descriptor enumerable is not specified, check that it does not throw", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "9"; | |
var pd = { value: 0, writable: true }; // set writable to true to avoid throw code path. | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_110: { | |
name: "8.12.9.7.b (variation 3): re-define property: current descriptor is not configurable and descriptor enumerable is same as current enumerable, check that it does not throw", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "10"; | |
var pd = { value: 0, writable: true }; // set writable to true to avoid throw code path. | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, enumerable: false, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_111: { | |
name: "8.12.9.8: re-define property: descriptor is not empty, generic and is different from current", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "11"; | |
var pd = { value: 0, configurable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { enumerable: true }; // change enumerable to make sure that descriptor is different from current. | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 0, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
// - descriptor.IsData != current.IsData | |
test_112: { | |
name: "8.12.9.9.a: re-define property: descriptor.IsData != current.IsData and current is not configurable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "12"; | |
var pd = { value: 0, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: function () { return this.Value; } }; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test_113: { | |
name: "8.12.9.9.b (variation 1): re-define property: convert from data to accessor descriptor, check that configurable/enumerable (true) are preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "13"; | |
var pd = { value: 0, configurable: true, enumerable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
var getter = function () { return this.Value; }; | |
pd = { get: getter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_114: { | |
name: "8.12.9.9.b (variation 2): re-define property: convert from data to accessor descriptor, check that enumerable (false) is preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "14"; | |
var pd = { value: 0, configurable: true, enumerable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var getter = function () { return this.Value; }; | |
pd = { get: getter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_115: { | |
name: "8.12.9.9.b (variation 3): re-define property: convert from data to accessor descriptor, check that configurable/enumerable not preserved when specified by descriptor", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "15"; | |
var pd = { value: 0, configurable: true, enumerable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
var getter = function () { return this.Value; }; | |
pd = { get: getter, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: getter, set: undefined, configurable: false, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_116: { | |
name: "8.12.9.9.c (variation 1): re-define property: convert from accessor to data descriptor, check that configurable/enumerable (true) are preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "16"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: true | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_117: { | |
name: "8.12.9.9.c (variation 2): re-define property: convert from accessor to data descriptor, check that enumerable (false) is preserved", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "17"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: false | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_118: { | |
name: "8.12.9.9.c (variation 3): re-define property: convert from accessor to data descriptor, check that configurable/enumerable (true/false) not preserved when specified by descriptor (false/absent)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "18"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: false | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, configurable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
// expected: configurable/enumerable = false/false. | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_119: { | |
name: "8.12.9.9.c (variation 4): re-define property: convert from accessor to data descriptor, check that configurable/enumerable (true/true) not preserved when specified by descriptor (absent/false)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "19"; | |
var pd = { | |
set: function (arg) { helpers.writeln("setter was called"); this.Value = arg; }, | |
configurable: true, | |
enumerable: true | |
}; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1, enumerable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
// expected: configurable/enumerable = true/false. | |
var expected = { writable: false, value: 1, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
// - descriptor is data, current is data | |
test_120: { | |
name: "8.12.9.10.a (variation 1): re-define data property: current is not configurable/not writable and descriptor writable is absent/value is same", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "20"; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 1, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_121: { | |
name: "8.12.9.10.a.i: re-define data property: current is not configurable/not writable and descriptor is writable, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "21"; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 2, writable: true }; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
return true; | |
} | |
}, | |
test_122: { | |
name: "8.12.9.10.a.ii: re-define data property: current is not configurable/not writable and descriptor writable is false and value is different, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "22"; | |
var pd = { value: 1 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { value: 2, writable: false }; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test_123: { | |
name: "8.12.9.10.a (variation 2): re-define data property: current is configurable", | |
body: function () { | |
var propertyName = "23"; | |
var o = { 23: 1 }; | |
var pd = { value: 2, writable: false }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { writable: false, value: 2, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
// where we are: | |
// - re-define | |
// - desc is not empty | |
// - desc and current are not the same | |
// - descriptor is accessor, current is accessor | |
test_124: { | |
name: "Test: 8.12.9.11 (variation 1): re-define accessor property: current configurable is true: valid case", | |
body: function () { | |
var propertyName = "24"; | |
var o = { | |
get 24() { return this.Value; }, | |
set 24(arg) { helpers.writeln("old setter"); this.Value = arg; } | |
}; | |
var newGetter = function() { return 2; }; | |
var newSetter = function(arg) { helpers.writeln("new setter"); } | |
var pd = { get: newGetter, set: newSetter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: newGetter, set: newSetter, configurable: true, enumerable: true }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_125: { | |
name: "8.12.9.11.a.i: re-define accessor property: current configurable is false, descriptor specifies setter as different, expect TypeError", | |
body: function () { | |
var propertyName = "25"; | |
var o = helpers.getDummyObject(); | |
var pd = { set: function (arg) { helpers.writeln("old setter"); this.Value = arg; } }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { set: function (arg) { helpers.writeln("new setter"); } }; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test_126: { | |
name: "8.12.9.11.a.ii: re-define accessor property: current configurable is false, descriptor specifies getter as different, expect TypeError", | |
body: function () { | |
var propertyName = "26"; | |
var o = helpers.getDummyObject(); | |
var pd = { get: function () { return this.Value; } }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: function () { helpers.writeln("new getter"); return 2; } }; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
test_127: { | |
name: "8.12.9.11 (variation 2): re-define accessor property: current configurable is true and no getter, descriptor specifies getter as undefined, setter as same", | |
body: function () { | |
var propertyName = "27"; | |
var o = helpers.getDummyObject(); | |
var setter = function (arg) { helpers.writeln("setter") }; | |
var pd = { set: setter }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: undefined, set: setter }; | |
Object.defineProperty(o, propertyName, pd); | |
var expected = { get: undefined, set: setter, configurable: false, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
} | |
}, | |
test_128: { | |
name: "Re-define property from data to accessor property. Make sure that setter is called when setting the value.", | |
body: function () { | |
// define a data property. | |
var propertyName = "28"; | |
var o = helpers.getDummyObject(); | |
var pd = { value: 1, configurable: true }; | |
Object.defineProperty(o, propertyName, pd); | |
// re-define the property to be accessor property. | |
var log = ""; | |
var getter = function () { log += "getter was called."; return this.Value; } | |
var setter = function (arg) { log += "setter was called."; this.Value = arg; }; | |
pd = { get: getter, set: setter }; | |
Object.defineProperty(o, propertyName, pd); | |
// set the value and get it. | |
var newValue = 2; | |
o[propertyName] = newValue; | |
var actualValue = o[propertyName]; | |
// validate. | |
var expected = { get: getter, set: setter, configurable: true, enumerable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
assert.areEqual("setter was called.getter was called.", log, "wrong log"); | |
assert.areEqual(newValue, actualValue, "wrong value"); | |
} | |
}, | |
test_129: { | |
name: "Define property 'length' as accessor property on array: check that it throws TypeError.", | |
body: function () { | |
assert.throws( | |
function () { Object.defineProperty([], "length", { configurable: false, get: function () { return 2; } }); }, | |
TypeError); | |
assert.throws( | |
function () { Object.defineProperty(Array.prototype, "length", { configurable: false, get: function () { return 2; } }); }, | |
TypeError); | |
} | |
}, | |
// Where we are: some tests for specific issues. | |
test_130: { | |
name: "Define property with getter specified as undefined, then access the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "30"; | |
var pd = { get: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
assert.areEqual(undefined, o[propertyName]); | |
} | |
}, | |
test_131: { | |
name: "Define property with setter specified as undefined, then set the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "31"; | |
var pd = { set: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
o[propertyName] = 1; // Make sure this does not throw. | |
assert.areEqual(undefined, o[propertyName]); // Just in case try to access the property. | |
} | |
}, | |
test_132: { | |
name: "Convert data to accessor property with getter specified as undefined, then access the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "32"; | |
var pd = { configurable: true, value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { get: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
assert.areEqual(undefined, o[propertyName]); | |
} | |
}, | |
test_133: { | |
name: "Convert data to accessor property with setter specified as undefined, then set the property (WOOB bug 1123281)", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "33"; | |
var pd = { configurable: true, value: 0 }; | |
Object.defineProperty(o, propertyName, pd); | |
pd = { set: undefined }; | |
Object.defineProperty(o, propertyName, pd); | |
o[propertyName] = 1; // Make sure this does not throw. | |
assert.areEqual(undefined, o[propertyName]); // Just in case try to access the property. | |
} | |
}, | |
// Note: this test irreversibly changes the dummy object (that's important when dummy object is document/window), | |
// it should in the very end. | |
test_134: { | |
name: "8.12.9.3: define property for non-extensible object, check that it throws TypeError", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
Object.preventExtensions(o); | |
var propertyName = "1"; | |
var pd = {}; | |
assert.throws(function () { Object.defineProperty(o, propertyName, pd); }, TypeError); | |
} | |
}, | |
// --------------------- misc adhoc tests ------------------------------------- | |
test_301: { | |
name: "set property whose writable is false", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 17; | |
o[propName] = 100; | |
Object.defineProperty(o, propName, {writable: false}); | |
o[propName] = 200; // should have no effect | |
assert.areEqual(100, o[propName]); | |
} | |
}, | |
test_302: { | |
name: "delete index property", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 123; | |
assert.areEqual(true, delete o[1], "delete non-exist property should return true"); | |
o[propName] = 123; | |
assert.areEqual(true, delete o[propName], "delete this property should return true"); | |
assert.areEqual(undefined, o[propName], "deleted property value should become undefined"); | |
Object.defineProperty(o, propName, {get:function(){return 123;}, configurable: true}); | |
assert.areEqual(123, o[propName], "Property value should be from getter"); | |
assert.areEqual(true, delete o[propName], "delete this property should return true"); | |
assert.areEqual(undefined, o[propName], "deleted property value should become undefined"); | |
Object.defineProperty(o, propName, {value: 123, configurable: false}); | |
assert.areEqual(123, o[propName], "Property value should be the value"); | |
assert.areEqual(false, delete o[propName], "delete this property should return false, not configurable"); | |
assert.areEqual(123, o[propName], "Property value should not be changed"); | |
} | |
}, | |
test_303: { | |
name: "delete a data property then set", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 303; | |
Object.defineProperty(o, propName, { | |
value: 100, | |
configurable: true | |
}); | |
assert.areEqual(delete o[propName], true, "delete should succeed on configurable data property"); | |
o[propName] = 200; | |
assert.areEqual(200, o[propName]); | |
} | |
}, | |
test_304: { | |
name: "delete a getter property then set", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 303; | |
Object.defineProperty(o, propName, { | |
get: function() { return 100; }, | |
configurable: true | |
}); | |
assert.areEqual(true, delete o[propName], "delete should succeed on configurable accessor property"); | |
o[propName] = 200; | |
assert.areEqual(200, o[propName]); | |
} | |
}, | |
test_305: { | |
name: "delete a setter property then set", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 303; | |
Object.defineProperty(o, propName, { | |
set: function(arg) { return 100; }, | |
configurable: true | |
}); | |
assert.areEqual(true, delete o[propName], "delete should succeed on configurable accessor property"); | |
o[propName] = 200; | |
assert.areEqual(200, o[propName]); | |
} | |
}, | |
test_306: { | |
name: "Set a property while prototype has a getter", | |
body: function() { | |
var propName = "abc"; | |
try { | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return 100; }, | |
configurable: true | |
}); | |
var o = helpers.getDummyObject(); | |
o[propName] = 200; // should have no effect since proto only has a getter | |
assert.areEqual(100, o[propName]); | |
} finally { | |
delete Object.prototype[propName]; | |
} | |
} | |
}, | |
test_306_i: { | |
name: "Set a property while prototype has a getter", | |
body: function() { | |
var propName = "306"; // Without quote it fails on array. Covered by 310_i | |
try { | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return 100; }, | |
configurable: true | |
}); | |
var o = helpers.getDummyObject(); | |
o[propName] = 200; // should have no effect since proto only has a getter | |
assert.areEqual(100, o[propName]); | |
} finally { | |
delete Object.prototype[propName]; | |
} | |
} | |
}, | |
test_307: { | |
name: "Define a property while prototype has a getter", | |
body: function() { | |
var propName = "abc"; | |
try { | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return 100; }, | |
configurable: true | |
}); | |
var o = helpers.getDummyObject(); | |
Object.defineProperty(o, propName, { value: 200 }); | |
assert.areEqual(200, o[propName]); //DefineOwnProperty succeeds | |
} finally { | |
delete Object.prototype[propName]; | |
} | |
} | |
}, | |
test_307_i: { | |
name: "Define a property while prototype has a getter", | |
body: function() { | |
var propName = 307; | |
try { | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return 100; }, | |
configurable: true | |
}); | |
var o = helpers.getDummyObject(); | |
Object.defineProperty(o, propName, { value: 200 }); | |
assert.areEqual(200, o[propName]); //DefineOwnProperty succeeds | |
} finally { | |
delete Object.prototype[propName]; | |
} | |
} | |
}, | |
test_308: { | |
disabled: true, // !!! Disable due to bug (to be opened) causing assertion !!! | |
pass: "misc", | |
name: "Set a property via object literal while prototype has a getter", | |
body: function() { | |
var propName = "abc"; | |
try { | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return 100; }, | |
configurable: true | |
}); | |
var o = {abc: 200}; | |
assert.areEqual(100, o[propName]); | |
} finally { | |
delete Object.prototype[propName]; | |
} | |
} | |
}, | |
test_308_i: { | |
pass: "misc", | |
name: "Set a property via object literal while prototype has a getter", | |
body: function() { | |
var propName = 308; | |
try { | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return 100; }, | |
configurable: true | |
}); | |
var o = {308: 200}; // succeeds since object literals do not check prototypes | |
assert.areEqual(200, o[propName]); | |
} finally { | |
delete Object.prototype[propName]; | |
} | |
} | |
}, | |
test_309_i: { | |
disabled: true, // !!! Disabled, Array doesn't honor prototype element attribute/getter/setter !!! | |
pass: "misc", | |
name: "Set a property while prototype property is not writable", | |
body: function() { | |
try { | |
Object.defineProperty(Object.prototype, 1, { | |
value: 100, | |
writable: false, | |
configurable: true | |
}); | |
var o = []; | |
assert.areEqual(100, o[1]); | |
o[1] = 200; // should have no effect since proto[1] is not writable | |
assert.areEqual(100, o[1]); | |
} finally { | |
delete Object.prototype[1]; | |
} | |
} | |
}, | |
test_310_i: { | |
disabled: true, // !!! Disabled, Array doesn't honor prototype element attribute/getter/setter !!! | |
pass: "misc", | |
name: "Set a property while prototype property is a getter", | |
body: function() { | |
try { | |
Object.defineProperty(Object.prototype, 1, { | |
get: function () { return 100; }, | |
configurable: true | |
}); | |
var o = []; | |
assert.areEqual(100, o[1]); | |
o[1] = 200; // should have no effect since proto[1] has only getter | |
assert.areEqual(100, o[1]); | |
} finally { | |
delete Object.prototype[1]; | |
} | |
} | |
}, | |
test_311_i: { | |
disabled: true, // !!! Disabled, Array doesn't honor prototype element attribute/getter/setter !!! | |
pass: "misc", | |
name: "Set a property while prototype property is getter/setter", | |
body: function() { | |
try { | |
var tmp = 100; | |
Object.defineProperty(Object.prototype, 1, { | |
get: function () { return tmp; }, | |
set: function(arg) { tmp = arg + 300; }, | |
configurable: true | |
}); | |
var o = []; | |
assert.areEqual(100, o[1]); | |
o[1] = 200; // should call setter | |
assert.areEqual(500, o[1]); | |
} finally { | |
delete Object.prototype[1]; | |
} | |
} | |
}, | |
test_312_i: { | |
name: "Test getter/setter on prototype receives the right this arg", | |
body: function() { | |
try { | |
var propName = "1"; //avoid array fast path for now | |
Object.prototype.tmp = 123; | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return this.tmp; }, | |
set: function (arg) { this.tmp = arg + 300; }, | |
configurable: true | |
}); | |
var o = helpers.getDummyObject(); | |
assert.areEqual(123, o[propName], "Should read data on prototype"); | |
o[propName] = 200; // should call proto setter on o | |
assert.areEqual(500, o.tmp, "setter should set data on o"); | |
assert.areEqual(500, o[propName], "Should read data on o"); | |
assert.areEqual(123, Object.prototype.tmp, "proto data unchanged"); | |
} finally { | |
delete Object.prototype[propName]; | |
delete Object.prototype.tmp; | |
} | |
} | |
}, | |
test_312a_i: { | |
name: "Test getter on prototype receives the right this arg", | |
body: function() { | |
try { | |
var propName = "1"; //avoid array fast path for now | |
Object.prototype.tmp = 123; | |
Object.defineProperty(Object.prototype, propName, { | |
get: function () { return this.tmp; }, | |
configurable: true | |
}); | |
var o = helpers.getDummyObject(); | |
o.length = 10; // Makes propName in length range, also prepare for indexOf | |
assert.areEqual(123, o[propName], "Should read data on prototype"); | |
o.tmp = 456; | |
assert.areEqual(456, o[propName], "Should read data on o"); | |
var i = Array.prototype.indexOf.apply(o, [456]); | |
assert.areEqual(propName, i.toString(), "getter should find data on o, not on prototype!"); | |
} finally { | |
delete Object.prototype[propName]; | |
delete Object.prototype.tmp; | |
} | |
} | |
}, | |
test_313_i: { | |
name: "preventExtensions with index property", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
o[1] = 1; | |
assert.areEqual(1, o[1]); | |
assert.areEqual(true, Object.isExtensible(o), "default is extensible"); | |
assert.areEqual(false, Object.isSealed(o), "default not sealed"); | |
assert.areEqual(false, Object.isFrozen(o), "default not frozen"); | |
Object.preventExtensions(o); | |
assert.areEqual(false, Object.isExtensible(o), "now NOT extensible"); | |
assert.areEqual(false, Object.isSealed(o), "still not sealed, o[1] configurable"); | |
assert.areEqual(false, Object.isFrozen(o), "still not frozen, o[1] configurable"); | |
o[1] = 11; // should succeed | |
assert.areEqual(11, o[1], "write should succeed"); | |
o[2] = 2; // should fail | |
assert.areEqual(undefined, o[2], "extend should fail"); | |
// verify unchanged | |
assert.areEqual(false, Object.isExtensible(o), "extensible not changed"); | |
assert.areEqual(false, Object.isSealed(o), "sealed not changed"); | |
assert.areEqual(false, Object.isFrozen(o), "frozen not changed"); | |
} | |
}, | |
test_314_i: { | |
name: "seal with index property", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
o[1] = 1; | |
Object.seal(o); | |
assert.areEqual(false, Object.isExtensible(o), "now NOT extensible"); | |
assert.areEqual(true, Object.isSealed(o), "now IS sealed"); | |
assert.areEqual(false, Object.isFrozen(o), "still not frozen, o[1] writable"); | |
o[1] = 11; // should succeed | |
assert.areEqual(11, o[1], "write should succeed"); | |
assert.areEqual(false, delete o[1], "delete should fail, object sealed"); | |
assert.areEqual(11, o[1], "delete should fail"); | |
o[2] = 2; // should fail | |
assert.areEqual(undefined, o[2], "extend should fail"); | |
// verify unchanged | |
assert.areEqual(false, Object.isExtensible(o), "extensible not changed"); | |
assert.areEqual(true, Object.isSealed(o), "sealed not changed"); | |
assert.areEqual(false, Object.isFrozen(o), "frozen not changed"); | |
} | |
}, | |
test_315_i: { | |
name: "freeze with index property", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
o[1] = 1; | |
Object.freeze(o); | |
assert.areEqual(false, Object.isExtensible(o), "now NOT extensible"); | |
assert.areEqual(true, Object.isSealed(o), "now IS sealed"); | |
assert.areEqual(true, Object.isFrozen(o), "now IS frozen"); | |
o[1] = 11; // should fail | |
assert.areEqual(1, o[1], "write should fail"); | |
assert.areEqual(false, delete o[1], "delete should fail, object sealed"); | |
assert.areEqual(1, o[1], "delete should fail"); | |
o[2] = 2; // should fail | |
assert.areEqual(undefined, o[2], "extend should fail"); | |
// verify unchanged | |
assert.areEqual(false, Object.isExtensible(o), "extensible not changed"); | |
assert.areEqual(true, Object.isSealed(o), "sealed not changed"); | |
assert.areEqual(true, Object.isFrozen(o), "frozen not changed"); | |
} | |
}, | |
test_316_i: { | |
name: "preventExtensions on empty object -> isSealed and isFrozen", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
Object.preventExtensions(o); // Haven't set any item yet, objectArray is null | |
assert.areEqual(false, Object.isExtensible(o), "NOT extensible"); | |
assert.areEqual(true, Object.isSealed(o), "IS sealed"); | |
assert.areEqual(true, Object.isFrozen(o) || Array.isArray(o), "IS frozen, unless isArray (length writable)"); | |
o[1] = 11; | |
assert.areEqual(undefined, o[1], "Write failed, not extensible"); | |
} | |
}, | |
test_317_i: { | |
name: "preventExtensions on object with an accessor -> isSealed and isFrozen", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 123; | |
Object.defineProperty(o, propName, {get: function(){ return "123"; }, configurable: false}); | |
Object.preventExtensions(o); | |
assert.areEqual(false, Object.isExtensible(o), "NOT extensible"); | |
assert.areEqual(true, Object.isSealed(o), "IS sealed"); | |
assert.areEqual(true, Object.isFrozen(o) || Array.isArray(o), "IS frozen, unless isArray (length writable)"); | |
o[1] = 11; | |
assert.areEqual(undefined, o[1], "Write failed, not extensible"); | |
assert.areEqual(false, delete o[propName], "delete should fail, not configurable"); | |
assert.areEqual("123", o[propName], "delete failed, not configurable"); | |
} | |
}, | |
test_318_i: { | |
name: "preventExtensions on object with data -> isSealed and isFrozen", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 123; | |
Object.defineProperty(o, propName, {value: 456, configurable: false, writable: true}); | |
Object.preventExtensions(o); | |
assert.areEqual(false, Object.isExtensible(o), "NOT extensible"); | |
assert.areEqual(true, Object.isSealed(o), "IS sealed"); | |
assert.areEqual(false, Object.isFrozen(o), "NOT frozen, data writable"); | |
} | |
}, | |
test_319_i: { | |
name: "preventExtensions on object with data -> isSealed and isFrozen", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 123; | |
Object.defineProperty(o, propName, {value: 456, configurable: false, writable: false}); | |
Object.preventExtensions(o); | |
assert.areEqual(false, Object.isExtensible(o), "NOT extensible"); | |
assert.areEqual(true, Object.isSealed(o), "IS sealed"); | |
assert.areEqual(true, Object.isFrozen(o) || Array.isArray(o), "IS frozen, unless isArray (length writable)"); | |
} | |
}, | |
test_320_i: { | |
name: "preventExtensions on object with data -> isSealed and isFrozen", | |
body: function() { | |
var o = helpers.getDummyObject(); | |
var propName = 123; | |
Object.defineProperty(o, propName, {value: 456, configurable: false, writable: false}); | |
o[234] = 345; | |
Object.preventExtensions(o); | |
assert.areEqual(false, Object.isExtensible(o), "NOT extensible"); | |
assert.areEqual(false, Object.isSealed(o), "NOT sealed, 234 configurable"); | |
assert.areEqual(false, Object.isFrozen(o), "NOT frozen, 234 configurable/writable"); | |
} | |
}, | |
test_321_i: { | |
name: "Test prototype value is used in sort", | |
body: function() { | |
try { | |
var propName = 1; | |
Object.defineProperty(Object.prototype, propName, { | |
value: 321, | |
writable: true, configurable: true, enumerable: true | |
}); | |
var o = helpers.getDummyObject(); | |
o[0] = 10; | |
o.length = 3; | |
o.sort = Array.prototype.sort; | |
o.join = Array.prototype.join; | |
o.toString = Array.prototype.toString; | |
o.sort(); | |
assert.areEqual("10,321,", o.toString(), "sort result mismatch?"); | |
} finally { | |
delete Object.prototype[propName]; | |
} | |
} | |
}, | |
test_322_i: { | |
name: "Convert accessor to a data property for non-extensible object (WIN8 bug 463559) but for numeric property", | |
body: function () { | |
var o = helpers.getDummyObject(); | |
var propertyName = "1"; | |
Object.defineProperty(o, propertyName, { | |
get: function() { return 0; }, | |
set: function(val) { helpers.writeln("setter was called although it shouldn't"); }, | |
configurable: true | |
}); | |
Object.preventExtensions(o); | |
var val = 1; | |
Object.defineProperty(o, propertyName, { value: val, }); | |
var expected = { value: val, configurable: true, enumerable: false, writable: false }; | |
assert.areEqual(expected, Object.getOwnPropertyDescriptor(o, propertyName), "wrong value of getOwnPropertyDescriptor"); | |
assert.areEqual(val, o[propertyName], "the property value is wrong"); | |
assert.areEqual(false, Object.isExtensible(o), "isExtensible() changed"); | |
} | |
}, | |
}; // tests. | |
var passes = { | |
pass1: { | |
name: "obj", | |
prep: function() { | |
helpers.getDummyObject = function() { | |
return {}; // a normal object | |
}; | |
} | |
}, | |
pass2: { | |
name: "arr", | |
prep: function() { | |
helpers.getDummyObject = function() { | |
return []; // a normal array | |
}; | |
} | |
}, | |
pass3: { | |
name: "es5arr", | |
prep: function() { | |
helpers.getDummyObject = function() { | |
var arr = []; | |
Object.defineProperty(arr, "12345", { | |
get: function() { | |
helpers.writeln("dummy called"); | |
}, | |
configurable: true | |
}); | |
delete arr[12345]; | |
return arr; // an ES5 array | |
}; | |
} | |
}, | |
pass4: { | |
name: "misc", | |
runonce: true, // Run misc tests only once | |
prep: function() { | |
helpers.getDummyObject = function() { | |
return null; // Misc tests do not use helpers.getDummyObject | |
}; | |
} | |
} | |
}; | |
testRunner.runTests(passes, tests); |