| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| |
| if (typeof (WScript) != "undefined") { |
| WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js", "self"); |
| } |
| |
| var tests = { |
| // Note: each test has name (string) and body (function) properties. |
| // Success is when the body does not throw, failure -- when it throws. |
| |
| 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_v3"; |
| 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. |
| } |
| }, |
| |
| test34: { |
| name: "Convert accessor to a data property for non-extensible object (WIN8 bug 463559)", |
| body: function () { |
| var o = helpers.getDummyObject(); |
| var propertyName = "x"; |
| |
| 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"); |
| } |
| }, |
| |
| // Note: this test irreversibly changes the dummy object (that's important when dummy object is document/window), |
| // it should in the very end. |
| test_last_01: { |
| 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); |
| } |
| } |
| |
| }; // tests. |
| |
| testRunner.runTests(tests); |