diff --git a/harness/propertyHelper.js b/harness/propertyHelper.js index 6d67e40511..54fadd1925 100644 --- a/harness/propertyHelper.js +++ b/harness/propertyHelper.js @@ -1,4 +1,74 @@ +function verifyProperty(obj, name, desc, options) { + assert( + arguments.length > 2, + 'verifyProperty should receive at least 3 arguments: obj, name, and descriptor' + ); + + var originalDesc = Object.getOwnPropertyDescriptor(obj, name); + var nameStr = String(name); + + // Allows checking for undefined descriptor if it's explicitly given. + if (desc === undefined) { + assert.sameValue( + originalDesc, + undefined, + `obj['${nameStr}'] descriptor should be undefined` + ); + + // desc and originalDesc are both undefined, problem solved; + return true; + } + + assert( + Object.prototype.hasOwnProperty.call(obj, name), + `obj should have an own property ${nameStr}` + ); + + assert.notSameValue( + desc, + null, + `The desc argument should be an object or undefined, null` + ); + + assert.sameValue( + typeof desc, + "object", + `The desc argument should be an object or undefined, ${String(desc)}` + ); + + var failures = []; + + if (Object.prototype.hasOwnProperty.call(desc, 'enumerable')) { + if (desc.enumerable !== originalDesc.enumerable || + desc.enumerable !== isEnumerable(obj, name)) { + failures.push(`descriptor should ${desc.enumerable ? '' : 'not '}be enumerable`); + } + } + + if (Object.prototype.hasOwnProperty.call(desc, 'writable')) { + if (desc.writable !== originalDesc.writable || + desc.writable !== isWritable(obj, name)) { + failures.push(`descriptor should ${desc.writable ? '' : 'not '}be writable`); + } + } + + if (Object.prototype.hasOwnProperty.call(desc, 'configurable')) { + if (desc.configurable !== originalDesc.configurable || + desc.configurable !== isConfigurable(obj, name)) { + failures.push(`descriptor should ${desc.configurable ? '' : 'not '}be configurable`); + } + } + + assert.sameValue(failures.length, 0, failures.join('; ')); + + if (options && options.restore) { + Object.defineProperty(obj, name, originalDesc); + } + + return true; +} + function isConfigurable(obj, name) { try { delete obj[name]; @@ -11,7 +81,7 @@ function isConfigurable(obj, name) { } function isEnumerable(obj, name) { - var stringCheck; + var stringCheck = false; if (typeof name === "string") { for (var x in obj) { diff --git a/test/harness/assert-throws-incorrect-ctor.js b/test/harness/assert-throws-incorrect-ctor.js index 47f4f0ba76..b12f06ee77 100644 --- a/test/harness/assert-throws-incorrect-ctor.js +++ b/test/harness/assert-throws-incorrect-ctor.js @@ -3,8 +3,8 @@ /*--- description: > - Functions that throw values whose constructor does not match the specified - constructor do not satisfy the assertion. + Functions that throw values whose constructor does not match the specified + constructor do not satisfy the assertion. ---*/ var threw = false; diff --git a/test/harness/verifyProperty-arguments.js b/test/harness/verifyProperty-arguments.js new file mode 100644 index 0000000000..9c2c9faaec --- /dev/null +++ b/test/harness/verifyProperty-arguments.js @@ -0,0 +1,25 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + verifyProperty should receive at least 3 arguments: obj, name, and descriptor +includes: [propertyHelper.js] +---*/ + +// monkeypatch the API +$ERROR = function $ERROR(message) { + throw new Test262Error(message); +}; + +assert.throws(Test262Error, () => { + verifyProperty(); +}, "0 arguments"); + +assert.throws(Test262Error, () => { + verifyProperty(Object); +}, "1 argument"); + +assert.throws(Test262Error, () => { + verifyProperty(Object, 'foo'); +}, "2 arguments"); diff --git a/test/harness/verifyProperty-desc-is-not-object.js b/test/harness/verifyProperty-desc-is-not-object.js new file mode 100644 index 0000000000..6df9700a97 --- /dev/null +++ b/test/harness/verifyProperty-desc-is-not-object.js @@ -0,0 +1,35 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + The desc argument should be an object or undefined +includes: [propertyHelper.js] +---*/ + +// monkeypatch the API +$ERROR = function $ERROR(message) { + throw new Test262Error(message); +}; + +var sample = { foo: 42 }; + +assert.throws(Test262Error, () => { + verifyProperty(sample, "foo", 'configurable'); +}, "string"); + +assert.throws(Test262Error, () => { + verifyProperty(sample, 'foo', true); +}, "boolean"); + +assert.throws(Test262Error, () => { + verifyProperty(sample, 'foo', 42); +}, "number"); + +assert.throws(Test262Error, () => { + verifyProperty(sample, 'foo', null); +}, "null"); + +assert.throws(Test262Error, () => { + verifyProperty(sample, 'foo', Symbol(1)); +}, "symbol"); diff --git a/test/harness/verifyProperty-noproperty.js b/test/harness/verifyProperty-noproperty.js new file mode 100644 index 0000000000..bc63830675 --- /dev/null +++ b/test/harness/verifyProperty-noproperty.js @@ -0,0 +1,21 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + The first argument should have an own property +includes: [propertyHelper.js] +---*/ + +// monkeypatch the API +$ERROR = function $ERROR(message) { + throw new Test262Error(message); +}; + +assert.throws(Test262Error, () => { + verifyProperty(Object, 'JeanPaulSartre', {}); +}, "inexisting property"); + +assert.throws(Test262Error, () => { + verifyProperty({}, 'hasOwnProperty', {}); +}, "inexisting own property"); diff --git a/test/harness/verifyProperty-restore-accessor-symbol.js b/test/harness/verifyProperty-restore-accessor-symbol.js new file mode 100644 index 0000000000..77d726d542 --- /dev/null +++ b/test/harness/verifyProperty-restore-accessor-symbol.js @@ -0,0 +1,42 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + verifyProperty allows restoring the original accessor descriptor +includes: [propertyHelper.js] +---*/ + +var obj; +var prop = Symbol(1); +var desc = { enumerable: true, configurable: true, get() { return 42; }, set() {} }; + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + false +); + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc, { restore: true }); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + true +); +assert.sameValue(obj[prop], 42); +assert.sameValue( + Object.getOwnPropertyDescriptor(obj, prop).get, + desc.get +); + +assert.sameValue( + Object.getOwnPropertyDescriptor(obj, prop).set, + desc.set +); diff --git a/test/harness/verifyProperty-restore-accessor.js b/test/harness/verifyProperty-restore-accessor.js new file mode 100644 index 0000000000..0a8b84dd34 --- /dev/null +++ b/test/harness/verifyProperty-restore-accessor.js @@ -0,0 +1,42 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + verifyProperty allows restoring the original accessor descriptor +includes: [propertyHelper.js] +---*/ + +var obj; +var prop = "prop"; +var desc = { enumerable: true, configurable: true, get() { return 42; }, set() {} }; + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + false +); + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc, { restore: true }); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + true +); +assert.sameValue(obj[prop], 42); +assert.sameValue( + Object.getOwnPropertyDescriptor(obj, prop).get, + desc.get +); + +assert.sameValue( + Object.getOwnPropertyDescriptor(obj, prop).set, + desc.set +); diff --git a/test/harness/verifyProperty-restore-symbol.js b/test/harness/verifyProperty-restore-symbol.js new file mode 100644 index 0000000000..a407412e56 --- /dev/null +++ b/test/harness/verifyProperty-restore-symbol.js @@ -0,0 +1,33 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + verifyProperty allows restoring the original descriptor +includes: [propertyHelper.js] +---*/ + +var obj; +var prop = Symbol(1); +var desc = { enumerable: true, configurable: true, writable: true, value: 42 }; + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + false +); + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc, { restore: true }); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + true +); +assert.sameValue(obj[prop], 42); diff --git a/test/harness/verifyProperty-restore.js b/test/harness/verifyProperty-restore.js new file mode 100644 index 0000000000..56c01e8e3e --- /dev/null +++ b/test/harness/verifyProperty-restore.js @@ -0,0 +1,33 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + verifyProperty allows restoring the original descriptor +includes: [propertyHelper.js] +---*/ + +var obj; +var prop = 'prop'; +var desc = { enumerable: true, configurable: true, writable: true, value: 42 }; + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + false +); + +obj = {}; +Object.defineProperty(obj, prop, desc); + +verifyProperty(obj, prop, desc, { restore: true }); + +assert.sameValue( + Object.prototype.hasOwnProperty.call(obj, prop), + true +); +assert.sameValue(obj[prop], 42); diff --git a/test/harness/verifyProperty-string-prop.js b/test/harness/verifyProperty-string-prop.js new file mode 100644 index 0000000000..c1c0338439 --- /dev/null +++ b/test/harness/verifyProperty-string-prop.js @@ -0,0 +1,51 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Verify property descriptor +includes: [propertyHelper.js] +---*/ + +var obj; +var prop = 'prop'; + +function reset(desc) { + obj = {}; + Object.defineProperty(obj, prop, desc); +} + +function checkDesc(desc) { + reset(desc); + assert(verifyProperty(obj, prop, desc)); + + reset(desc); + assert(verifyProperty(obj, prop, { enumerable: desc.enumerable })); + + reset(desc); + assert(verifyProperty(obj, prop, { writable: desc.writable })); + + reset(desc); + assert(verifyProperty(obj, prop, { configurable: desc.configurable })); + + reset(desc); + assert(verifyProperty(obj, prop, { configurable: desc.configurable, enumerable: desc.enumerable })); + + reset(desc); + assert(verifyProperty(obj, prop, { configurable: desc.configurable, writable: desc.writable })); + + reset(desc); + assert(verifyProperty(obj, prop, { writable: desc.writable, enumerable: desc.enumerable })); + + reset(desc); + assert(verifyProperty(obj, prop, { enumerable: desc.enumerable, configurable: desc.configurable })); +} + +checkDesc({ enumerable: true, configurable: true, writable: true }); +checkDesc({ enumerable: false, writable: false, configurable: false }); +checkDesc({ enumerable: true, writable: false, configurable: false }); +checkDesc({ enumerable: false, writable: true, configurable: false }); +checkDesc({ enumerable: false, writable: false, configurable: true }); +checkDesc({ enumerable: true, writable: false, configurable: true }); +checkDesc({ enumerable: true, writable: true, configurable: false }); +checkDesc({ enumerable: false, writable: true, configurable: true }); diff --git a/test/harness/verifyProperty-symbol-prop.js b/test/harness/verifyProperty-symbol-prop.js new file mode 100644 index 0000000000..3a59108d8d --- /dev/null +++ b/test/harness/verifyProperty-symbol-prop.js @@ -0,0 +1,51 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Verify symbol named property descriptor +includes: [propertyHelper.js] +---*/ + +var obj; +var prop = Symbol(1); + +function reset(desc) { + obj = {}; + Object.defineProperty(obj, prop, desc); +} + +function checkDesc(desc) { + reset(desc); + assert(verifyProperty(obj, prop, desc)); + + reset(desc); + assert(verifyProperty(obj, prop, { enumerable: desc.enumerable })); + + reset(desc); + assert(verifyProperty(obj, prop, { writable: desc.writable })); + + reset(desc); + assert(verifyProperty(obj, prop, { configurable: desc.configurable })); + + reset(desc); + assert(verifyProperty(obj, prop, { configurable: desc.configurable, enumerable: desc.enumerable })); + + reset(desc); + assert(verifyProperty(obj, prop, { configurable: desc.configurable, writable: desc.writable })); + + reset(desc); + assert(verifyProperty(obj, prop, { writable: desc.writable, enumerable: desc.enumerable })); + + reset(desc); + assert(verifyProperty(obj, prop, { enumerable: desc.enumerable, configurable: desc.configurable })); +} + +checkDesc({ enumerable: true, configurable: true, writable: true }); +checkDesc({ enumerable: false, writable: false, configurable: false }); +checkDesc({ enumerable: true, writable: false, configurable: false }); +checkDesc({ enumerable: false, writable: true, configurable: false }); +checkDesc({ enumerable: false, writable: false, configurable: true }); +checkDesc({ enumerable: true, writable: false, configurable: true }); +checkDesc({ enumerable: true, writable: true, configurable: false }); +checkDesc({ enumerable: false, writable: true, configurable: true }); diff --git a/test/harness/verifyProperty-undefined-desc.js b/test/harness/verifyProperty-undefined-desc.js new file mode 100644 index 0000000000..315061666d --- /dev/null +++ b/test/harness/verifyProperty-undefined-desc.js @@ -0,0 +1,32 @@ +// Copyright (C) 2017 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + Verify an undefined descriptor +includes: [propertyHelper.js] +---*/ + +// monkeypatch the API +$ERROR = function $ERROR(message) { + throw new Test262Error(message); +}; + +var sample = { + bar: undefined, + get baz() {} +}; + +assert.sameValue( + verifyProperty(sample, "foo", undefined), + true, + "returns true if desc and property descriptor are both undefined" +); + +assert.throws(Test262Error, () => { + verifyProperty(sample, 'bar', undefined); +}, "dataDescriptor value is undefined"); + +assert.throws(Test262Error, () => { + verifyProperty(sample, 'baz', undefined); +}, "accessor returns undefined");