diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/tests/non262/Reflect | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/non262/Reflect')
19 files changed, 1523 insertions, 0 deletions
diff --git a/js/src/tests/non262/Reflect/apply.js b/js/src/tests/non262/Reflect/apply.js new file mode 100644 index 0000000000..fbd9db2a4b --- /dev/null +++ b/js/src/tests/non262/Reflect/apply.js @@ -0,0 +1,130 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.apply calls functions. +assertEq(Reflect.apply(Math.floor, undefined, [1.75]), 1); + +// Reflect.apply requires a target object that's callable. +var nonCallable = [{}, [], (class clsX { constructor() {} })]; +for (var value of nonCallable) { + assertThrowsInstanceOf(() => Reflect.apply(nonCallable), TypeError); +} + +// When target is not callable, Reflect.apply does not try to get argumentList.length before throwing. +var hits = 0; +var bogusArgumentList = {get length() { hit++; throw "FAIL";}}; +assertThrowsInstanceOf(() => Reflect.apply({callable: false}, null, bogusArgumentList), + TypeError); +assertEq(hits, 0); + +// Reflect.apply works on a range of different callable objects. +// Builtin functions (we also tested Math.floor above): +assertEq(Reflect.apply(String.fromCharCode, + undefined, + [104, 101, 108, 108, 111]), + "hello"); + +// Builtin methods: +assertEq(Reflect.apply(RegExp.prototype.exec, + /ab/, + ["confabulation"]).index, + 4); + +// Builtin methods of primitive objects: +assertEq(Reflect.apply("".charAt, + "ponies", + [3]), + "i"); + +// Bound functions: +assertEq(Reflect.apply(function () { return this; }.bind(Math), + Function, + []), + Math); +assertEq(Reflect.apply(Array.prototype.concat.bind([1, 2], [3]), + [4, 5], + [[6, 7, 8]]).join(), + "1,2,3,6,7,8"); + +// Generator functions: +function* g(arg) { yield "pass" + arg; } +assertEq(Reflect.apply(g, + undefined, + ["word"]).next().value, + "password"); + +// Proxies: +function f() { return 13; } +assertEq(Reflect.apply(new Proxy(f, {}), + undefined, + []), + 13); + +// Cross-compartment wrappers: +var gw = newGlobal(); +assertEq(Reflect.apply(gw.parseInt, + undefined, + ["45"]), + 45); +assertEq(Reflect.apply(gw.Symbol.for, + undefined, + ["moon"]), + Symbol.for("moon")); + +gw.eval("function q() { return q; }"); +assertEq(Reflect.apply(gw.q, + undefined, + []), + gw.q); + + +// Exceptions are propagated. +var nope = new Error("nope"); +function fail() { + throw nope; +} +assertThrowsValue(() => Reflect.apply(fail, undefined, []), + nope); + +// Exceptions thrown by cross-compartment wrappers are re-wrapped for the +// calling compartment. +var gxw = gw.eval("var x = new Error('x'); x"); +gw.eval("function fail() { throw x; }"); +assertThrowsValue(() => Reflect.apply(gw.fail, undefined, []), + gxw); + +// The thisArgument is passed to the target function as the 'this' value. +var obj = {}; +hits = 0; +assertEq(Reflect.apply(function () { hits++; assertEq(this, obj); }, + obj, + []), + undefined); +assertEq(hits, 1); + +// Primitive values can be thisArgument. +function strictThis() { "use strict"; return this; } +for (var value of [null, undefined, 0, -0, NaN, Symbol("moon")]) { + assertEq(Reflect.apply(strictThis, value, []), + value); +} + +// If the target is a non-strict function and thisArgument is a primitive value +// other than null or undefined, then thisArgument is converted to a wrapper +// object. +var testValues = [true, 1e9, "ok", Symbol("ok")]; +function nonStrictThis(expected) { + assertEq(typeof this, "object"); + assertEq(Reflect.apply(Object.prototype.toString, this, []).toLowerCase(), expected); + return "ok"; +} +for (var value of testValues) { + assertEq(Reflect.apply(nonStrictThis, + value, + ["[object " + typeof value + "]"]), + "ok"); +} + +// For more Reflect.apply tests, see target.js and argumentsList.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/argumentsList.js b/js/src/tests/non262/Reflect/argumentsList.js new file mode 100644 index 0000000000..1cd5984f00 --- /dev/null +++ b/js/src/tests/non262/Reflect/argumentsList.js @@ -0,0 +1,164 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Tests for the argumentList argument to Reflect.apply and Reflect.construct. + +// Reflect.apply and Reflect.construct require an argumentList argument that must be an object. +assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined), // missing + TypeError); +assertThrowsInstanceOf(() => Reflect.construct(Object), // missing + TypeError); +for (var primitive of SOME_PRIMITIVE_VALUES) { + assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined, primitive), + TypeError); + assertThrowsInstanceOf(() => Reflect.construct(Object, primitive), + TypeError); +} + +// Array used by several tests below. +var BOTH = [ + Reflect.apply, + // Adapt Reflect.construct to accept the same arguments as Reflect.apply. + (target, thisArgument, argumentList) => Reflect.construct(target, argumentList) +]; + +// The argumentList is copied and becomes the list of arguments passed to the function. +function getRest(...x) { return x; } +var args = [1, 2, 3]; +for (var method of BOTH) { + var result = method(getRest, undefined, args); + assertEq(result.join(), args.join()); + assertEq(result !== args, true); +} + +// argumentList.length can be less than func.length. +function testLess(a, b, c, d, e) { + assertEq(a, 1); + assertEq(b, true); + assertEq(c, "three"); + assertEq(d, Symbol.for); + assertEq(e, undefined); + + assertEq(arguments.length, 4); + assertEq(arguments !== args, true); + return "ok"; +} +args = [1, true, "three", Symbol.for]; +assertEq(Reflect.apply(testLess, undefined, args), "ok"); +assertEq(Reflect.construct(testLess, args) instanceof testLess, true); + +// argumentList.length can be more than func.length. +function testMoar(a) { + assertEq(a, args[0]); + return "good"; +} +assertEq(Reflect.apply(testMoar, undefined, args), "good"); +assertEq(Reflect.construct(testMoar, args) instanceof testMoar, true); + +// argumentList can be any object with a .length property. +function getArgs(...args) { + return args; +} +for (var method of BOTH) { + assertDeepEq(method(getArgs, undefined, {length: 0}), + []); + assertDeepEq(method(getArgs, undefined, {length: 1, "0": "zero"}), + ["zero"]); + assertDeepEq(method(getArgs, undefined, {length: 2}), + [undefined, undefined]); + assertDeepEq(method(getArgs, undefined, function (a, b, c) {}), + [undefined, undefined, undefined]); +} + +// The Iterable/Iterator interfaces are not used. +var funnyArgs = { + 0: "zero", + 1: "one", + length: 2, + [Symbol.iterator]() { throw "FAIL 1"; }, + next() { throw "FAIL 2"; } +}; +for (var method of BOTH) { + assertDeepEq(method(getArgs, undefined, funnyArgs), + ["zero", "one"]); +} + +// If argumentList has no .length property, no arguments are passed. +function count() { return {numArgsReceived: arguments.length}; } +for (var method of BOTH) { + assertEq(method(count, undefined, {"0": 0, "1": 1}).numArgsReceived, + 0); + function* g() { yield 1; yield 2; } + assertEq(method(count, undefined, g()).numArgsReceived, + 0); +} + +// If argumentsList.length has a getter, it is called. +var log; +args = { + get length() { log += "L"; return 1; }, + get "0"() { log += "0"; return "zero"; }, + get "1"() { log += "1"; return "one"; } +}; +for (var method of BOTH) { + log = ""; + assertDeepEq(method(getArgs, undefined, args), + ["zero"]); + assertEq(log, "L0"); +} + +// The argumentsList.length getter can throw; the exception is propagated. +var exc = {status: "bad"}; +args = { + get length() { throw exc; } +}; +for (var method of BOTH) { + assertThrowsValue(() => method(count, undefined, args), exc); +} + +// If argumentsList.length is unreasonably huge, we get an error. +// (This is an implementation limit.) +for (var method of BOTH) { + for (var value of [1e12, 1e240, Infinity]) { + assertThrowsInstanceOf(() => method(count, undefined, {length: value}), + Error); + } +} + +// argumentsList.length is converted to an integer. +for (var value of [1.7, "1", {valueOf() { return "1"; }}]) { + args = { + length: value, + "0": "ponies" + }; + for (var method of BOTH) { + var result = method(getArgs, undefined, args); + assertEq(result.length, 1); + assertEq(result[0], "ponies"); + } +} + +// If argumentsList.length is negative or NaN, no arguments are passed. +for (var method of BOTH) { + for (var num of [-1, -0.1, -0, -1e99, -Infinity, NaN]) { + assertEq(method(count, undefined, {length: num}).numArgsReceived, + 0); + } +} + +// Many arguments can be passed. +var many = 65537; +var args = {length: many, 0: "zero", [many - 1]: "last"}; +function testMany(...args) { + for (var i = 0; i < many; i++) { + assertEq(i in args, true); + assertEq(args[i], i === 0 ? "zero" : i === many - 1 ? "last" : undefined); + } + return this; +} +assertEq(Reflect.apply(testMany, "pass", args).toString(), "pass"); +assertEq(Reflect.construct(testMany, args) instanceof testMany, true); +assertEq(Reflect.apply(new Proxy(testMany, {}), "pass", args).toString(), "pass"); +assertEq(Reflect.construct(new Proxy(testMany, {}), args) instanceof testMany, true); + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/browser.js b/js/src/tests/non262/Reflect/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/non262/Reflect/browser.js diff --git a/js/src/tests/non262/Reflect/construct.js b/js/src/tests/non262/Reflect/construct.js new file mode 100644 index 0000000000..7dbb9bfa7d --- /dev/null +++ b/js/src/tests/non262/Reflect/construct.js @@ -0,0 +1,107 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.construct invokes constructors. + +assertDeepEq(Reflect.construct(Object, []), {}); +assertDeepEq(Reflect.construct(String, ["hello"]), new String("hello")); + +// Constructing Date creates a real Date object. +var d = Reflect.construct(Date, [1776, 6, 4]); +assertEq(d instanceof Date, true); +assertEq(d.getFullYear(), 1776); // non-generic method requires real Date object + +// [[Construct]] methods don't necessarily create new objects. +var obj = {}; +assertEq(Reflect.construct(Object, [obj]), obj); + + +// === Various kinds of constructors +// We've already seen some builtin constructors. +// +// JS functions: +function f(x) { this.x = x; } +assertDeepEq(Reflect.construct(f, [3]), new f(3)); +f.prototype = Array.prototype; +assertDeepEq(Reflect.construct(f, [3]), new f(3)); + +// Bound functions: +var bound = f.bind(null, "carrot"); +assertDeepEq(Reflect.construct(bound, []), new bound); + +// Classes: +class Base { + constructor(...args) { + this.args = args; + this.newTarget = new.target; + } +} +class Derived extends Base { + constructor(...args) { super(...args); } +} + +assertDeepEq(Reflect.construct(Base, []), new Base); +assertDeepEq(Reflect.construct(Derived, [7]), new Derived(7)); +g = Derived.bind(null, "q"); +assertDeepEq(Reflect.construct(g, [8, 9]), new g(8, 9)); + +// Cross-compartment wrappers: +var g = newGlobal(); +var local = {here: this}; +g.eval("function F(arg) { this.arg = arg }"); +assertDeepEq(Reflect.construct(g.F, [local]), new g.F(local)); + +// If first argument to Reflect.construct isn't a constructor, it throws a +// TypeError. +var nonConstructors = [ + {}, + Reflect.construct, // builtin functions aren't constructors + x => x + 1, + Math.max.bind(null, 0), // bound non-constructors aren't constructors + ((x, y) => x > y).bind(null, 0), + + // A Proxy to a non-constructor function isn't a constructor, even if a + // construct handler is present. + new Proxy(Reflect.construct, {construct(){}}), +]; +for (var obj of nonConstructors) { + assertThrowsInstanceOf(() => Reflect.construct(obj, []), TypeError); + assertThrowsInstanceOf(() => Reflect.construct(obj, [], Object), TypeError); +} + + +// === new.target tests + +// If the newTarget argument to Reflect.construct is missing, the target is used. +function checkNewTarget() { + assertEq(new.target, expected); + expected = undefined; +} +var expected = checkNewTarget; +Reflect.construct(checkNewTarget, []); + +// The newTarget argument is correctly passed to the constructor. +var constructors = [Object, Function, f, bound]; +for (var ctor of constructors) { + expected = ctor; + Reflect.construct(checkNewTarget, [], ctor); + assertEq(expected, undefined); +} + +// The newTarget argument must be a constructor. +for (var v of SOME_PRIMITIVE_VALUES.concat(nonConstructors)) { + assertThrowsInstanceOf(() => Reflect.construct(checkNewTarget, [], v), TypeError); +} + +// The builtin Array constructor uses new.target.prototype and always +// creates a real array object. +function someConstructor() {} +var result = Reflect.construct(Array, [], someConstructor); +assertEq(Reflect.getPrototypeOf(result), someConstructor.prototype); +assertEq(result.length, 0); +assertEq(Array.isArray(result), true); + + +// For more Reflect.construct tests, see target.js and argumentsList.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/defineProperty.js b/js/src/tests/non262/Reflect/defineProperty.js new file mode 100644 index 0000000000..1f299f4e85 --- /dev/null +++ b/js/src/tests/non262/Reflect/defineProperty.js @@ -0,0 +1,164 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.defineProperty defines properties. +var obj = {}; +assertEq(Reflect.defineProperty(obj, "x", {value: 7}), true); +assertEq(obj.x, 7); +var desc = Reflect.getOwnPropertyDescriptor(obj, "x"); +assertDeepEq(desc, {value: 7, + writable: false, + enumerable: false, + configurable: false}); + +// Reflect.defineProperty can define a symbol-keyed property. +var key = Symbol(":o)"); +assertEq(Reflect.defineProperty(obj, key, {value: 8}), true); +assertEq(obj[key], 8); + +// array .length property +obj = [1, 2, 3, 4, 5]; +assertEq(Reflect.defineProperty(obj, "length", {value: 4}), true); +assertDeepEq(obj, [1, 2, 3, 4]); + +// The target can be a proxy. +obj = {}; +var proxy = new Proxy(obj, { + defineProperty(t, id, desc) { + t[id] = 1; + return true; + } +}); +assertEq(Reflect.defineProperty(proxy, "prop", {value: 7}), true); +assertEq(obj.prop, 1); +assertEq(delete obj.prop, true); +assertEq("prop" in obj, false); + +// The attributes object is re-parsed, not passed through to the +// handler.defineProperty method. +obj = {}; +var attributes = { + configurable: 17, + enumerable: undefined, + value: null +}; +proxy = new Proxy(obj, { + defineProperty(t, id, desc) { + assertEq(desc !== attributes, true); + assertEq(desc.configurable, true); + assertEq(desc.enumerable, false); + assertEq(desc.value, null); + assertEq("writable" in desc, false); + return 15; // and the return value here is coerced to boolean + } +}); +assertEq(Reflect.defineProperty(proxy, "prop", attributes), true); + + +// === Failure and error cases +// +// Reflect.defineProperty behaves much like Object.defineProperty, which has +// extremely thorough tests elsewhere, and the implementation is largely +// shared. Duplicating those tests with Reflect.defineProperty would be a +// big waste. +// +// However, certain failures cause Reflect.defineProperty to return false +// without throwing a TypeError (unlike Object.defineProperty). So here we test +// many error cases to check that behavior. + +// missing attributes argument +assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y"), + TypeError); + +// non-object attributes argument +for (var attributes of SOME_PRIMITIVE_VALUES) { + assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y", attributes), + TypeError); +} + +// inextensible object +obj = Object.preventExtensions({}); +assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false); + +// inextensible object with irrelevant inherited property +obj = Object.preventExtensions(Object.create({"prop": 3})); +assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false); + +// redefine nonconfigurable to configurable +obj = Object.freeze({prop: 1}); +assertEq(Reflect.defineProperty(obj, "prop", {configurable: true}), false); + +// redefine enumerability of nonconfigurable property +obj = Object.freeze(Object.defineProperties({}, { + x: {enumerable: true, configurable: false, value: 0}, + y: {enumerable: false, configurable: false, value: 0}, +})); +assertEq(Reflect.defineProperty(obj, "x", {enumerable: false}), false); +assertEq(Reflect.defineProperty(obj, "y", {enumerable: true}), false); + +// redefine nonconfigurable data to accessor property, or vice versa +obj = Object.seal({x: 1, get y() { return 2; }}); +assertEq(Reflect.defineProperty(obj, "x", {get() { return 2; }}), false); +assertEq(Reflect.defineProperty(obj, "y", {value: 1}), false); + +// redefine nonwritable, nonconfigurable property as writable +obj = Object.freeze({prop: 0}); +assertEq(Reflect.defineProperty(obj, "prop", {writable: true}), false); +assertEq(Reflect.defineProperty(obj, "prop", {writable: false}), true); // no-op + +// change value of nonconfigurable nonwritable property +obj = Object.freeze({prop: 0}); +assertEq(Reflect.defineProperty(obj, "prop", {value: -0}), false); +assertEq(Reflect.defineProperty(obj, "prop", {value: +0}), true); // no-op + +// change getter or setter +function g() {} +function s(x) {} +obj = {}; +Object.defineProperty(obj, "prop", {get: g, set: s, configurable: false}); +assertEq(Reflect.defineProperty(obj, "prop", {get: s}), false); +assertEq(Reflect.defineProperty(obj, "prop", {get: g}), true); // no-op +assertEq(Reflect.defineProperty(obj, "prop", {set: g}), false); +assertEq(Reflect.defineProperty(obj, "prop", {set: s}), true); // no-op + +// Proxy defineProperty handler method that returns false +var falseValues = [false, 0, -0, "", NaN, null, undefined]; +if (typeof createIsHTMLDDA === "function") + falseValues.push(createIsHTMLDDA()); +var value; +proxy = new Proxy({}, { + defineProperty(t, id, desc) { + return value; + } +}); +for (value of falseValues) { + assertEq(Reflect.defineProperty(proxy, "prop", {value: 1}), false); +} + +// Proxy defineProperty handler method returns true, in violation of invariants. +// Per spec, this is a TypeError, not a false return. +obj = Object.freeze({x: 1}); +proxy = new Proxy(obj, { + defineProperty(t, id, desc) { + return true; + } +}); +assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "x", {value: 2}), TypeError); +assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "y", {value: 0}), TypeError); +assertEq(Reflect.defineProperty(proxy, "x", {value: 1}), true); + +// The second argument is converted ToPropertyKey before any internal methods +// are called on the first argument. +var poison = + (counter => new Proxy({}, new Proxy({}, { get() { throw counter++; } })))(42); +assertThrowsValue(() => { + Reflect.defineProperty(poison, { + toString() { throw 17; }, + valueOf() { throw 8675309; } + }, poison); +}, 17); + + +// For more Reflect.defineProperty tests, see target.js and propertyKeys.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/deleteProperty.js b/js/src/tests/non262/Reflect/deleteProperty.js new file mode 100644 index 0000000000..744e0f5715 --- /dev/null +++ b/js/src/tests/non262/Reflect/deleteProperty.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.deleteProperty deletes properties. +var obj = {x: 1, y: 2}; +assertEq(Reflect.deleteProperty(obj, "x"), true); +assertDeepEq(obj, {y: 2}); + +var arr = [1, 1, 2, 3, 5]; +assertEq(Reflect.deleteProperty(arr, "3"), true); +assertDeepEq(arr, [1, 1, 2, , 5]); + + +// === Failure and error cases +// Since Reflect.deleteProperty is almost exactly identical to the non-strict +// `delete` operator, there is not much to test that would not be redundant. + +// Returns true if no such property exists. +assertEq(Reflect.deleteProperty({}, "q"), true); + +// Or if it's inherited. +var proto = {x: 1}; +assertEq(Reflect.deleteProperty(Object.create(proto), "x"), true); +assertEq(proto.x, 1); + +// Return false if asked to delete a non-configurable property. +var arr = []; +assertEq(Reflect.deleteProperty(arr, "length"), false); +assertEq(arr.hasOwnProperty("length"), true); +assertEq(Reflect.deleteProperty(this, "undefined"), false); +assertEq(this.undefined, void 0); + +// Return false if a Proxy's deleteProperty handler returns a false-y value. +var value; +var proxy = new Proxy({}, { + deleteProperty(t, k) { + return value; + } +}); +for (value of [true, false, 0, "something", {}]) { + assertEq(Reflect.deleteProperty(proxy, "q"), !!value); +} + +// If a Proxy's handler method throws, the error is propagated. +proxy = new Proxy({}, { + deleteProperty(t, k) { throw "vase"; } +}); +assertThrowsValue(() => Reflect.deleteProperty(proxy, "prop"), "vase"); + +// Throw a TypeError if a Proxy's handler method returns true in violation of +// the object invariants. +proxy = new Proxy(Object.freeze({prop: 1}), { + deleteProperty(t, k) { return true; } +}); +assertThrowsInstanceOf(() => Reflect.deleteProperty(proxy, "prop"), TypeError); + + +// === Deleting elements from `arguments` + +// Non-strict arguments element becomes unmapped +function f(x, y, z) { + assertEq(Reflect.deleteProperty(arguments, "0"), true); + arguments.x = 33; + return x; +} +assertEq(f(17, 19, 23), 17); + +// Frozen non-strict arguments element +function testFrozenArguments() { + Object.freeze(arguments); + assertEq(Reflect.deleteProperty(arguments, "0"), false); + assertEq(arguments[0], "zero"); + assertEq(arguments[1], "one"); +} +testFrozenArguments("zero", "one"); + + +// For more Reflect.deleteProperty tests, see target.js and propertyKeys.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/get.js b/js/src/tests/non262/Reflect/get.js new file mode 100644 index 0000000000..b38b188b03 --- /dev/null +++ b/js/src/tests/non262/Reflect/get.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.get gets the value of a property. + +var x = {p: 1}; +assertEq(Reflect.get(x, "p"), 1); +assertEq(Reflect.get(x, "toString"), Object.prototype.toString); +assertEq(Reflect.get(x, "missing"), undefined); + + +// === Various targets + +// Array +assertEq(Reflect.get([], 700), undefined); +assertEq(Reflect.get(["zero", "one"], 1), "one"); + +// TypedArray +assertEq(Reflect.get(new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]), 7), 7); + +// Treatment of NaN +var f = new Float64Array([NaN]); +var u = new Uint32Array(f.buffer); +u[0]++; +u[1]++; +assertEq(f[0], NaN); +assertEq(Reflect.get(f, 0), NaN); + +// Proxy with no get handler +assertEq(Reflect.get(new Proxy(x, {}), "p"), 1); + +// Proxy with a get handler +var obj = new Proxy(x, { + get(t, k, r) { return k + "ful"; } +}); +assertEq(Reflect.get(obj, "mood"), "moodful"); + +// Exceptions thrown by a proxy's get handler are propagated. +assertThrowsInstanceOf(() => Reflect.get(obj, Symbol()), TypeError); + +// Ordinary object, property has a setter and no getter +obj = {set name(x) {}}; +assertEq(Reflect.get(obj, "name"), undefined); + + +// === Receiver + +// Receiver argument is passed to getters as the this-value. +obj = { get x() { return this; }}; +assertEq(Reflect.get(obj, "x", Math), Math); +assertEq(Reflect.get(Object.create(obj), "x", JSON), JSON); + +// If missing, target is passed instead. +assertEq(Reflect.get(obj, "x"), obj); + +// Receiver argument is passed to the proxy get handler. +obj = new Proxy({}, { + get(t, k, r) { + assertEq(k, "itself"); + return r; + } +}); +assertEq(Reflect.get(obj, "itself"), obj); +assertEq(Reflect.get(obj, "itself", Math), Math); +assertEq(Reflect.get(Object.create(obj), "itself", Math), Math); + +// The receiver shouldn't have to be an object +assertEq(Reflect.get(obj, "itself", 37.2), 37.2); + +// For more Reflect.get tests, see target.js and propertyKeys.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/getOwnPropertyDescriptor.js b/js/src/tests/non262/Reflect/getOwnPropertyDescriptor.js new file mode 100644 index 0000000000..aa7329778d --- /dev/null +++ b/js/src/tests/non262/Reflect/getOwnPropertyDescriptor.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.getOwnPropertyDescriptor inspects object properties. +assertDeepEq( + Reflect.getOwnPropertyDescriptor({x: "hello"}, "x"), + {value: "hello", writable: true, enumerable: true, configurable: true}); +assertEq( + Reflect.getOwnPropertyDescriptor({x: "hello"}, "y"), + undefined); +assertDeepEq( + Reflect.getOwnPropertyDescriptor([], "length"), + {value: 0, writable: true, enumerable: false, configurable: false}); + +// Reflect.getOwnPropertyDescriptor shares its implementation with +// Object.getOwnPropertyDescriptor. The only difference is how non-object +// targets are handled. +// +// For more Reflect.getOwnPropertyDescriptor tests, see target.js and propertyKeys.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/getPrototypeOf.js b/js/src/tests/non262/Reflect/getPrototypeOf.js new file mode 100644 index 0000000000..6a29d4a9b2 --- /dev/null +++ b/js/src/tests/non262/Reflect/getPrototypeOf.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.getPrototypeOf returns an object's prototype. +assertEq(Reflect.getPrototypeOf({}), Object.prototype); +assertEq(Reflect.getPrototypeOf(Object.prototype), null); +assertEq(Reflect.getPrototypeOf(Object.create(null)), null); + +var proxy = new Proxy({}, { + getPrototypeOf(t) { return Math; } +}); + +assertEq(Reflect.getPrototypeOf(proxy), Math); + +// For more Reflect.getPrototypeOf tests, see target.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/has.js b/js/src/tests/non262/Reflect/has.js new file mode 100644 index 0000000000..6019a61ed3 --- /dev/null +++ b/js/src/tests/non262/Reflect/has.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.has is identical to the `in` operator. +assertEq(Reflect.has({x: 0}, "x"), true); +assertEq(Reflect.has({x: 0}, "y"), false); +assertEq(Reflect.has({x: 0}, "toString"), true); + +// The target can be an array; Reflect.has works on array elements. +var arr = ["zero"]; +arr[10000] = 0; +assertEq(Reflect.has(arr, "10000"), true); +assertEq(Reflect.has(arr, 10000), true); +assertEq(Reflect.has(arr, "-0"), false); +assertEq(Reflect.has(arr, -0), true); + +// And string objects (though not string primitives; see target.js). +var str = new String("hello"); +assertEq(Reflect.has(str, "4"), true); +assertEq(Reflect.has(str, "-0"), false); +assertEq(Reflect.has(str, -0), true); + +// Proxy without .has() handler method +var obj = {get prop() {}}; +for (var i = 0; i < 2; i++) { + obj = new Proxy(obj, {}); + assertEq(Reflect.has(obj, "prop"), true); + assertEq(Reflect.has(obj, "nope"), false); +} + +// Proxy with .has() handler method +obj = new Proxy({}, { + has(t, k) { return k.startsWith("door"); } +}); +assertEq(Reflect.has(obj, "doorbell"), true); +assertEq(Reflect.has(obj, "dormitory"), false); + + +// For more Reflect.has tests, see target.js and propertyKeys.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/isExtensible.js b/js/src/tests/non262/Reflect/isExtensible.js new file mode 100644 index 0000000000..f38724875d --- /dev/null +++ b/js/src/tests/non262/Reflect/isExtensible.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.isExtensible behaves just like Object.extensible except when the +// target argument is missing or is not an object (and that behavior is tested +// in target.js). + +// Test basic functionality. +var someObjects = [ + {}, + {a: "a"}, + [0, 1], + new Uint8Array(64), + Object(Symbol("table")), + new Proxy({}, {}) +]; +if (typeof SharedArrayBuffer != "undefined") + someObjects.push(new Uint8Array(new SharedArrayBuffer(64))); + +for (var obj of someObjects) { + assertEq(Reflect.isExtensible(obj), true); + assertEq(Reflect.preventExtensions(obj), true); + assertEq(Reflect.isExtensible(obj), false); +} + +// Array with nonwritable length. +var arr = [0, 1, 2, 3]; +Object.defineProperty(arr, "length", {writable: false}); +assertEq(Reflect.isExtensible(arr), true); + +// Proxy case. +for (var ext of [true, false]) { + var obj = {}; + if (!ext) + Object.preventExtensions(obj); + var proxy = new Proxy(obj, { + isExtensible() { return ext; } + }); + assertEq(Reflect.isExtensible(proxy), ext); +} + +// If a Proxy's isExtensible method throws, the exception is propagated. +proxy = new Proxy({}, { + isExtensible() { throw "oops"; } +}); +assertThrowsValue(() => Reflect.isExtensible(proxy), "oops"); + +// If an invariant is broken, [[IsExtensible]] does not return false. It throws +// a TypeError. +proxy = new Proxy({}, { + isExtensible() { return false; } +}); +assertThrowsInstanceOf(() => Reflect.isExtensible(proxy), TypeError); + +// For more Reflect.isExtensible tests, see target.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/ownKeys.js b/js/src/tests/non262/Reflect/ownKeys.js new file mode 100644 index 0000000000..5433562eb5 --- /dev/null +++ b/js/src/tests/non262/Reflect/ownKeys.js @@ -0,0 +1,66 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.ownKeys(obj) returns an array of an object's own property keys. + +// Test that Reflect.ownKeys gets the expected result when applied to various +// objects. (These tests also check the basics: that the result is an array, +// that its prototype is correct, etc.) +var sym = Symbol.for("comet"); +var sym2 = Symbol.for("meteor"); +var cases = [ + {object: {z: 3, y: 2, x: 1}, + keys: ["z", "y", "x"]}, + {object: [], + keys: ["length"]}, + {object: new Int8Array(4), + keys: ["0", "1", "2", "3"]}, + {object: new Proxy({a: 7}, {}), + keys: ["a"]}, + {object: {[sym]: "ok"}, + keys: [sym]}, + {object: {[sym]: 0, // test 9.1.12 ordering + "str": 0, + "773": 0, + "0": 0, + [sym2]: 0, + "-1": 0, + "8": 0, + "second str": 0}, + keys: ["0", "8", "773", // indexes in numeric order + "str", "-1", "second str", // strings in insertion order + sym, sym2]}, // symbols in insertion order + {object: newGlobal().Math, // cross-compartment wrapper + keys: Reflect.ownKeys(Math)} +]; +for (var {object, keys} of cases) + assertDeepEq(Reflect.ownKeys(object), keys); + +// Reflect.ownKeys() creates a new array each time it is called. +var object = {}, keys = []; +for (var i = 0; i < 3; i++) { + var newKeys = Reflect.ownKeys(object); + assertEq(newKeys !== keys, true); + keys = newKeys; +} + +// Proxy behavior with successful ownKeys() handler +keys = ["str", "0"]; +obj = {}; +proxy = new Proxy(obj, { + ownKeys() { return keys; } +}); +var actual = Reflect.ownKeys(proxy); +assertDeepEq(actual, keys); // we get correct answers +assertEq(actual !== keys, true); // but not the same object + +// If a proxy breaks invariants, a TypeError is thrown. +var obj = Object.preventExtensions({}); +var proxy = new Proxy(obj, { + ownKeys() { return ["something"]; } +}); +assertThrowsInstanceOf(() => Reflect.ownKeys(proxy), TypeError); + +// For more Reflect.ownKeys tests, see target.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/preventExtensions.js b/js/src/tests/non262/Reflect/preventExtensions.js new file mode 100644 index 0000000000..63ca2545b4 --- /dev/null +++ b/js/src/tests/non262/Reflect/preventExtensions.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.preventExtensions is the same as Object.preventExtensions, except +// for the return value and the behavior in error cases. + +var someObjects = [ + {}, + new Int32Array(7), + Object(Symbol("table")), + new Proxy({}, {}) +]; + +for (var obj of someObjects) { + assertEq(Reflect.preventExtensions(obj), true); + // [[PreventExtensions]] on an already-inextensible object is a no-op. + assertEq(Reflect.preventExtensions(obj), true); +} + +// Error cases. +assertThrowsInstanceOf(() => Reflect.isExtensible(), TypeError); +for (var value of [undefined, null, true, 1, NaN, "Phaedo", Symbol("good")]) { + assertThrowsInstanceOf(() => Reflect.isExtensible(value), TypeError); +} + +// A proxy's preventExtensions handler can return false without doing anything. +obj = {}; +var proxy = new Proxy(obj, { + preventExtensions() { return false; } +}); +assertEq(Reflect.preventExtensions(proxy), false); +assertEq(Reflect.isExtensible(obj), true); +assertEq(Reflect.isExtensible(proxy), true); + +// If a proxy's preventExtensions handler throws, the exception is propagated. +obj = {}; +proxy = new Proxy(obj, { + preventExtensions() { throw "fit"; } +}); +assertThrowsValue(() => Reflect.preventExtensions(proxy), "fit"); +assertEq(Reflect.isExtensible(obj), true); +assertEq(Reflect.isExtensible(proxy), true); + +// If a proxy's preventExtensions handler returns true while leaving the target +// extensible, that's a TypeError. +obj = {}; +proxy = new Proxy(obj, { + preventExtensions() { return true; } +}); +assertThrowsInstanceOf(() => Reflect.preventExtensions(proxy), TypeError); +assertEq(Reflect.isExtensible(obj), true); +assertEq(Reflect.isExtensible(proxy), true); + +// For more Reflect.preventExtensions tests, see target.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/propertyKeys.js b/js/src/tests/non262/Reflect/propertyKeys.js new file mode 100644 index 0000000000..6495a96fd9 --- /dev/null +++ b/js/src/tests/non262/Reflect/propertyKeys.js @@ -0,0 +1,84 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Test corner cases involving Reflect methods' propertyKey arguments. + +// keys - Array of propertyKey values to be tested. +// +// Each element of this array is a record with these properties: +// +// * value: a value that will be passed as a property key +// to the various Reflect methods; +// +// * expected: (optional) the string or symbol that ToPropertyKey(value) +// should return. If this is omitted, ToPropertyKey(value) === value. +// +var keys = [ + {value: null, expected: "null"}, + {value: undefined, expected: "undefined"}, + {value: true, expected: "true"}, + {value: 42, expected: "42"}, + {value: "string"}, + {value: ""}, + {value: "string with \0"}, + {value: new String("ok"), expected: "ok"}, + {value: Symbol("sym")}, + {value: Symbol.iterator}, + {value: Object(Symbol.for("comet")), expected: Symbol.for("comet")}, + { + value: { + toString() { return "key"; }, + valueOf() { return "bad"; } + }, + expected: "key" + }, + { + value: { + toString: undefined, + valueOf() { return "fallback"; } + }, + expected: "fallback" + }, + { + value: { + [Symbol.toPrimitive](hint) { return hint; } + }, + expected: "string" + }, + { + value: { + [Symbol.toPrimitive](hint) { return Symbol.for(hint); } + }, + expected: Symbol.for("string") + } +]; + +for (var {value, expected} of keys) { + if (expected === undefined) + expected = value; + + var obj = {}; + assertEq(Reflect.defineProperty(obj, value, {value: 1, configurable: true}), true); + assertDeepEq(Reflect.ownKeys(obj), [expected]); + assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, value), + {value: 1, + writable: false, + enumerable: false, + configurable: true}); + assertEq(Reflect.deleteProperty(obj, value), true); + assertEq(Reflect.has(obj, value), false); + assertEq(Reflect.set(obj, value, 113), true); + assertEq(obj[expected], 113); + assertEq(Reflect.has(obj, value), true); + assertEq(Reflect.get(obj, value), 113); +} + +// ToPropertyKey can throw. +var exc = {}; +var badKey = {toString() { throw exc; }}; +var methodNames = ["defineProperty", "deleteProperty", "has", "get", "getOwnPropertyDescriptor", "set"]; +for (var name of methodNames) { + assertThrowsValue(() => Reflect[name]({}, badKey), exc); +} + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/set.js b/js/src/tests/non262/Reflect/set.js new file mode 100644 index 0000000000..83cd98b691 --- /dev/null +++ b/js/src/tests/non262/Reflect/set.js @@ -0,0 +1,280 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.set does property assignment. +// With three arguments, this is pretty straightforward. +var obj = {}; +assertEq(Reflect.set(obj, "prop", "value"), true); +assertEq(obj.prop, "value"); + + +// === Various targets + +// It can assign array elements. +var arr = ["duck", "duck", "duck"]; +assertEq(Reflect.set(arr, 2, "goose"), true); +assertEq(arr[2], "goose"); + +// It can extend an array. +assertEq(Reflect.set(arr, 3, "Model T"), true); +assertEq(arr.length, 4); + +// It can truncate an array. +assertEq(Reflect.set(arr, "length", 1), true); +assertDeepEq(arr, ["duck"]); + +// It won't assign to non-writable properties of String objects. +var str = new String("hello"); +assertEq(Reflect.set(str, "0", "y"), false); +assertEq(str[0], "h"); +assertEq(Reflect.set(str, "length", 700), false); +assertEq(str.length, 5); + + +// === Receivers +// The optional fourth argument is the receiver, which [[Set]] methods use for +// various things. + +// On ordinary objects, if the property has a setter, the receiver is passed as +// the this-value to the setter. +var expected; +var obj = { + set prop(v) { + "use strict"; + assertEq(v, 32); + assertEq(this, expected); + } +}; +for (expected of [obj, {}, [], 37.3]) { + assertEq(Reflect.set(obj, "prop", 32, expected), true); +} + +// If the property doesn't already exist, it is defined on the receiver. +obj = {}; +var obj2 = {}; +assertEq(Reflect.set(obj, "prop", 47, obj2), true); +assertDeepEq(obj, {}); +assertDeepEq(Reflect.getOwnPropertyDescriptor(obj2, "prop"), + {value: 47, writable: true, enumerable: true, configurable: true}); + +// If the property doesn't already exist, and the receiver isn't an object, return false. +for (var v of SOME_PRIMITIVE_VALUES) { + assertEq(Reflect.set({}, "x", 0, v), false); +} + +// Receiver defaults to the target. +obj = {}; +var hits; +var expectedReceiver; +var proxy = new Proxy(obj, { + set(t, k, v, r) { + assertEq(t, obj); + assertEq(k, "key"); + assertEq(v, "value"); + assertEq(r, expectedReceiver); // not obj + hits++; + return true; + } +}); +hits = 0; +expectedReceiver = proxy; +assertEq(Reflect.set(proxy, "key", "value"), true); +assertEq(hits, 1); + +// But not if explicitly present and undefined. +hits = 0; +expectedReceiver = undefined; +assertEq(Reflect.set(proxy, "key", "value", undefined), true); +assertEq(hits, 1); + +// Reflect.set can be used as fallback behavior in a proxy handler .set() +// method. +var log; +obj = { + set prop(v) { + log += "p"; + assertEq(v, "value"); + assertEq(this, proxy); // not obj! + } +}; +proxy = new Proxy(obj, { + set(t, k, v, r) { + assertEq(t, obj); + assertEq(r, proxy); + log += "s"; + return Reflect.set(t, k, v, r); + } +}); +log = ""; +assertEq(Reflect.set(proxy, "prop", "value"), true); +assertEq(log, "sp"); + + +// === Cross-compartment wrapper behavior. + +// When calling a cross-compartment wrapper, receiver is rewrapped for the +// target compartment. +var g = newGlobal(); +if (!("assertEq" in g)) + g.assertEq = assertEq; // necessary in the browser +g.eval(` + var hits; + var obj = { + set x(v) { + "use strict"; + assertEq(this, receiver); + assertEq(v, "xyzzy"); + hits++; + } + }; + var receiver = {}; +`); +g.hits = 0; +assertEq(Reflect.set(g.obj, "x", "xyzzy", g.receiver), true); +assertEq(g.hits, 1); + +// ...even when receiver is from a different compartment than target. +var receiver = {}; +g.receiver = receiver; +g.hits = 0; +assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true); +assertEq(g.hits, 1); + +// ...even when receiver is a primtive value, even undefined. +for (receiver of SOME_PRIMITIVE_VALUES) { + g.receiver = receiver; + g.hits = 0; + assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true); + assertEq(g.hits, 1); +} + + +// === Less than 3 arguments + +// With two arguments, the value is assumed to be undefined. +obj = {}; +assertEq(Reflect.set(obj, "size"), true); +assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "size"), + {value: undefined, writable: true, enumerable: true, configurable: true}); + +// With just one argument, the key is "undefined". +obj = {}; +assertEq(Reflect.set(obj), true); +assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "undefined"), + {value: undefined, writable: true, enumerable: true, configurable: true}); + +// For the no argument-case, see target.js. + + +// === Failure cases + +// Non-writable data property +obj = {}; +Reflect.defineProperty(obj, "x", {value: 0, writable: false}); +assertEq(Reflect.set(obj, "x", 1), false); +assertEq(obj.x, 0); + +// The same, but inherited from a prototype +var obj2 = Object.create(obj); +assertEq(Reflect.set(obj2, "x", 1), false); +assertEq(obj2.hasOwnProperty("x"), false); +assertEq(obj2.x, 0); + +// Getter, no setter +obj = {}; +var desc = {get: () => 12, set: undefined, enumerable: false, configurable: true}; +Reflect.defineProperty(obj, "y", desc); +assertEq(Reflect.set(obj, "y", 13), false); +assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc); + +// The same, but inherited from a prototype +obj2 = Object.create(obj); +assertEq(Reflect.set(obj2, "y", 1), false); +assertEq(obj2.hasOwnProperty("y"), false); +assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc); + +// Proxy set handler returns a false value +for (var no of [false, ""]) { + var hits = 0; + obj = {}; + var proxy = new Proxy(obj, { + set(t, k, v, r) { + assertEq(t, obj); + assertEq(k, "x"); + assertEq(v, 33); + assertEq(r, proxy); + hits++; + return no; + } + }); + assertEq(Reflect.set(proxy, "x", 33), false); + assertEq(hits, 1); + assertEq("x" in obj, false); +} + +// Proxy handler method throws +obj = {}; +proxy = new Proxy(obj, { + set(t, k, v, r) { throw "i don't like " + v; } +}); +assertThrowsValue(() => Reflect.set(proxy, "food", "cheese"), "i don't like cheese"); + +// If a Proxy set handler breaks the object invariants, it's a TypeError. +for (obj of [{a: 0}, {get a() { return 0; }}]) { + Object.freeze(obj); + proxy = new Proxy(obj, { + set(t, k, v, r) { return true; } + }); + assertThrowsInstanceOf(() => Reflect.set(proxy, "a", "b"), TypeError); +} + +// Per spec, this should first call p.[[Set]]("0", 42, a) and +// then (since p has no own properties) a.[[Set]]("0", 42, a). +// The latter should not define a property on p. +var a = [0, 1, 2, 3]; +var p = Object.create(a); +Reflect.set(p, "0", 42, a); +assertEq(p.hasOwnProperty("0"), false); +assertDeepEq(Reflect.getOwnPropertyDescriptor(a, "0"), + {value: 42, writable: true, enumerable: true, configurable: true}); + +// Test behavior of ordinary objects' [[Set]] method (ES6 9.1.9). +// On an ordinary object, if the property key isn't present, [[Set]] calls +// receiver.[[GetOwnProperty]]() and then receiver.[[DefineProperty]](). +var log; +obj = {}; +var proxyTarget = {}; +var existingDescriptor, expected, defineResult; +var receiver = new Proxy(proxyTarget, { + getOwnPropertyDescriptor(t, k) { + log += "g"; + return existingDescriptor; + }, + defineProperty(t, k, desc) { + log += "d"; + assertEq(t, proxyTarget); + assertEq(k, "prop"); + assertDeepEq(desc, expected); + return defineResult; + } +}); +existingDescriptor = undefined; +expected = {value: 5, writable: true, enumerable: true, configurable: true}; +for (var defineResult of [true, false]) { + log = ""; + assertEq(Reflect.set(obj, "prop", 5, receiver), defineResult); + assertEq(log, "gd"); +} + +existingDescriptor = {value: 7, writable: true, enumerable: false, configurable: true}; +expected = {value: 4}; +for (var defineResult of [true, false]) { + log = ""; + assertEq(Reflect.set(obj, "prop", 4, receiver), defineResult); + assertEq(log, "gd"); +} + + +// For more Reflect.set tests, see target.js and propertyKeys.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/setPrototypeOf.js b/js/src/tests/non262/Reflect/setPrototypeOf.js new file mode 100644 index 0000000000..ed7857a028 --- /dev/null +++ b/js/src/tests/non262/Reflect/setPrototypeOf.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.setPrototypeOf changes an object's [[Prototype]]. +var obj = {}; +assertEq(Object.getPrototypeOf(obj), Object.prototype); +var proto = {}; +assertEq(Reflect.setPrototypeOf(obj, proto), true); +assertEq(Object.getPrototypeOf(obj), proto); + +// It can change an object's [[Prototype]] to null. +obj = {}; +assertEq(Reflect.setPrototypeOf(obj, null), true); +assertEq(Object.getPrototypeOf(obj), null); + +// The proto argument is required too. +obj = {}; +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(obj), TypeError); + +// The proto argument must be either null or an object. +for (proto of [undefined, false, 0, 1.6, "that", Symbol.iterator]) { + assertThrowsInstanceOf(() => Reflect.setPrototypeOf(obj, proto), TypeError); +} + +// Return false if the target isn't extensible. +proto = {}; +obj = Object.preventExtensions(Object.create(proto)); +assertEq(Reflect.setPrototypeOf(obj, {}), false); +assertEq(Reflect.setPrototypeOf(obj, null), false); +assertEq(Reflect.setPrototypeOf(obj, proto), true); // except if not changing anything + +// Return false rather than create a [[Prototype]] cycle. +obj = {}; +assertEq(Reflect.setPrototypeOf(obj, obj), false); + +// Don't create a [[Prototype]] cycle involving 2 objects. +obj = Object.create(proto); +assertEq(Reflect.setPrototypeOf(proto, obj), false); + +// Don't create a longish [[Prototype]] cycle. +for (var i = 0; i < 256; i++) + obj = Object.create(obj); +assertEq(Reflect.setPrototypeOf(proto, obj), false); + +// The spec claims we should allow creating cycles involving proxies. (The +// cycle check quietly exits on encountering the proxy.) +obj = {}; +var proxy = new Proxy(Object.create(obj), {}); + +assertEq(Reflect.setPrototypeOf(obj, proxy), true); +assertEq(Reflect.getPrototypeOf(obj), proxy); +assertEq(Reflect.getPrototypeOf(proxy), obj); + +// If a proxy handler returns a false-y value, return false. +var hits = 0; +proto = {name: "proto"}; +obj = {name: "obj"}; +proxy = new Proxy(obj, { + setPrototypeOf(t, p) { + assertEq(t, obj); + assertEq(p, proto); + hits++; + return 0; + } +}); + +assertEq(Reflect.setPrototypeOf(proxy, proto), false); +assertEq(hits, 1); + +// For more Reflect.setPrototypeOf tests, see target.js. + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/shell.js b/js/src/tests/non262/Reflect/shell.js new file mode 100644 index 0000000000..2aa5397ed9 --- /dev/null +++ b/js/src/tests/non262/Reflect/shell.js @@ -0,0 +1,9 @@ +// List of a few values that are not objects. +var SOME_PRIMITIVE_VALUES = [ + undefined, null, + false, + -Infinity, -1.6e99, -1, -0, 0, Math.pow(2, -1074), 1, 4294967295, + Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER + 1, 1.6e99, Infinity, NaN, + "", "Phaedo", + Symbol(), Symbol("iterator"), Symbol.for("iterator"), Symbol.iterator +]; diff --git a/js/src/tests/non262/Reflect/surfaces.js b/js/src/tests/non262/Reflect/surfaces.js new file mode 100644 index 0000000000..f3bac51873 --- /dev/null +++ b/js/src/tests/non262/Reflect/surfaces.js @@ -0,0 +1,59 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Check surface features of the Reflect object. +assertEq(typeof Reflect, 'object'); +assertEq(Object.getPrototypeOf(Reflect), Object.prototype); +assertEq(Reflect.toString(), '[object Reflect]'); +assertThrowsInstanceOf(() => new Reflect, TypeError); + +var desc = Object.getOwnPropertyDescriptor(this, "Reflect"); +assertEq(desc.enumerable, false); +assertEq(desc.configurable, true); +assertEq(desc.writable, true); + +for (const name in Reflect) + throw new Error("Reflect should not have any enumerable properties"); + +// The name and length of all the standard Reflect methods. +var methods = { + apply: 3, + construct: 2, + defineProperty: 3, + deleteProperty: 2, + get: 2, + getOwnPropertyDescriptor: 2, + getPrototypeOf: 1, + has: 2, + isExtensible: 1, + ownKeys: 1, + preventExtensions: 1, + set: 3, + setPrototypeOf: 2 +}; + +// Check that all Reflect properties are listed above. +for (const name of Reflect.ownKeys(Reflect)) { + // If this assertion fails, congratulations on implementing a new Reflect feature! + // Add it to the list of methods above. + if (typeof name !== "symbol" && name !== "parse") + assertEq(name in methods, true, `unexpected property found: Reflect.${name}`); +} + +// Check the .length and property attributes of each Reflect method. +for (const name of Object.keys(methods)) { + var desc = Object.getOwnPropertyDescriptor(Reflect, name); + assertEq(desc.enumerable, false); + assertEq(desc.configurable, true); + assertEq(desc.writable, true); + var f = desc.value; + assertEq(typeof f, "function"); + assertEq(f.length, methods[name]); +} + +// Check that the SpiderMonkey "resolve hook" mechanism does not resurrect the +// Reflect property once it is deleted. +delete this.Reflect; +assertEq("Reflect" in this, false); + +reportCompare(0, 0); diff --git a/js/src/tests/non262/Reflect/target.js b/js/src/tests/non262/Reflect/target.js new file mode 100644 index 0000000000..f35fe816ad --- /dev/null +++ b/js/src/tests/non262/Reflect/target.js @@ -0,0 +1,44 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Check correct handling of the `target` argument shared by every Reflect method. + +// For each standard Reflect method, an array of arguments +// that would be OK after a suitable target argument. +var methodInfo = { + apply: [undefined, []], + construct: [[]], + defineProperty: ["x", {}], + deleteProperty: ["x"], + get: ["x", {}], + getOwnPropertyDescriptor: ["x"], + getPrototypeOf: [], + has: ["x"], + isExtensible: [], + ownKeys: [], + preventExtensions: [], + set: ["x", 0], + setPrototypeOf: [{}] +}; + +// Check that all Reflect properties are listed above. +for (const name of Reflect.ownKeys(Reflect)) { + // If this assertion fails, congratulations on implementing a new Reflect feature! + // Add it to methodInfo above. + if (typeof name !== "symbol" && name !== "parse") + assertEq(name in methodInfo, true); +} + +for (const name of Object.keys(methodInfo)) { + var args = methodInfo[name]; + + // The target argument is required. + assertThrowsInstanceOf(Reflect[name], TypeError); + + // Throw if the target argument is not an object. + for (var value of SOME_PRIMITIVE_VALUES) { + assertThrowsInstanceOf(() => Reflect[name](value, ...args), TypeError); + } +} + +reportCompare(0, 0); |