diff options
Diffstat (limited to 'js/src/tests/ecma_6/Object')
36 files changed, 1392 insertions, 0 deletions
diff --git a/js/src/tests/ecma_6/Object/accessor-arguments-rest.js b/js/src/tests/ecma_6/Object/accessor-arguments-rest.js new file mode 100644 index 000000000..82f37b62e --- /dev/null +++ b/js/src/tests/ecma_6/Object/accessor-arguments-rest.js @@ -0,0 +1,24 @@ +assertThrowsInstanceOf(() => eval("({ get x(...a) { } })"), SyntaxError); +assertThrowsInstanceOf(() => eval("({ get x(a, ...b) { } })"), SyntaxError); +assertThrowsInstanceOf(() => eval("({ get x([a], ...b) { } })"), SyntaxError); +assertThrowsInstanceOf(() => eval("({ get x({a}, ...b) { } })"), SyntaxError); +assertThrowsInstanceOf(() => eval("({ get x({a: A}, ...b) { } })"), SyntaxError); + +assertThrowsInstanceOf(() => eval("({ set x(...a) { } })"), SyntaxError); +assertThrowsInstanceOf(() => eval("({ set x(a, ...b) { } })"), SyntaxError); +assertThrowsInstanceOf(() => eval("({ set x([a], ...b) { } })"), SyntaxError); +assertThrowsInstanceOf(() => eval("({ set x({a: A}, ...b) { } })"), SyntaxError); + +({ get(...a) { } }); +({ get(a, ...b) { } }); +({ get([a], ...b) { } }); +({ get({a}, ...b) { } }); +({ get({a: A}, ...b) { } }); + +({ set(...a) { } }); +({ set(a, ...b) { } }); +({ set([a], ...b) { } }); +({ set({a: A}, ...b) { } }); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/accessor-name.js b/js/src/tests/ecma_6/Object/accessor-name.js new file mode 100644 index 000000000..1b5268e07 --- /dev/null +++ b/js/src/tests/ecma_6/Object/accessor-name.js @@ -0,0 +1,36 @@ +function name(obj, property, get) { + let desc = Object.getOwnPropertyDescriptor(obj, property); + return (get ? desc.get : desc.set).name; +} + +assertEq(name({get a() {}}, "a", true), "get a"); +assertEq(name({set a(v) {}}, "a", false), "set a"); + +assertEq(name({get 123() {}}, "123", true), "get 123"); +assertEq(name({set 123(v) {}}, "123", false), "set 123"); + +assertEq(name({get case() {}}, "case", true), "get case"); +assertEq(name({set case(v) {}}, "case", false), "set case"); + +assertEq(name({get get() {}}, "get", true), "get get"); +assertEq(name({set set(v) {}}, "set", false), "set set"); + +let o = {get a() { }, set a(v) {}}; +assertEq(name(o, "a", true), "get a"); +assertEq(name(o, "a", false), "set a"); + +o = {get 123() { }, set 123(v) {}} +assertEq(name(o, "123", true), "get 123"); +assertEq(name(o, "123", false), "set 123"); + +o = {get case() { }, set case(v) {}} +assertEq(name(o, "case", true), "get case"); +assertEq(name(o, "case", false), "set case"); + +// Congratulations on implementing these! +assertEq(name({get ["a"]() {}}, "a", true), ""); +assertEq(name({get [123]() {}}, "123", true), ""); +assertEq(name({set ["a"](v) {}}, "a", false), ""); +assertEq(name({set [123](v) {}}, "123", false), ""); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/accessor-non-constructor.js b/js/src/tests/ecma_6/Object/accessor-non-constructor.js new file mode 100644 index 000000000..32d1d3467 --- /dev/null +++ b/js/src/tests/ecma_6/Object/accessor-non-constructor.js @@ -0,0 +1,20 @@ +var obj = { get a() { return 1; } }; +assertThrowsInstanceOf(() => { + new Object.getOwnPropertyDescriptor(obj, "a").get +}, TypeError); + +obj = { set a(b) { } }; +assertThrowsInstanceOf(() => { + new Object.getOwnPropertyDescriptor(obj, "a").set +}, TypeError); + +obj = { get a() { return 1; }, set a(b) { } }; +assertThrowsInstanceOf(() => { + new Object.getOwnPropertyDescriptor(obj, "a").get +}, TypeError); +assertThrowsInstanceOf(() => { + new Object.getOwnPropertyDescriptor(obj, "a").set +}, TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/assign.js b/js/src/tests/ecma_6/Object/assign.js new file mode 100644 index 000000000..5deb09c8e --- /dev/null +++ b/js/src/tests/ecma_6/Object/assign.js @@ -0,0 +1,303 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function checkDataProperty(object, propertyKey, value, writable, enumerable, configurable) { + var desc = Object.getOwnPropertyDescriptor(object, propertyKey); + assertEq(desc === undefined, false); + assertEq('value' in desc, true); + assertEq(desc.value, value); + assertEq(desc.writable, writable); + assertEq(desc.enumerable, enumerable); + assertEq(desc.configurable, configurable); +} + +/* 19.1.2.1 Object.assign ( target, ...sources ) */ +assertEq(Object.assign.length, 2); + +// Basic functionality works with multiple sources +function basicMultipleSources() { + var a = {}; + var b = { bProp : 7 }; + var c = { cProp : 8 }; + Object.assign(a, b, c); + assertEq(a.bProp, 7); + assertEq(a.cProp, 8); +} +basicMultipleSources(); + +// Basic functionality works with symbols (Bug 1052358) +function basicSymbols() { + var a = {}; + var b = { bProp : 7 }; + var aSymbol = Symbol("aSymbol"); + b[aSymbol] = 22; + Object.assign(a, b); + assertEq(a.bProp, 7); + assertEq(a[aSymbol], 22); +} +basicSymbols(); + +// Calls ToObject() for target, skips null/undefined sources, uses +// ToObject(source) otherwise. +function testToObject() { + assertThrowsInstanceOf(() => Object.assign(null, null), TypeError); + assertThrowsInstanceOf(() => Object.assign(), TypeError); + assertThrowsInstanceOf(() => Object.assign(null, {}), TypeError); + assertEq(Object.assign({}, null) instanceof Object, true); + assertEq(Object.assign({}, undefined) instanceof Object, true); + + // Technically an embedding could have this as extension acting differently + // from ours, so a feature-test is inadequate. We can move this subtest + // into extensions/ if that ever matters. + if (typeof objectEmulatingUndefined === "function") { + var falsyObject = objectEmulatingUndefined(); + falsyObject.foo = 7; + + var obj = Object.assign({}, falsyObject); + assertEq(obj instanceof Object, true); + assertEq(obj.foo, 7); + } + + assertEq(Object.assign(true, {}) instanceof Boolean, true); + assertEq(Object.assign(1, {}) instanceof Number, true); + assertEq(Object.assign("string", {}) instanceof String, true); + var o = {}; + assertEq(Object.assign(o, {}), o); +} +testToObject(); + +// Invokes [[OwnPropertyKeys]] on ToObject(source) +function testOwnPropertyKeys() { + assertThrowsInstanceOf(() => Object.assign(null, new Proxy({}, { + getOwnPropertyNames: () => { throw new Error("not called"); } + })), TypeError); + + var ownKeysCalled = false; + Object.assign({}, new Proxy({}, { + ownKeys: function() { + ownKeysCalled = true; + return []; + } + })); + assertEq(ownKeysCalled, true); +}; +testOwnPropertyKeys(); + +// Ensure correct property traversal +function correctPropertyTraversal() { + var log = ""; + var source = new Proxy({a: 1, b: 2}, { + ownKeys: () => ["b", "c", "a"], + getOwnPropertyDescriptor: function(t, pk) { + log += "#" + pk; + return Object.getOwnPropertyDescriptor(t, pk); + }, + get: function(t, pk, r) { + log += "-" + pk; + return t[pk]; + }, + }); + Object.assign({}, source); + assertEq(log, "#b-b#c#a-a"); +} +correctPropertyTraversal(); + +// Only [[Enumerable]] properties are assigned to target +function onlyEnumerablePropertiesAssigned() { + var source = Object.defineProperties({}, { + a: {value: 1, enumerable: true}, + b: {value: 2, enumerable: false}, + }); + var target = Object.assign({}, source); + assertEq("a" in target, true); + assertEq("b" in target, false); +} +onlyEnumerablePropertiesAssigned(); + + +// Enumerability is decided on-time, not before main loop (1) +function testEnumerabilityDeterminedInLoop1() +{ + var getterCalled = false; + var sourceTarget = { + get a() { getterCalled = true }, + get b() { Object.defineProperty(sourceTarget, "a", {enumerable: false}) }, + }; + var source = new Proxy(sourceTarget, { ownKeys: () => ["b", "a"] }); + Object.assign({}, source); + assertEq(getterCalled, false); +} +testEnumerabilityDeterminedInLoop1(); + +// Enumerability is decided on-time, not before main loop (2) +function testEnumerabilityDeterminedInLoop2() +{ + var getterCalled = false; + var sourceTarget = { + get a() { getterCalled = true }, + get b() { Object.defineProperty(sourceTarget, "a", {enumerable: true}) }, + }; + var source = new Proxy(sourceTarget, { + ownKeys: () => ["b", "a"] + }); + Object.defineProperty(sourceTarget, "a", {enumerable: false}); + Object.assign({}, source); + assertEq(getterCalled, true); +} +testEnumerabilityDeterminedInLoop2(); + +// Properties are retrieved through Get() and assigned onto +// the target as data properties, not in any sense cloned over as descriptors +function testPropertiesRetrievedThroughGet() { + var getterCalled = false; + Object.assign({}, {get a() { getterCalled = true }}); + assertEq(getterCalled, true); +} +testPropertiesRetrievedThroughGet(); + +// Properties are retrieved through Get() +// Properties are assigned through Put() +function testPropertiesAssignedThroughPut() { + var setterCalled = false; + Object.assign({set a(v) { setterCalled = v }}, {a: true}); + assertEq(setterCalled, true); +} +testPropertiesAssignedThroughPut(); + +// Properties are retrieved through Get() +// Properties are assigned through Put(): Existing property attributes are not altered +function propertiesAssignedExistingNotAltered() { + var source = {a: 1, b: 2, c: 3}; + var target = {a: 0, b: 0, c: 0}; + Object.defineProperty(target, "a", {enumerable: false}); + Object.defineProperty(target, "b", {configurable: false}); + Object.defineProperty(target, "c", {enumerable: false, configurable: false}); + Object.assign(target, source); + checkDataProperty(target, "a", 1, true, false, true); + checkDataProperty(target, "b", 2, true, true, false); + checkDataProperty(target, "c", 3, true, false, false); +} +propertiesAssignedExistingNotAltered(); + +// Properties are retrieved through Get() +// Properties are assigned through Put(): Throws TypeError if non-writable +function propertiesAssignedTypeErrorNonWritable() { + var source = {a: 1}; + var target = {a: 0}; + Object.defineProperty(target, "a", {writable: false}); + assertThrowsInstanceOf(() => Object.assign(target, source), TypeError); + checkDataProperty(target, "a", 0, false, true, true); +} +propertiesAssignedTypeErrorNonWritable(); + +// Properties are retrieved through Get() +// Put() creates standard properties; Property attributes from source are ignored +function createsStandardProperties() { + var source = {a: 1, b: 2, c: 3, get d() { return 4 }}; + Object.defineProperty(source, "b", {writable: false}); + Object.defineProperty(source, "c", {configurable: false}); + var target = Object.assign({}, source); + checkDataProperty(target, "a", 1, true, true, true); + checkDataProperty(target, "b", 2, true, true, true); + checkDataProperty(target, "c", 3, true, true, true); + checkDataProperty(target, "d", 4, true, true, true); +} +createsStandardProperties(); + +// Properties created during traversal are not copied +function propertiesCreatedDuringTraversalNotCopied() { + var source = {get a() { this.b = 2 }}; + var target = Object.assign({}, source); + assertEq("a" in target, true); + assertEq("b" in target, false); +} +propertiesCreatedDuringTraversalNotCopied(); + +// Properties deleted during traversal are not copied +function testDeletePropertiesNotCopied() { + var source = new Proxy({ + get a() { delete this.b }, + b: 2, + }, { + getOwnPropertyNames: () => ["a", "b"] + }); + var target = Object.assign({}, source); + assertEq("a" in target, true); + assertEq("b" in target, false); +} +testDeletePropertiesNotCopied(); + +function testDeletionExposingShadowedProperty() +{ + var srcProto = { b: 42 }; + var src = + Object.create(srcProto, + { a: { enumerable: true, get: function() { delete this.b; } }, + b: { value: 2, configurable: true, enumerable: true } }); + var source = new Proxy(src, { getOwnPropertyNames: () => ["a", "b"] }); + var target = Object.assign({}, source); + assertEq("a" in target, true); + assertEq("b" in target, false); +} +testDeletionExposingShadowedProperty(); + +// Properties first deleted and then recreated during traversal are copied (1) +function testDeletedAndRecreatedPropertiesCopied1() { + var source = new Proxy({ + get a() { delete this.c }, + get b() { this.c = 4 }, + c: 3, + }, { + getOwnPropertyNames: () => ["a", "b", "c"] + }); + var target = Object.assign({}, source); + assertEq("a" in target, true); + assertEq("b" in target, true); + assertEq("c" in target, true); + checkDataProperty(target, "c", 4, true, true, true); +} +testDeletedAndRecreatedPropertiesCopied1(); + +// Properties first deleted and then recreated during traversal are copied (2) +function testDeletedAndRecreatedPropertiesCopied2() { + var source = new Proxy({ + get a() { delete this.c }, + get b() { this.c = 4 }, + c: 3, + }, { + ownKeys: () => ["a", "c", "b"] + }); + var target = Object.assign({}, source); + assertEq("a" in target, true); + assertEq("b" in target, true); + assertEq("c" in target, false); +} +testDeletedAndRecreatedPropertiesCopied2(); + +// String and Symbol valued properties are copied +function testStringAndSymbolPropertiesCopied() { + var keyA = "str-prop"; + var source = {"str-prop": 1}; + var target = Object.assign({}, source); + checkDataProperty(target, keyA, 1, true, true, true); +} +testStringAndSymbolPropertiesCopied(); + +// Intermediate exceptions stop traversal and throw exception +function testExceptionsDoNotStopFirstReported1() { + var TestError = function TestError() {}; + var source = new Proxy({}, { + getOwnPropertyDescriptor: function(t, pk) { + assertEq(pk, "b"); + throw new TestError(); + }, + ownKeys: () => ["b", "a"] + }); + assertThrowsInstanceOf(() => Object.assign({}, source), TestError); +} +testExceptionsDoNotStopFirstReported1(); + + +if (typeof reportCompare == "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/browser.js b/js/src/tests/ecma_6/Object/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Object/browser.js diff --git a/js/src/tests/ecma_6/Object/bug-1150906.js b/js/src/tests/ecma_6/Object/bug-1150906.js new file mode 100644 index 000000000..27403cccf --- /dev/null +++ b/js/src/tests/ecma_6/Object/bug-1150906.js @@ -0,0 +1,13 @@ +function f(x) { + Object.defineProperty(arguments, 0, { + get: function() {} + }); + return arguments; +} + +var obj = f(1); +assertEq(obj[0], undefined); +assertEq(Object.getOwnPropertyDescriptor(obj, 0).set, undefined); +assertThrowsInstanceOf(() => { "use strict"; obj[0] = 1; }, TypeError); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/bug-1206700.js b/js/src/tests/ecma_6/Object/bug-1206700.js new file mode 100644 index 000000000..4918bcbec --- /dev/null +++ b/js/src/tests/ecma_6/Object/bug-1206700.js @@ -0,0 +1,10 @@ +var x = {}; +Reflect.set(x, "prop", 5, Object.prototype); +var y = {}; +Reflect.set(y, "prop", 6, Object.prototype); +assertEq(x.hasOwnProperty("prop"), false); +assertEq(y.hasOwnProperty("prop"), false); +assertEq(Object.prototype.hasOwnProperty("prop"), true); +assertEq(Object.prototype.prop, 6); + +reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/Object/defineProperties-order.js b/js/src/tests/ecma_6/Object/defineProperties-order.js new file mode 100644 index 000000000..417d10183 --- /dev/null +++ b/js/src/tests/ecma_6/Object/defineProperties-order.js @@ -0,0 +1,17 @@ +// Based on testcases provided by AndrĂ© Bargull + +let log = []; +let logger = new Proxy({}, { + get(target, key) { + log.push(key); + } +}); + +Object.create(null, new Proxy({a: {value: 0}, b: {value: 1}}, logger)); +assertEq(log.join(), "ownKeys,getOwnPropertyDescriptor,get,getOwnPropertyDescriptor,get"); + +log = []; +Object.defineProperties({}, new Proxy({a: {value: 0}, b: {value: 1}}, logger)); +assertEq(log.join(), "ownKeys,getOwnPropertyDescriptor,get,getOwnPropertyDescriptor,get"); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/defineProperty-proxy.js b/js/src/tests/ecma_6/Object/defineProperty-proxy.js new file mode 100644 index 000000000..b5ece940b --- /dev/null +++ b/js/src/tests/ecma_6/Object/defineProperty-proxy.js @@ -0,0 +1,54 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Test details of the implementation of ToPropertyDescriptor exposed to scripts +// thanks to scriptable proxies. + +// A LoggingProxy object logs certain operations performed on it. +var log = []; +function LoggingProxy(target) { + return new Proxy(target, { + has: function (t, id) { + log.push("has " + id); + return id in t; + }, + get: function (t, id) { + log.push("get " + id); + return t[id]; + } + }); +} + +// Tragically, we use separate code to implement Object.defineProperty on +// arrays and on proxies. So run the test three times. +var testSubjects = [ + {}, + [], + new Proxy({}, {}) +]; + +for (var obj of testSubjects) { + log = []; + + // Object.defineProperty is one public method that performs a + // ToPropertyDescriptor call. + Object.defineProperty(obj, "x", new LoggingProxy({ + enumerable: true, + configurable: true, + value: 3, + writable: true + })); + + // It should have performed exactly these operations on the proxy, in this + // order. See ES6 rev 24 (2014 April 27) 6.2.4.5 ToPropertyDescriptor. + assertDeepEq(log, [ + "has enumerable", "get enumerable", + "has configurable", "get configurable", + "has value", "get value", + "has writable", "get writable", + "has get", + "has set" + ]); +} + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/destructuring-shorthand-defaults.js b/js/src/tests/ecma_6/Object/destructuring-shorthand-defaults.js new file mode 100644 index 000000000..a03dea2a2 --- /dev/null +++ b/js/src/tests/ecma_6/Object/destructuring-shorthand-defaults.js @@ -0,0 +1,135 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Ensure that the syntax used in shorthand destructuring with defaults +// e.g. |{x=1, y=2} = {}| properly raises a syntax error within an object +// literal. As per ES6 12.2.6 Object Initializer, "NOTE 3." + +const SYNTAX_ERROR_STMTS = [ + // expressions + "({x={}={}}),", + "({y={x={}={}={}={}={}={}={}={}}={}}),", + "({a=1, b=2, c=3, x=({}={})}),", + "({x=1, y={z={1}}})", + "({x=1} = {y=1});", + "({x: y={z=1}}={})", + "({x=1}),", + "({z={x=1}})=>{};", + "({x = ({y=1}) => y})", + "(({x=1})) => x", + "({e=[]}==(;", + "({x=1}[-1]);", + "({x=y}[-9])", + "({x=y}.x.z[-9])", + "({x=y}`${-9}`)", + "(new {x=y}(-9))", + "new {x=1}", + "new {x=1}={}", + "typeof {x=1}", + "typeof ({x=1})", + "({x=y, [-9]:0})", + "((({w = x} >(-9)", + "++({x=1})", + "--{x=1}", + "!{x=1}={}", + "delete {x=1}", + "delete ({x=1})", + "delete {x=1} = {}", + "({x=1}.abc)", + "x > (0, {a = b} );", + // declarations + "var x = 0 + {a=1} = {}", + "let o = {x=1};", + "var j = {x=1};", + "var j = {x={y=1}}={};", + "const z = {x=1};", + "const z = {x={y=1}}={};", + "const {x=1};", + "const {x={y=33}}={};", + "var {x=1};", + "let {x=1};", + "let x, y, {z=1}={}, {w=2}, {e=3};", + // array initialization + "[{x=1, y = ({z=2} = {})}];", + // try/catch + "try {throw 'a';} catch ({x={y=1}}) {}", + // if/else + "if ({k: 1, x={y=2}={}}) {}", + "if (false) {} else if (true) { ({x=1}) }", + // switch + "switch ('c') { case 'c': ({x=1}); }", + // for + "for ({x=1}; 1;) {1}", + "for ({x={y=2}}; 1;) {1}", + "for (var x = 0; x < 2; x++) { ({x=1, y=2}) }", + "for (let x=1;{x=1};){}", + "for (let x=1;{x={y=2}};){}", + "for (let x=1;1;{x=1}){}", + "for (let x=1;1;{x={y=2}}){}", + // while + "while ({x=1}) {1};", + "while ({x={y=2}}={}) {1};", + // with + "with ({x=1}) {};", + "with ({x={y=3}={}}) {};", + "with (Math) { ({x=1}) };", + // ternary + "true ? {x=1} : 1;", + "false ? 1 : {x=1};", + "{x=1} ? 2 : 3;", +] + +for (var stmt of SYNTAX_ERROR_STMTS) { + assertThrowsInstanceOf(() => { + eval(stmt); + }, SyntaxError); +} + +const REFERENCE_ERROR_STMTS = [ + "({x} += {});", + "({x = 1}) = {x: 2};", +] + +for (var stmt of REFERENCE_ERROR_STMTS) { + assertThrowsInstanceOf(() => { + eval(stmt); + }, ReferenceError); +} + +// A few tricky but acceptable cases: +// see https://bugzilla.mozilla.org/show_bug.cgi?id=932080#c2 + +assertEq((({a = 0}) => a)({}), 0); +assertEq((({a = 0} = {}) => a)({}), 0); +assertEq((({a = 0} = {}) => a)({a: 1}), 1); + +{ + let x, y; + ({x=1} = {}); + assertEq(x, 1); + ({x=1} = {x: 4}); + assertEq(x, 4); + ({x=1, y=2} = {}) + assertEq(x, 1); + assertEq(y, 2); +} + +{ + let {x={i=1, j=2}={}}={}; + assertDeepEq(x, ({})); + assertEq(i, 1); + assertEq(j, 2); +} + +// Default destructuring values, which are variables, should be defined +// within closures (Bug 1255167). +{ + let f = function(a){ + return (function({aa = a}){ return aa; })({}); + }; + assertEq(f(9999), 9999); +} + +if (typeof reportCompare == "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/duplProps.js b/js/src/tests/ecma_6/Object/duplProps.js new file mode 100644 index 000000000..41b8d67fb --- /dev/null +++ b/js/src/tests/ecma_6/Object/duplProps.js @@ -0,0 +1,116 @@ +/* + * ES6 allows duplicate property names in object literals, even in strict mode. + * These tests modify the tests in test262 to reflect this change. + */ + +// test262/ch11/11.1/11.1.5/11.1.5-4-4-a-1-s.js +a = function() { "use strict"; return { foo: 0, foo : 1 }}; +assertEq(a().foo, 1); +a = function() { return { foo: 0, foo : 1 }}; +assertEq(a().foo, 1); + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-b-1.js +a = function() { "use strict"; return { foo : 1, get foo() { return 2; }}}; +assertEq(a().foo, 2); +a = function() { return { foo : 1, get foo() { return 2;} }}; +assertEq(a().foo, 2); + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-c-1.js +a = function() { "use strict"; return { get foo() { return 2; }, foo : 1 }}; +assertEq(a().foo, 1); +a = function() { return { get foo() { return 2; }, foo : 1 }}; +assertEq(a().foo, 1); + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-b-2.js +a = function() { "use strict"; return { foo : 1, set foo(a) { throw 2; }}}; +try { + a().foo = 5; + throw new Error("2 should be thrown here"); +} catch (e) { + if (e !== 2) + throw new Error("2 should be thrown here"); +} +a = function() { return { foo : 1, set foo(a) { throw 2;} }}; +try { + a().foo = 5; + throw new Error("2 should be thrown here"); +} catch (e) { + if (e !== 2) + throw new Error("2 should be thrown here"); +} + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-d-1.js +a = function() { "use strict"; return { get foo() { return 2; }, get foo() { return 3; } }}; +assertEq(a().foo, 3); +a = function() { return { get foo() { return 2; }, get foo() { return 3; } }}; +assertEq(a().foo, 3); + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-c-2.js +a = function() { "use strict"; return { set foo(a) { throw 2; }, foo : 1 }}; +assertEq(a().foo, 1); +a = function() { return { set foo(a) { throw 2; }, foo : 1 }}; +assertEq(a().foo, 1); + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-d-2.js +a = function() { "use strict"; return { set foo(a) { throw 2; }, set foo(a) { throw 3; }}}; +try { + a().foo = 5; + throw new Error("3 should be thrown here"); +} catch (e) { + if (e !== 3) + throw new Error("3 should be thrown here"); +} +a = function() { return { set foo(a) { throw 2; }, set foo(a) { throw 3; }}}; +try { + a().foo = 5; + throw new Error("3 should be thrown here"); +} catch (e) { + if (e !== 3) + throw new Error("3 should be thrown here"); +} + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-d-3.js +a = function() { "use strict"; return { get foo() { return 2; }, set foo(a) { throw 3; }, + get foo() { return 4; }}}; +try { + assertEq(a().foo, 4); + a().foo = 5; + throw new Error("3 should be thrown here"); +} catch (e) { + if (e !== 3) + throw new Error("3 should be thrown here"); +} +a = function() { return { get foo() { return 2; }, set foo(a) { throw 3; }, + get foo() { return 4; }}}; +try { + assertEq(a().foo, 4); + a().foo = 5; + throw new Error("3 should be thrown here"); +} catch (e) { + if (e !== 3) + throw new Error("3 should be thrown here"); +} + +// test262/ch11/11.1/11.1.5/11.1.5_4-4-d-4.js +a = function() { "use strict"; return { set foo(a) { throw 2; }, get foo() { return 4; }, + set foo(a) { throw 3; }}}; +try { + assertEq(a().foo, 4); + a().foo = 5; + throw new Error("3 should be thrown here"); +} catch (e) { + if (e !== 3) + throw new Error("3 should be thrown here"); +} +a = function() { return { set foo(a) { throw 2; }, get foo() { return 4; }, + set foo(a) { throw 3; }}}; +try { + assertEq(a().foo, 4); + a().foo = 5; + throw new Error("3 should be thrown here"); +} catch (e) { + if (e !== 3) + throw new Error("3 should be thrown here"); +} + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/freeze-proxy.js b/js/src/tests/ecma_6/Object/freeze-proxy.js new file mode 100644 index 000000000..3d95a28d4 --- /dev/null +++ b/js/src/tests/ecma_6/Object/freeze-proxy.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function logProxy(object = {}, handler = {}) { + var log = []; + var proxy = new Proxy(object, new Proxy(handler, { + get(target, propertyKey, receiver) { + log.push(propertyKey); + return target[propertyKey]; + } + })); + return {proxy, log}; +} + +// The order of operations is backwards when compared to ES6 draft rev 27 +// (2014 August 24), but see https://bugs.ecmascript.org/show_bug.cgi?id=3215 +// for an explanation on why the spec version is clearly wrong. + +var {proxy, log} = logProxy(); +Object.freeze(proxy); +assertDeepEq(log, ["preventExtensions", "ownKeys"]); + +var {proxy, log} = logProxy(); +Object.freeze(Object.freeze(proxy)); +assertDeepEq(log, ["preventExtensions", "ownKeys", "preventExtensions", "ownKeys"]); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/freeze.js b/js/src/tests/ecma_6/Object/freeze.js new file mode 100644 index 000000000..18f71f76d --- /dev/null +++ b/js/src/tests/ecma_6/Object/freeze.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1076588; +var summary = "Object.freeze() should return its argument with no conversion when the argument is a primitive value"; + +print(BUGNUMBER + ": " + summary); +assertEq(Object.freeze(), undefined); +assertEq(Object.freeze(undefined), undefined); +assertEq(Object.freeze(null), null); +assertEq(Object.freeze(1), 1); +assertEq(Object.freeze("foo"), "foo"); +assertEq(Object.freeze(true), true); +if (typeof Symbol === "function") { + assertEq(Object.freeze(Symbol.for("foo")), Symbol.for("foo")); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/getOwnPropertyDescriptor.js b/js/src/tests/ecma_6/Object/getOwnPropertyDescriptor.js new file mode 100644 index 000000000..7aaba7b5e --- /dev/null +++ b/js/src/tests/ecma_6/Object/getOwnPropertyDescriptor.js @@ -0,0 +1,35 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1079188; +var summary = "Coerce the argument passed to Object.getOwnPropertyDescriptor using ToObject"; +print(BUGNUMBER + ": " + summary); + +assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(), TypeError); +assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(undefined), TypeError); +assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(null), TypeError); + +Object.getOwnPropertyDescriptor(1); +Object.getOwnPropertyDescriptor(true); +if (typeof Symbol === "function") { + Object.getOwnPropertyDescriptor(Symbol("foo")); +} + +assertDeepEq(Object.getOwnPropertyDescriptor("foo", "length"), { + value: 3, + writable: false, + enumerable: false, + configurable: false +}); + +assertDeepEq(Object.getOwnPropertyDescriptor("foo", 0), { + value: "f", + writable: false, + enumerable: true, + configurable: false +}); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/getOwnPropertySymbols-proxy.js b/js/src/tests/ecma_6/Object/getOwnPropertySymbols-proxy.js new file mode 100644 index 000000000..56f20afb3 --- /dev/null +++ b/js/src/tests/ecma_6/Object/getOwnPropertySymbols-proxy.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// getOwnPropertySymbols(proxy) calls the getOwnPropertyNames hook (only). + +var symbols = [Symbol(), Symbol("moon"), Symbol.for("sun"), Symbol.iterator]; +var hits = 0; + +function HandlerProxy() { + return new Proxy({}, { + get: function (t, key) { + if (key !== "ownKeys") + throw new Error("tried to access handler[" + uneval(key) + "]"); + hits++; + return t => symbols; + } + }); +} + +function OwnKeysProxy() { + return new Proxy({}, new HandlerProxy); +} + +assertDeepEq(Object.getOwnPropertySymbols(new OwnKeysProxy), symbols); +assertEq(hits, 1); + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/getOwnPropertySymbols.js b/js/src/tests/ecma_6/Object/getOwnPropertySymbols.js new file mode 100644 index 000000000..b92d14ef1 --- /dev/null +++ b/js/src/tests/ecma_6/Object/getOwnPropertySymbols.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +assertDeepEq(Object.getOwnPropertySymbols({}), []); + +// String keys are ignored. +assertEq(Object.getOwnPropertySymbols({a: 1, b: 2}).length, 0); +assertEq(Object.getOwnPropertySymbols([0, 1, 2, 3]).length, 0); + +// Symbol keys are observed. +var iterable = {}; +Object.defineProperty(iterable, Symbol.iterator, { + value: () => [][Symbol.iterator]() +}); +assertDeepEq(Object.getOwnPropertySymbols(iterable), [Symbol.iterator]); +assertDeepEq(Object.getOwnPropertySymbols(new Proxy(iterable, {})), [Symbol.iterator]); + +// Test on an object with a thousand own properties. +var obj = {}; +for (var i = 0; i < 1000; i++) { + obj[Symbol.for("x" + i)] = 1; +} +assertEq(Object.getOwnPropertyNames(obj).length, 0); +var symbols = Object.getOwnPropertySymbols(obj); +assertEq(symbols.length, 1000); +assertEq(symbols.indexOf(Symbol.for("x0")) !== -1, true); +assertEq(symbols.indexOf(Symbol.for("x241")) !== -1, true); +assertEq(symbols.indexOf(Symbol.for("x999")) !== -1, true); +assertEq(Object.getOwnPropertySymbols(new Proxy(obj, {})).length, 1000); + +// The prototype chain is not consulted. +assertEq(Object.getOwnPropertySymbols(Object.create(obj)).length, 0); +assertEq(Object.getOwnPropertySymbols(new Proxy(Object.create(obj), {})).length, 0); + +// Primitives are coerced to objects; but there are never any symbol-keyed +// properties on the resulting wrapper objects. +assertThrowsInstanceOf(() => Object.getOwnPropertySymbols(), TypeError); +assertThrowsInstanceOf(() => Object.getOwnPropertySymbols(undefined), TypeError); +assertThrowsInstanceOf(() => Object.getOwnPropertySymbols(null), TypeError); +for (var primitive of [true, 1, 3.14, "hello", Symbol()]) + assertEq(Object.getOwnPropertySymbols(primitive).length, 0); + +assertEq(Object.getOwnPropertySymbols.length, 1); + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/getPrototypeOf.js b/js/src/tests/ecma_6/Object/getPrototypeOf.js new file mode 100644 index 000000000..71cd30c62 --- /dev/null +++ b/js/src/tests/ecma_6/Object/getPrototypeOf.js @@ -0,0 +1,22 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1079090; +var summary = "Coerce the argument passed to Object.getPrototypeOf using ToObject"; +print(BUGNUMBER + ": " + summary); + +assertThrowsInstanceOf(() => Object.getPrototypeOf(), TypeError); +assertThrowsInstanceOf(() => Object.getPrototypeOf(undefined), TypeError); +assertThrowsInstanceOf(() => Object.getPrototypeOf(null), TypeError); + +assertEq(Object.getPrototypeOf(1), Number.prototype); +assertEq(Object.getPrototypeOf(true), Boolean.prototype); +assertEq(Object.getPrototypeOf("foo"), String.prototype); +if (typeof Symbol === "function") { + assertEq(Object.getPrototypeOf(Symbol("foo")), Symbol.prototype); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/getter-name.js b/js/src/tests/ecma_6/Object/getter-name.js new file mode 100644 index 000000000..601d6b477 --- /dev/null +++ b/js/src/tests/ecma_6/Object/getter-name.js @@ -0,0 +1,10 @@ +var BUGNUMBER = 1180290; +var summary = 'Object accessors should have get prefix'; + +print(BUGNUMBER + ": " + summary); + +assertEq(Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").get.name, "get __proto__"); +assertEq(Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").set.name, "set __proto__"); + +if (typeof reportCompare === 'function') + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/isExtensible.js b/js/src/tests/ecma_6/Object/isExtensible.js new file mode 100644 index 000000000..f1fa00878 --- /dev/null +++ b/js/src/tests/ecma_6/Object/isExtensible.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var BUGNUMBER = 1060873; +var summary = "Object.isExtensible() should return false when given primitive values as input"; + +print(BUGNUMBER + ": " + summary); +assertEq(Object.isExtensible(), false); +assertEq(Object.isExtensible(undefined), false); +assertEq(Object.isExtensible(null), false); +assertEq(Object.isExtensible(1), false); +assertEq(Object.isExtensible("foo"), false); +assertEq(Object.isExtensible(true), false); +if (typeof Symbol === "function") { + assertEq(Object.isExtensible(Symbol()), false); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/isFrozen.js b/js/src/tests/ecma_6/Object/isFrozen.js new file mode 100644 index 000000000..02056802d --- /dev/null +++ b/js/src/tests/ecma_6/Object/isFrozen.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1071464; +var summary = "Object.isFrozen() should return true when given primitive values as input"; + +print(BUGNUMBER + ": " + summary); +assertEq(Object.isFrozen(), true); +assertEq(Object.isFrozen(undefined), true); +assertEq(Object.isFrozen(null), true); +assertEq(Object.isFrozen(1), true); +assertEq(Object.isFrozen("foo"), true); +assertEq(Object.isFrozen(true), true); +if (typeof Symbol === "function") { + assertEq(Object.isFrozen(Symbol()), true); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/isSealed.js b/js/src/tests/ecma_6/Object/isSealed.js new file mode 100644 index 000000000..cd363a87e --- /dev/null +++ b/js/src/tests/ecma_6/Object/isSealed.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1062860; +var summary = "Object.isSealed() should return true when given primitive values as input"; + +print(BUGNUMBER + ": " + summary); +assertEq(Object.isSealed(), true); +assertEq(Object.isSealed(undefined), true); +assertEq(Object.isSealed(null), true); +assertEq(Object.isSealed(1), true); +assertEq(Object.isSealed("foo"), true); +assertEq(Object.isSealed(true), true); +if (typeof Symbol === "function") { + assertEq(Object.isSealed(Symbol()), true); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/keys.js b/js/src/tests/ecma_6/Object/keys.js new file mode 100644 index 000000000..5766f16d1 --- /dev/null +++ b/js/src/tests/ecma_6/Object/keys.js @@ -0,0 +1,23 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1038545; +var summary = "Coerce the argument passed to Object.keys using ToObject"; +print(BUGNUMBER + ": " + summary); + +assertThrowsInstanceOf(() => Object.keys(), TypeError); +assertThrowsInstanceOf(() => Object.keys(undefined), TypeError); +assertThrowsInstanceOf(() => Object.keys(null), TypeError); + +assertDeepEq(Object.keys(1), []); +assertDeepEq(Object.keys(true), []); +if (typeof Symbol === "function") { + assertDeepEq(Object.keys(Symbol("foo")), []); +} + +assertDeepEq(Object.keys("foo"), ["0", "1", "2"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/method-non-constructor.js b/js/src/tests/ecma_6/Object/method-non-constructor.js new file mode 100644 index 000000000..fd1d589b9 --- /dev/null +++ b/js/src/tests/ecma_6/Object/method-non-constructor.js @@ -0,0 +1,12 @@ +var obj = { method() { } }; +assertThrowsInstanceOf(() => { + new obj.method; +}, TypeError); + +obj = { constructor() { } }; +assertThrowsInstanceOf(() => { + new obj.constructor; +}, TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/preventExtensions-proxy.js b/js/src/tests/ecma_6/Object/preventExtensions-proxy.js new file mode 100644 index 000000000..347a63bc3 --- /dev/null +++ b/js/src/tests/ecma_6/Object/preventExtensions-proxy.js @@ -0,0 +1,23 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function logProxy(object = {}, handler = {}) { + var log = []; + var proxy = new Proxy(object, new Proxy(handler, { + get(target, propertyKey, receiver) { + log.push(propertyKey); + return target[propertyKey]; + } + })); + return {proxy, log}; +} + +var {proxy, log} = logProxy(); +Object.preventExtensions(proxy); +assertDeepEq(log, ["preventExtensions"]); + +var {proxy, log} = logProxy(); +Object.preventExtensions(Object.preventExtensions(proxy)); +assertDeepEq(log, ["preventExtensions", "preventExtensions"]); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/preventExtensions.js b/js/src/tests/ecma_6/Object/preventExtensions.js new file mode 100644 index 000000000..75c8ed3db --- /dev/null +++ b/js/src/tests/ecma_6/Object/preventExtensions.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1073446; +var summary = "Object.preventExtensions() should return its argument with no conversion when the argument is a primitive value"; + +print(BUGNUMBER + ": " + summary); +assertEq(Object.preventExtensions(), undefined); +assertEq(Object.preventExtensions(undefined), undefined); +assertEq(Object.preventExtensions(null), null); +assertEq(Object.preventExtensions(1), 1); +assertEq(Object.preventExtensions("foo"), "foo"); +assertEq(Object.preventExtensions(true), true); +if (typeof Symbol === "function") { + assertEq(Object.preventExtensions(Symbol.for("foo")), Symbol.for("foo")); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/property-descriptor-order.js b/js/src/tests/ecma_6/Object/property-descriptor-order.js new file mode 100644 index 000000000..337d247da --- /dev/null +++ b/js/src/tests/ecma_6/Object/property-descriptor-order.js @@ -0,0 +1,17 @@ +var names = Object.getOwnPropertyNames(Object.getOwnPropertyDescriptor({foo: 0}, "foo")); +assertDeepEq(names, ["value", "writable", "enumerable", "configurable"]); + +names = Object.getOwnPropertyNames(Object.getOwnPropertyDescriptor({get foo(){}}, "foo")); +assertDeepEq(names, ["get", "set", "enumerable", "configurable"]); + +var proxy = new Proxy({}, { + defineProperty(target, key, desc) { + var names = Object.getOwnPropertyNames(desc); + assertDeepEq(names, ["set", "configurable"]); + return true; + } +}); + +Object.defineProperty(proxy, "foo", {configurable: true, set: function() {}}); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/propertyIsEnumerable-proxy.js b/js/src/tests/ecma_6/Object/propertyIsEnumerable-proxy.js new file mode 100644 index 000000000..a1dda90e0 --- /dev/null +++ b/js/src/tests/ecma_6/Object/propertyIsEnumerable-proxy.js @@ -0,0 +1,59 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function logProxy(object) { + var log = []; + var handler = { + getOwnPropertyDescriptor(target, propertyKey) { + log.push(propertyKey); + return Object.getOwnPropertyDescriptor(target, propertyKey); + } + }; + var proxy = new Proxy(object, new Proxy(handler, { + get(target, propertyKey, receiver) { + if (!(propertyKey in target)) { + throw new Error(`Unexpected call to trap: "${propertyKey}"`); + } + return target[propertyKey]; + } + })); + return {proxy, log}; +} + +var properties = ["string-property"]; +if (typeof Symbol === 'function') + properties.push(Symbol("symbol-property")); + +for (var property of properties) { + // Test 1: property is not present on object + var {proxy, log} = logProxy({}); + var result = Object.prototype.propertyIsEnumerable.call(proxy, property); + assertEq(result, false); + assertDeepEq(log, [property]); + + // Test 2: property is present on object and enumerable + var {proxy, log} = logProxy({[property]: 0}); + var result = Object.prototype.propertyIsEnumerable.call(proxy, property); + assertEq(result, true); + assertDeepEq(log, [property]); + + // Test 3: property is present on object, but not enumerable + var {proxy, log} = logProxy(Object.defineProperty({[property]: 0}, property, {enumerable: false})); + var result = Object.prototype.propertyIsEnumerable.call(proxy, property); + assertEq(result, false); + assertDeepEq(log, [property]); + + // Test 4: property is present on prototype object + var {proxy, log} = logProxy(Object.create({[property]: 0})); + var result = Object.prototype.propertyIsEnumerable.call(proxy, property); + assertEq(result, false); + assertDeepEq(log, [property]); + + // Test 5: property is present on prototype object, prototype is proxy object + var {proxy, log} = logProxy({[property]: 0}); + var result = Object.prototype.propertyIsEnumerable.call(Object.create(proxy), property); + assertEq(result, false); + assertDeepEq(log, []); +} + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/seal-proxy.js b/js/src/tests/ecma_6/Object/seal-proxy.js new file mode 100644 index 000000000..44bb685c8 --- /dev/null +++ b/js/src/tests/ecma_6/Object/seal-proxy.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function logProxy(object = {}, handler = {}) { + var log = []; + var proxy = new Proxy(object, new Proxy(handler, { + get(target, propertyKey, receiver) { + log.push(propertyKey); + return target[propertyKey]; + } + })); + return {proxy, log}; +} + +// The order of operations is backwards when compared to ES6 draft rev 27 +// (2014 August 24), but see https://bugs.ecmascript.org/show_bug.cgi?id=3215 +// for an explanation on why the spec version is clearly wrong. + +var {proxy, log} = logProxy(); +Object.seal(proxy); +assertDeepEq(log, ["preventExtensions", "ownKeys"]); + +var {proxy, log} = logProxy(); +Object.seal(Object.seal(proxy)); +assertDeepEq(log, ["preventExtensions", "ownKeys", "preventExtensions", "ownKeys"]); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/seal.js b/js/src/tests/ecma_6/Object/seal.js new file mode 100644 index 000000000..e325c80d9 --- /dev/null +++ b/js/src/tests/ecma_6/Object/seal.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +var BUGNUMBER = 1075294; +var summary = "Object.seal() should return its argument with no conversion when the argument is a primitive value"; + +print(BUGNUMBER + ": " + summary); +assertEq(Object.seal(), undefined); +assertEq(Object.seal(undefined), undefined); +assertEq(Object.seal(null), null); +assertEq(Object.seal(1), 1); +assertEq(Object.seal("foo"), "foo"); +assertEq(Object.seal(true), true); +if (typeof Symbol === "function") { + assertEq(Object.seal(Symbol.for("foo")), Symbol.for("foo")); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/setPrototypeOf-cross-realm-cycle.js b/js/src/tests/ecma_6/Object/setPrototypeOf-cross-realm-cycle.js new file mode 100644 index 000000000..e2efe010e --- /dev/null +++ b/js/src/tests/ecma_6/Object/setPrototypeOf-cross-realm-cycle.js @@ -0,0 +1,11 @@ +// The cycle check in 9.1.2 [[SetPrototypeOf]] prevents cross-realm cycles +// involving only ordinary objects. + +var gw = newGlobal(); + +var obj = {}; +var w = gw.Object.create(obj); +assertThrowsInstanceOf(() => Object.setPrototypeOf(obj, w), TypeError); +assertThrowsInstanceOf(() => gw.Object.setPrototypeOf(obj, w), gw.TypeError); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/setPrototypeOf-cycle.js b/js/src/tests/ecma_6/Object/setPrototypeOf-cycle.js new file mode 100644 index 000000000..a8b5aa75c --- /dev/null +++ b/js/src/tests/ecma_6/Object/setPrototypeOf-cycle.js @@ -0,0 +1,16 @@ +// The cycle check in 9.1.2 [[SetPrototypeOf]] does not walk proxies. +// Therefore it's very easy to create prototype chain cycles involving proxies, +// and the spec requires us to accept this. + +var t = {}; +var p = new Proxy(t, {}); +Object.setPrototypeOf(t, p); // đŸ™ˆ + +// Actually doing anything that searches this object's prototype chain +// technically should not terminate. We instead throw "too much recursion". +for (var obj of [t, p]) { + assertThrowsInstanceOf(() => "x" in obj, InternalError); + assertThrowsInstanceOf(() => obj.x, InternalError); + assertThrowsInstanceOf(() => { obj.x = 1; }, InternalError); +} +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/setPrototypeOf-same-value.js b/js/src/tests/ecma_6/Object/setPrototypeOf-same-value.js new file mode 100644 index 000000000..337550946 --- /dev/null +++ b/js/src/tests/ecma_6/Object/setPrototypeOf-same-value.js @@ -0,0 +1,11 @@ +// Setting a "new" prototype to the current [[Prototype]] value should never fail + +var x = {}, t = Object.create(x); +Object.preventExtensions(t); +// Should not fail, because it is the same [[Prototype]] value +Object.setPrototypeOf(t, x); + +// Object.prototype's [[Prototype]] is immutable, make sure we can still set null +Object.setPrototypeOf(Object.prototype, null); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/shell.js b/js/src/tests/ecma_6/Object/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Object/shell.js diff --git a/js/src/tests/ecma_6/Object/toLocaleString.js b/js/src/tests/ecma_6/Object/toLocaleString.js new file mode 100644 index 000000000..3fa2acc74 --- /dev/null +++ b/js/src/tests/ecma_6/Object/toLocaleString.js @@ -0,0 +1,13 @@ +"use strict"; + +Object.defineProperty(String.prototype, "toString", { + get() { + assertEq(typeof this, "string"); + + return function() { return typeof this; }; + } +}) +assertEq(Object.prototype.toLocaleString.call("test"), "string"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Object/toPrimitive-callers.js b/js/src/tests/ecma_6/Object/toPrimitive-callers.js new file mode 100644 index 000000000..ffeef2225 --- /dev/null +++ b/js/src/tests/ecma_6/Object/toPrimitive-callers.js @@ -0,0 +1,57 @@ +// Check all the algorithms that call ToPrimitive. Confirm that they're passing +// the correct hint, per spec. + +var STRING = "xyzzy"; +var NUMBER = 42; + +function assertCallsToPrimitive(f, expectedHint, expectedResult) { + var hint = undefined; + var testObj = { + [Symbol.toPrimitive](h) { + assertEq(hint, undefined); + hint = h; + return h === "number" ? NUMBER : STRING; + } + }; + var result = f(testObj); + assertEq(hint, expectedHint, String(f)); + assertEq(result, expectedResult, String(f)); +} + +// ToNumber +assertCallsToPrimitive(Number, "number", NUMBER); + +// ToString +assertCallsToPrimitive(String, "string", STRING); + +// ToPropertyKey +var obj = {[STRING]: "pass"}; +assertCallsToPrimitive(key => obj[key], "string", "pass"); + +// Abstract Relational Comparison +assertCallsToPrimitive(x => x >= 42, "number", true); +assertCallsToPrimitive(x => x > "42", "number", false); + +// Abstract Equality Comparison +assertCallsToPrimitive(x => x != STRING, "default", false); +assertCallsToPrimitive(x => STRING == x, "default", true); +assertCallsToPrimitive(x => x == NUMBER, "default", false); +assertCallsToPrimitive(x => NUMBER != x, "default", true); + +// Addition +assertCallsToPrimitive(x => 1 + x, "default", "1" + STRING); +assertCallsToPrimitive(x => "" + x, "default", STRING); + +// Date constructor +assertCallsToPrimitive(x => (new Date(x)).valueOf(), "default", Number(STRING)); + +// Date.prototype.toJSON +var expected = "a suffusion of yellow"; +function testJSON(x) { + x.toJSON = Date.prototype.toJSON; + x.toISOString = function () { return expected; }; + return JSON.stringify(x); +} +assertCallsToPrimitive(testJSON, "number", JSON.stringify(expected)); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Object/toPrimitive.js b/js/src/tests/ecma_6/Object/toPrimitive.js new file mode 100644 index 000000000..0904bd19a --- /dev/null +++ b/js/src/tests/ecma_6/Object/toPrimitive.js @@ -0,0 +1,101 @@ +// ES6 7.1.1 ToPrimitive(input [, PreferredType]) specifies a new extension +// point in the language. Objects can override the behavior of ToPrimitive +// somewhat by supporting the method obj[@@toPrimitive](hint). +// +// (Rationale: ES5 had a [[DefaultValue]] internal method, overridden only by +// Date objects. The change in ES6 is to make [[DefaultValue]] a plain old +// method. This allowed ES6 to eliminate the [[DefaultValue]] internal method, +// simplifying the meta-object protocol and thus proxies.) + +// obj[Symbol.toPrimitive]() is called whenever the ToPrimitive algorithm is invoked. +var expectedThis, expectedHint; +var obj = { + [Symbol.toPrimitive](hint, ...rest) { + assertEq(this, expectedThis); + assertEq(hint, expectedHint); + assertEq(rest.length, 0); + return 2015; + } +}; +expectedThis = obj; +expectedHint = "string"; +assertEq(String(obj), "2015"); +expectedHint = "number"; +assertEq(Number(obj), 2015); + +// It is called even through proxies. +var proxy = new Proxy(obj, {}); +expectedThis = proxy; +expectedHint = "default"; +assertEq("ES" + proxy, "ES2015"); + +// It is called even through additional proxies and the prototype chain. +proxy = new Proxy(Object.create(proxy), {}); +expectedThis = proxy; +expectedHint = "default"; +assertEq("ES" + (proxy + 1), "ES2016"); + +// It is not called if the operand is already a primitive. +var ok = true; +for (var constructor of [Boolean, Number, String, Symbol]) { + constructor.prototype[Symbol.toPrimitive] = function () { + ok = false; + throw "FAIL"; + }; +} +assertEq(Number(true), 1); +assertEq(Number(77.7), 77.7); +assertEq(Number("123"), 123); +assertThrowsInstanceOf(() => Number(Symbol.iterator), TypeError); +assertEq(String(true), "true"); +assertEq(String(77.7), "77.7"); +assertEq(String("123"), "123"); +assertEq(String(Symbol.iterator), "Symbol(Symbol.iterator)"); +assertEq(ok, true); + +// Converting a primitive symbol to another primitive type throws even if you +// delete the @@toPrimitive method from Symbol.prototype. +delete Symbol.prototype[Symbol.toPrimitive]; +var sym = Symbol("ok"); +assertThrowsInstanceOf(() => `${sym}`, TypeError); +assertThrowsInstanceOf(() => Number(sym), TypeError); +assertThrowsInstanceOf(() => "" + sym, TypeError); + +// However, having deleted that method, converting a Symbol wrapper object does +// work: it calls Symbol.prototype.toString(). +obj = Object(sym); +assertEq(String(obj), "Symbol(ok)"); +assertEq(`${obj}`, "Symbol(ok)"); + +// Deleting valueOf as well makes numeric conversion also call toString(). +delete Symbol.prototype.valueOf; +delete Object.prototype.valueOf; +assertEq(Number(obj), NaN); +Symbol.prototype.toString = function () { return "2060"; }; +assertEq(Number(obj), 2060); + +// Deleting Date.prototype[Symbol.toPrimitive] changes the result of addition +// involving Date objects. +var d = new Date; +assertEq(0 + d, 0 + d.toString()); +delete Date.prototype[Symbol.toPrimitive]; +assertEq(0 + d, 0 + d.valueOf()); + +// If @@toPrimitive, .toString, and .valueOf are all missing, we get a +// particular sequence of property accesses, followed by a TypeError exception. +var log = []; +function doGet(target, propertyName, receiver) { + log.push(propertyName); +} +var handler = new Proxy({}, { + get(target, trapName, receiver) { + if (trapName !== "get") + throw `FAIL: system tried to access handler method: ${uneval(trapName)}`; + return doGet; + } +}); +proxy = new Proxy(Object.create(null), handler); +assertThrowsInstanceOf(() => proxy == 0, TypeError); +assertDeepEq(log, [Symbol.toPrimitive, "valueOf", "toString"]); + +reportCompare(0, 0); |