diff options
Diffstat (limited to 'js/src/tests/ecma_6/Proxy')
20 files changed, 1207 insertions, 0 deletions
diff --git a/js/src/tests/ecma_6/Proxy/getPrototypeOf.js b/js/src/tests/ecma_6/Proxy/getPrototypeOf.js new file mode 100644 index 000000000..a0676c0c9 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/getPrototypeOf.js @@ -0,0 +1,285 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "getPrototypeOf.js"; +var BUGNUMBER = 888969; +var summary = "Scripted proxies' [[GetPrototypeOf]] behavior"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +const log = []; + +function observe(obj) +{ + var observingHandler = new Proxy({}, { + get(target, p, receiver) { + log.push(p); + return Reflect.get(target, p, receiver); + } + }); + + return new Proxy(obj, observingHandler); +} + +function nop() {} + +var p, h; + +// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. +// 2. If handler is null, throw a TypeError exception. +// 3. Assert: Type(handler) is Object. +var rev = Proxy.revocable({}, {}); +p = rev.proxy; + +assertEq(Object.getPrototypeOf(p), Object.prototype); +rev.revoke(); +assertThrowsInstanceOf(() => Object.getPrototypeOf(p), TypeError); + +// 4. Let target be the value of the [[ProxyTarget]] internal slot of O. +// 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). + +// Getting handler.getPrototypeOf might throw. +assertThrowsValue(() => Object.getPrototypeOf(new Proxy({}, + { get getPrototypeOf() { + throw 17; + } })), + 17); + +// The handler's getPrototypeOf, once gotten, might throw. +p = new Proxy({}, { getPrototypeOf() { throw 42; } }); + +assertThrowsValue(() => Object.getPrototypeOf(p), 42); + +// The trap might not be callable. +p = new Proxy({}, { getPrototypeOf: 17 }); + +assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + +// 6. If trap is undefined, then +// a. Return ? target.[[GetPrototypeOf]](). + +var x, tp; + +tp = + new Proxy(new Number(8675309), // behavior overridden by getPrototypeOf + { getPrototypeOf() { x = "getPrototypeOf trap"; return null; } }); + +// The target's [[GetPrototypeOf]] should be invoked if the handler's +// .getPrototypeOf is undefined. +p = new Proxy(tp, { getPrototypeOf: undefined }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), null); +assertEq(x, "getPrototypeOf trap"); + +// Likewise if the handler's .getPrototypeOf is null. +p = new Proxy(tp, { getPrototypeOf: null }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), null); +assertEq(x, "getPrototypeOf trap"); + +// Now the target is an empty object with a Number object as its [[Prototype]]. +var customProto = new Number(8675309); +tp = + new Proxy({}, + { getPrototypeOf() { + x = "getPrototypeOf trap"; + return customProto; + } }); + +// The target's [[GetPrototypeOf]] should be invoked if the handler's +// .getPrototypeOf is undefined. +p = new Proxy(tp, { getPrototypeOf: undefined }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), customProto); +assertEq(x, "getPrototypeOf trap"); + +// Likewise if the handler's .getPrototypeOf is null. +p = new Proxy(tp, { getPrototypeOf: null }); +x = "unset"; +assertEq(Object.getPrototypeOf(p), customProto); +assertEq(x, "getPrototypeOf trap"); + +// 7. Let handlerProto be ? Call(trap, handler, « target »). + +// The trap callable might throw. +p = new Proxy({}, { getPrototypeOf() { throw "ohai"; } }); + +assertThrowsValue(() => Object.getPrototypeOf(p), + "ohai"); + +var throwingTrap = + new Proxy(function() { throw "not called"; }, + { apply() { throw 37; } }); + +p = new Proxy({}, { getPrototypeOf: throwingTrap }); + +assertThrowsValue(() => Object.getPrototypeOf(p), + 37); + +// The trap callable must *only* be called. +p = new Proxy({}, + { + getPrototypeOf: observe(function() { throw "boo-urns"; }) + }); + +log.length = 0; +assertThrowsValue(() => Object.getPrototypeOf(p), + "boo-urns"); + +assertEq(log.length, 1); +assertEq(log[0], "apply"); + +// 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError exception. + +var rval; + +var typeTestingTarget = {}; +p = new Proxy(typeTestingTarget, { getPrototypeOf() { return rval; } }); + +function returnsPrimitives() +{ + rval = undefined; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = true; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = false; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = 0.0; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = -0.0; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = 3.141592654; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = NaN; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = -Infinity; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = "[[Prototype]] FOR REALZ"; + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + + rval = Symbol("[[Prototype]] FOR REALZ"); + assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); +} + +returnsPrimitives(); +Object.preventExtensions(typeTestingTarget); +returnsPrimitives(); + +// 9. Let extensibleTarget be ? IsExtensible(target). + +var act, extens; + +var typeTestingProxyTarget = + new Proxy({}, { isExtensible() { + seen = act(); + return extens; + } }); + +p = new Proxy(typeTestingProxyTarget, { getPrototypeOf() { return rval; } }); + +rval = null; +act = () => { throw "fnord" }; +assertThrowsValue(() => Object.getPrototypeOf(p), + "fnord"); + +rval = /abc/; +act = () => { throw "fnord again" }; +assertThrowsValue(() => Object.getPrototypeOf(p), + "fnord again"); + +rval = Object.prototype; +act = () => { throw "fnord" }; +assertThrowsValue(() => Object.getPrototypeOf(p), + "fnord"); + +// 10. If extensibleTarget is true, return handlerProto. + +p = new Proxy({}, { getPrototypeOf() { return rval; } }); + +rval = Number.prototype; +assertEq(Object.getPrototypeOf(p), Number.prototype); + +// 11. Let targetProto be ? target.[[GetPrototypeOf]](). + +var targetProto; + +var targetWithProto = + new Proxy(Object.preventExtensions(Object.create(null)), + { getPrototypeOf() { act2(); return targetProto; } }); + +p = new Proxy(targetWithProto, + { getPrototypeOf() { act1(); return rval; } }); + +rval = null; +targetProto = null; + +var regex = /targetProto/; + +act1 = () => log.push("act1"); +act2 = () => log.push("act2"); + +log.length = 0; +assertEq(Object.getPrototypeOf(p), null); +assertEq(log.length, 2); +assertEq(log[0], "act1"); +assertEq(log[1], "act2"); + +act1 = () => log.push("act1 again"); +act2 = () => { throw "target throw"; }; + +log.length = 0; +assertThrowsValue(() => Object.getPrototypeOf(p), + "target throw"); +assertEq(log.length, 1); +assertEq(log[0], "act1 again"); + +// 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception. + +act1 = act2 = nop; +rval = /a/; +assertThrowsInstanceOf(() => Object.getPrototypeOf(p), + TypeError); + +// 13. Return handlerProto. + +rval = null; +targetProto = null; + +assertEq(Object.getPrototypeOf(p), null); + +p = new Proxy(Object.preventExtensions(new Number(55)), + { getPrototypeOf() { return Number.prototype; } }); + +assertEq(Object.getPrototypeOf(p), Number.prototype); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/global-receiver.js b/js/src/tests/ecma_6/Proxy/global-receiver.js new file mode 100644 index 000000000..b2d160c0d --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/global-receiver.js @@ -0,0 +1,35 @@ +// The global object can be the receiver passed to the get and set traps of a Proxy. +var global = this; +var proto = Object.getPrototypeOf(global); +var gets = 0, sets = 0; + +try { + Object.setPrototypeOf(global, new Proxy(proto, { + has(t, id) { + return id === "bareword" || Reflect.has(t, id); + }, + get(t, id, r) { + gets++; + assertEq(r, global); + return Reflect.get(t, id, r); + }, + set(t, id, v, r) { + sets++; + assertEq(r, global); + return Reflect.set(t, id, v, r); + } + })); +} catch (e) { + global.bareword = undefined; + gets = 1; + sets = 1; +} + +assertEq(bareword, undefined); +assertEq(gets, 1); + +bareword = 12; +assertEq(sets, 1); +assertEq(global.bareword, 12); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Proxy/hasInstance.js b/js/src/tests/ecma_6/Proxy/hasInstance.js new file mode 100644 index 000000000..bbdffb227 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/hasInstance.js @@ -0,0 +1,13 @@ +var get = []; +var fun = function() {} +var p = new Proxy(fun, { + get(target, key) { + get.push(key); + return target[key]; + } +}); + +assertEq(new fun instanceof p, true); +assertDeepEq(get, [Symbol.hasInstance, "prototype"]); + +reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/json-stringify-replacer-array-revocable-proxy.js b/js/src/tests/ecma_6/Proxy/json-stringify-replacer-array-revocable-proxy.js new file mode 100644 index 000000000..5d667e353 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/json-stringify-replacer-array-revocable-proxy.js @@ -0,0 +1,39 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +var gTestfile = "json-stringify-replacer-array-revocable-proxy.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 1196497; +var summary = + "Don't assert when JSON.stringify is passed a revocable proxy to an array, " + + "then that proxy is revoked midflight during stringification"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var arr = []; +var { proxy, revoke } = Proxy.revocable(arr, { + get(thisv, prop, receiver) { + // First (and only) get will be for "length", to determine the length of the + // list of properties to serialize. Returning 0 uses the empty list, + // resulting in |a: 0| being ignored below. + assertEq(thisv, arr); + assertEq(prop, "length"); + assertEq(receiver, proxy); + + revoke(); + return 0; + } +}); + +assertEq(JSON.stringify({a: 0}, proxy), "{}"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/ownkeys-allowed-types.js b/js/src/tests/ecma_6/Proxy/ownkeys-allowed-types.js new file mode 100644 index 000000000..028ab8512 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/ownkeys-allowed-types.js @@ -0,0 +1,20 @@ +function makeProxy(type) { + return new Proxy({}, { ownKeys() { return [type]; } }); +} + +for (var type of [123, 12.5, true, false, undefined, null, {}, []]) { + var proxy = makeProxy(type); + assertThrowsInstanceOf(() => Object.ownKeys(proxy), TypeError); + assertThrowsInstanceOf(() => Object.getOwnPropertyNames(proxy), TypeError); +} + +type = Symbol(); +proxy = makeProxy(type); +assertEq(Object.getOwnPropertySymbols(proxy)[0], type); + +type = "abc"; +proxy = makeProxy(type); +assertEq(Object.getOwnPropertyNames(proxy)[0], type); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/ownkeys-linear.js b/js/src/tests/ecma_6/Proxy/ownkeys-linear.js new file mode 100644 index 000000000..7b05a9384 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/ownkeys-linear.js @@ -0,0 +1,70 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'ownkeys-linear.js'; +var BUGNUMBER = 1257779; +var summary = + "Scripted proxies' [[OwnPropertyKeys]] should have linear complexity"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// Making this 50k makes cgc builds time out on tbpl. 5k takes 28s locally. +// 10k takes 84s locally. So pick an intermediate number, with a generous +// constant factor in case cgc-on-tbpl is much slower. +const HALF_COUNT = 7500; + +var configurables = []; +for (var i = 0; i < HALF_COUNT; i++) + configurables.push("conf" + i); + +var nonconfigurables = []; +for (var i = 0; i < HALF_COUNT; i++) + nonconfigurables.push("nonconf" + i); + +var target = {}; +for (var name of configurables) + Object.defineProperty(target, name, { configurable: false, value: 0 }); +for (var name of nonconfigurables) + Object.defineProperty(target, name, { configurable: true, value: 0 }); + +var handler = { + ownKeys(t) { + assertEq(t, target, "target mismatch!"); + + var trapResult = []; + + // Append all nonconfigurables in reverse order of presence. + for (var i = nonconfigurables.length; i > 0; i--) + trapResult.push(nonconfigurables[i - 1]); + + // Then the same for all configurables. + for (var i = configurables.length; i > 0; i--) + trapResult.push(configurables[i - 1]); + + // The end consequence is that this ordering is exactly opposite the + // ordering they'll have on the target, and so worst-case performance will + // occur if the spec's |uncheckedResultKeys| structure is a vector having + // the same order as |trapResult|, searched from beginning to end in the + // presence-checks in the last few steps of the [[OwnPropertyKeys]] + // algorithm. + return trapResult; + } +}; + +var p = new Proxy(target, handler); + +// The test passes if it doesn't time out. +assertEq(Object.getOwnPropertyNames(p).length, HALF_COUNT * 2); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/ownkeys-trap-duplicates.js b/js/src/tests/ecma_6/Proxy/ownkeys-trap-duplicates.js new file mode 100644 index 000000000..eef84d571 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/ownkeys-trap-duplicates.js @@ -0,0 +1,32 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'ownkeys-trap-duplicates.js'; +var BUGNUMBER = 1293995; +var summary = + "Scripted proxies' [[OwnPropertyKeys]] should not throw if the trap " + + "implementation returns duplicate properties and the object is " + + "non-extensible or has non-configurable properties"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var target = Object.preventExtensions({ a: 1 }); +var proxy = new Proxy(target, { ownKeys(t) { return ["a", "a"]; } }); +assertDeepEq(Object.getOwnPropertyNames(proxy), ["a", "a"]); + +target = Object.freeze({ a: 1 }); +proxy = new Proxy(target, { ownKeys(t) { return ["a", "a"]; } }); +assertDeepEq(Object.getOwnPropertyNames(proxy), ["a", "a"]); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/proxy-__proto__.js b/js/src/tests/ecma_6/Proxy/proxy-__proto__.js new file mode 100644 index 000000000..f68bea489 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/proxy-__proto__.js @@ -0,0 +1,59 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'proxy-__proto__.js'; +var BUGNUMBER = 950407; +var summary = "Behavior of __proto__ on ES6 proxies"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var protoDesc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__"); +var protoGetter = protoDesc.get; +var protoSetter = protoDesc.set; + +function testProxy(target, initialProto) +{ + print("Now testing behavior for new Proxy(" + ("" + target) + ", {})"); + + var pobj = new Proxy(target, {}); + + // Check [[Prototype]] before attempted mutation + assertEq(Object.getPrototypeOf(pobj), initialProto); + assertEq(protoGetter.call(pobj), initialProto); + + // Attempt [[Prototype]] mutation + protoSetter.call(pobj, null); + + // Check [[Prototype]] after attempted mutation + assertEq(Object.getPrototypeOf(pobj), null); + assertEq(protoGetter.call(pobj), null); + assertEq(Object.getPrototypeOf(target), null); +} + +// Proxy object with non-null [[Prototype]] +var nonNullProto = { toString: function() { return "non-null prototype"; } }; +var target = Object.create(nonNullProto); +testProxy(target, nonNullProto); + +// Proxy object with null [[Prototype]] +target = Object.create(null); +target.toString = function() { return "null prototype" }; +testProxy(target, null); + +// Proxy function with [[Call]] +var callForCallOnly = function () { }; +callForCallOnly.toString = function() { return "callable target"; }; +testProxy(callForCallOnly, Function.prototype); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/proxy-constructNonObject.js b/js/src/tests/ecma_6/Proxy/proxy-constructNonObject.js new file mode 100644 index 000000000..04cee11e9 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/proxy-constructNonObject.js @@ -0,0 +1,18 @@ +function bogusConstruct(target) { return 4; } +function bogusConstructUndefined(target) { } + +var handler = { construct: bogusConstruct } + +function callable() {} + +var p = new Proxy(callable, handler); + +assertThrowsInstanceOf(function () { new p(); }, TypeError, + "[[Construct must throw if an object is not returned."); + +handler.construct = bogusConstructUndefined; +assertThrowsInstanceOf(function () { new p(); }, TypeError, + "[[Construct must throw if an object is not returned."); + +if (typeof reportCompare === "function") + reportCompare(0,0, "OK"); diff --git a/js/src/tests/ecma_6/Proxy/proxy-for-in.js b/js/src/tests/ecma_6/Proxy/proxy-for-in.js new file mode 100644 index 000000000..4332bfbba --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/proxy-for-in.js @@ -0,0 +1,37 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ +"use strict"; + +let steps = []; + +const object = { + __proto__: { + "xyz": 42 + } +}; +const proxy = new Proxy(object, { + ownKeys(target) { + steps.push("ownKeys") + return ["a", "b"]; + }, + + getOwnPropertyDescriptor(target, property) { + steps.push("getOwn-" + property); + return { + value: undefined, + configurable: true, + writable: true, + enumerable: (property === "a") + }; + } +}); + +let iterated = []; +for (let x in proxy) + iterated.push(x); + +assertEq(iterated.toString(), "a,xyz"); +assertEq(steps.toString(), "ownKeys,getOwn-a,getOwn-b"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/proxy-no-receiver-overwrite.js b/js/src/tests/ecma_6/Proxy/proxy-no-receiver-overwrite.js new file mode 100644 index 000000000..86d352d45 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/proxy-no-receiver-overwrite.js @@ -0,0 +1,23 @@ +"use strict"; + +var y = new Proxy({}, { + getOwnPropertyDescriptor(target, key) { + if (key === "a") { + return { configurable: true, get: function(v) {} }; + } else { + assertEq(key, "b"); + return { configurable: true, writable: false, value: 15 }; + } + }, + + defineProperty() { + throw "not invoked"; + } +}) + +// This will invoke [[Set]] on the target, with the proxy as receiver. +assertThrowsInstanceOf(() => y.a = 1, TypeError); +assertThrowsInstanceOf(() => y.b = 2, TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js b/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js new file mode 100644 index 000000000..e0ae15acf --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/proxy-with-revoked-arguments.js @@ -0,0 +1,53 @@ +var BUGNUMBER = 1151149; +var summary = "Proxy constructor should throw if either the target or handler is a revoked proxy."; + +print(BUGNUMBER + ": " + summary); + +var p = new Proxy({}, {}); + +new Proxy(p, {}); +new Proxy({}, p); + +var r = Proxy.revocable({}, {}); +p = r.proxy; + +new Proxy(p, {}); +new Proxy({}, p); + +r.revoke(); + +assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError); +assertThrowsInstanceOf(() => new Proxy({}, p), TypeError); + + +var r2 = Proxy.revocable({}, {}); +r = Proxy.revocable(r2.proxy, {}); +p = r.proxy; + +new Proxy(p, {}); +new Proxy({}, p); + +r2.revoke(); + +new Proxy(p, {}); +new Proxy({}, p); + +r.revoke(); + +assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError); +assertThrowsInstanceOf(() => new Proxy({}, p), TypeError); + + +var g = newGlobal(); +p = g.eval(`var r = Proxy.revocable({}, {}); r.proxy;`); + +new Proxy(p, {}); +new Proxy({}, p); + +g.eval(`r.revoke();`); + +assertThrowsInstanceOf(() => new Proxy(p, {}), TypeError); +assertThrowsInstanceOf(() => new Proxy({}, p), TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/regress-bug1037770.js b/js/src/tests/ecma_6/Proxy/regress-bug1037770.js new file mode 100644 index 000000000..240b04f32 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/regress-bug1037770.js @@ -0,0 +1,7 @@ +foo = 1; +Object.defineProperty(this, "foo", {writable:false, configurable:true}); +foo = 2; +assertEq(foo, 1); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/regress-bug1062349.js b/js/src/tests/ecma_6/Proxy/regress-bug1062349.js new file mode 100644 index 000000000..fe0ad3d9a --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/regress-bug1062349.js @@ -0,0 +1,31 @@ +// Adapted from a test case contributed by André Bargull in bug 1062349. + +var log = []; +var hh = { + get(t, pk) { + log.push("trap: " + pk); + return t[pk]; + } +}; +var h = new Proxy({ + get set() { + log.push("called set()"); + Object.defineProperty(o, "prop", {value: 0}); + log.push("o.prop:", Object.getOwnPropertyDescriptor(o, "prop")); + } +}, hh); +var p = new Proxy({}, h); +var o = {__proto__: p}; + +o.prop = 1; + +var expectedDesc = {value: 0, writable: false, enumerable: false, configurable: false}; +assertDeepEq(log, [ + "trap: set", + "called set()", + "o.prop:", + expectedDesc +]); +assertDeepEq(Object.getOwnPropertyDescriptor(o, "prop"), expectedDesc); + +reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Proxy/regress-bug950407.js b/js/src/tests/ecma_6/Proxy/regress-bug950407.js new file mode 100644 index 000000000..bb4a71eb0 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/regress-bug950407.js @@ -0,0 +1,11 @@ +var ab = new ArrayBuffer(5); +var p = new Proxy(ab, {}); +var ps = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").set; +var threw = 0; +try { + ps.call(p, {}); +} catch(ex) { + threw = 1; +} + +reportCompare(1, threw, "Setting __proto__ on a proxy to an ArrayBuffer must throw."); diff --git a/js/src/tests/ecma_6/Proxy/revocable-proxy-prototype.js b/js/src/tests/ecma_6/Proxy/revocable-proxy-prototype.js new file mode 100644 index 000000000..7afbc15d2 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/revocable-proxy-prototype.js @@ -0,0 +1,40 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'revocable-proxy-prototype.js'; +var BUGNUMBER = 1052139; +var summary = "Accessing a revocable proxy's [[Prototype]] shouldn't crash"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ +function checkFunctionAppliedToRevokedProxy(fun) +{ + var p = Proxy.revocable({}, {}); + p.revoke(); + + try + { + fun(p.proxy); + throw "didn't throw"; + } + catch (e) + { + assertEq(e instanceof TypeError, true, + "expected TypeError, got " + e); + } +} + +checkFunctionAppliedToRevokedProxy(proxy => Object.getPrototypeOf(proxy)); +checkFunctionAppliedToRevokedProxy(proxy => Object.setPrototypeOf(proxy, null)); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/revoke-as-side-effect.js b/js/src/tests/ecma_6/Proxy/revoke-as-side-effect.js new file mode 100644 index 000000000..25d4c9bf9 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/revoke-as-side-effect.js @@ -0,0 +1,73 @@ +function createProxy(proxyTarget) { + var {proxy, revoke} = Proxy.revocable(proxyTarget, new Proxy({}, { + get(target, propertyKey, receiver) { + print("trap get:", propertyKey); + revoke(); + } + })); + return proxy; +} + +var obj; + +// [[GetPrototypeOf]] +assertEq(Object.getPrototypeOf(createProxy({})), Object.prototype); +assertEq(Object.getPrototypeOf(createProxy([])), Array.prototype); + +// [[SetPrototypeOf]] +obj = {}; +Object.setPrototypeOf(createProxy(obj), Array.prototype); +assertEq(Object.getPrototypeOf(obj), Array.prototype); + +// [[IsExtensible]] +assertEq(Object.isExtensible(createProxy({})), true); +assertEq(Object.isExtensible(createProxy(Object.preventExtensions({}))), false); + +// [[PreventExtensions]] +obj = {}; +Object.preventExtensions(createProxy(obj)); +assertEq(Object.isExtensible(obj), false); + +// [[GetOwnProperty]] +assertEq(Object.getOwnPropertyDescriptor(createProxy({}), "a"), undefined); +assertEq(Object.getOwnPropertyDescriptor(createProxy({a: 5}), "a").value, 5); + +// [[DefineOwnProperty]] +obj = {}; +Object.defineProperty(createProxy(obj), "a", {value: 5}); +assertEq(obj.a, 5); + +// [[HasProperty]] +assertEq("a" in createProxy({}), false); +assertEq("a" in createProxy({a: 5}), true); + +// [[Get]] +assertEq(createProxy({}).a, undefined); +assertEq(createProxy({a: 5}).a, 5); + +// [[Set]] +assertThrowsInstanceOf(() => createProxy({}).a = 0, TypeError); +assertThrowsInstanceOf(() => createProxy({a: 5}).a = 0, TypeError); + +// [[Delete]] +assertEq(delete createProxy({}).a, true); +assertEq(delete createProxy(Object.defineProperty({}, "a", {configurable: false})).a, false); + +// [[OwnPropertyKeys]] +assertEq(Object.getOwnPropertyNames(createProxy({})).length, 0); +assertEq(Object.getOwnPropertyNames(createProxy({a: 5})).length, 1); + +// [[Call]] +assertEq(createProxy(function() { return "ok" })(), "ok"); + +// [[Construct]] +// This throws because after the "construct" trap on the proxy is consulted, +// OrdinaryCreateFromConstructor (called because the |q| function's +// [[ConstructorKind]] is "base" per FunctionAllocate) accesses +// |new.target.prototype| to create the |this| for the construct operation, that +// would be returned if |return obj;| didn't override it. +assertThrowsInstanceOf(() => new (createProxy(function q(){ return obj; })), + TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Proxy/setPrototypeOf.js b/js/src/tests/ecma_6/Proxy/setPrototypeOf.js new file mode 100644 index 000000000..d79c53fd9 --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/setPrototypeOf.js @@ -0,0 +1,258 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "setPrototypeOf.js"; +var BUGNUMBER = 888969; +var summary = "Scripted proxies' [[SetPrototypeOf]] behavior"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +const log = []; + +function observe(obj) +{ + var observingHandler = new Proxy({}, { + get(target, p, receiver) { + log.push(p); + return Reflect.get(target, p, receiver); + } + }); + + return new Proxy(obj, observingHandler); +} + +var p, h; + +// 1. Assert: Either Type(V) is Object or Type(V) is Null. +// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. +// 3. If handler is null, throw a TypeError exception. +// 4. Assert: Type(handler) is Object. +// 5. Let target be the value of the [[ProxyTarget]] internal slot of O. + +var rev = Proxy.revocable({}, {}); +p = rev.proxy; + +var originalProto = Reflect.getPrototypeOf(p); +assertEq(originalProto, Object.prototype); + +rev.revoke(); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, originalProto), + TypeError); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +// 6. Let trap be ? GetMethod(handler, "setPrototypeOf"). + +// handler has uncallable (and not null/undefined) property +p = new Proxy({}, { setPrototypeOf: 9 }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: -3.7 }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: NaN }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: Infinity }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: true }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: /x/ }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: Symbol(42) }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, { setPrototypeOf: class X {} }); +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +p = new Proxy({}, observe({})); + +assertEq(Reflect.setPrototypeOf(p, Object.prototype), true); +assertEq(log.length, 1); +assertEq(log[0], "get"); + +h = observe({ setPrototypeOf() { throw 3.14; } }); +p = new Proxy(Object.create(Object.prototype), h); + +// "setting" without change +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + 3.14); +assertEq(log.length, 1); +assertEq(log[0], "get"); + +// "setting" with change +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, /foo/), + 3.14); +assertEq(log.length, 1); +assertEq(log[0], "get"); + +// 7. If trap is undefined, then +// a. Return ? target.[[SetPrototypeOf]](V). + +var settingProtoThrows = + new Proxy({}, { setPrototypeOf() { throw "agnizes"; } }); + +p = new Proxy(settingProtoThrows, { setPrototypeOf: undefined }); +assertThrowsValue(() => Reflect.setPrototypeOf(p, null), + "agnizes"); + +p = new Proxy(settingProtoThrows, { setPrototypeOf: null }); +assertThrowsValue(() => Reflect.setPrototypeOf(p, null), + "agnizes"); + +var anotherProto = + new Proxy({}, + { setPrototypeOf(t, p) { + log.push("reached"); + return Reflect.setPrototypeOf(t, p); + } }); + +p = new Proxy(anotherProto, { setPrototypeOf: undefined }); + +log.length = 0; +assertEq(Reflect.setPrototypeOf(p, null), true); +assertEq(log.length, 1); +assertEq(log[0], "reached"); + +p = new Proxy(anotherProto, { setPrototypeOf: null }); + +log.length = 0; +assertEq(Reflect.setPrototypeOf(p, null), true); +assertEq(log.length, 1); +assertEq(log[0], "reached"); + +// 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V »)). + +// The trap callable might throw. +p = new Proxy({}, { setPrototypeOf() { throw "ohai"; } }); + +assertThrowsValue(() => Reflect.setPrototypeOf(p, /x/), + "ohai"); + +var throwingTrap = + new Proxy(function() { throw "not called"; }, + { apply() { throw 37; } }); + +p = new Proxy({}, { setPrototypeOf: throwingTrap }); + +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + 37); + +// The trap callable must *only* be called. +p = new Proxy({}, + { + setPrototypeOf: observe(function() { throw "boo-urns"; }) + }); + +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + "boo-urns"); + +assertEq(log.length, 1); +assertEq(log[0], "apply"); + +// 9. If booleanTrapResult is false, return false. + +p = new Proxy({}, { setPrototypeOf() { return false; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return +0; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return -0; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return NaN; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return ""; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +p = new Proxy({}, { setPrototypeOf() { return undefined; } }); +assertEq(Reflect.setPrototypeOf(p, Object.prototype), false); + +// 10. Let extensibleTarget be ? IsExtensible(target). + +var targetThrowIsExtensible = + new Proxy({}, { isExtensible() { throw "psych!"; } }); + +p = new Proxy(targetThrowIsExtensible, { setPrototypeOf() { return true; } }); +assertThrowsValue(() => Reflect.setPrototypeOf(p, Object.prototype), + "psych!"); + +// 11. If extensibleTarget is true, return true. + +var targ = {}; + +p = new Proxy(targ, { setPrototypeOf() { return true; } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +p = new Proxy(targ, { setPrototypeOf() { return /x/; } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +p = new Proxy(targ, { setPrototypeOf() { return Infinity; } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +p = new Proxy(targ, { setPrototypeOf() { return Symbol(true); } }); +assertEq(Reflect.setPrototypeOf(p, /x/), true); +assertEq(Reflect.getPrototypeOf(targ), Object.prototype); +assertEq(Reflect.getPrototypeOf(p), Object.prototype); + +// 12. Let targetProto be ? target.[[GetPrototypeOf]](). + +var targetNotExtensibleGetProtoThrows = + new Proxy(Object.preventExtensions({}), + { getPrototypeOf() { throw NaN; } }); + +p = new Proxy(targetNotExtensibleGetProtoThrows, + { setPrototypeOf() { log.push("goober"); return true; } }); + +log.length = 0; +assertThrowsValue(() => Reflect.setPrototypeOf(p, /abcd/), + NaN); + +// 13. If SameValue(V, targetProto) is false, throw a TypeError exception. + +var newProto; + +p = new Proxy(Object.preventExtensions(Object.create(Math)), + { setPrototypeOf(t, p) { return true; } }); + +assertThrowsInstanceOf(() => Reflect.setPrototypeOf(p, null), + TypeError); + +// 14. Return true. + +assertEq(Reflect.setPrototypeOf(p, Math), true); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Proxy/shell.js b/js/src/tests/ecma_6/Proxy/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/shell.js diff --git a/js/src/tests/ecma_6/Proxy/trap-null.js b/js/src/tests/ecma_6/Proxy/trap-null.js new file mode 100644 index 000000000..703649e7c --- /dev/null +++ b/js/src/tests/ecma_6/Proxy/trap-null.js @@ -0,0 +1,103 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = 'trap-null.js'; +var BUGNUMBER = 1257102; +var summary = "null as a trap value on a handler should operate on the target"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// This might seem like overkill, but this proxying trick caught typos of +// several trap names before this test landed. \o/ /o\ +var allTraps = { + getPrototypeOf: null, + setPrototypeOf: null, + isExtensible: null, + preventExtensions: null, + getOwnPropertyDescriptor: null, + defineProperty: null, + has: null, + get: null, + set: null, + deleteProperty: null, + ownKeys: null, + apply: null, + construct: null, +}; + +var complainingHandler = new Proxy(allTraps, { + get(target, p, receiver) { + var v = Reflect.get(target, p, receiver); + if (v !== null) + throw new TypeError("failed to set one of the traps to null? " + p); + + return v; + } +}); + +var proxyTarget = function(x) { + "use strict"; + var str = this + x; + str += new.target ? "constructing" : "calling"; + return new.target ? new String(str) : str; +}; +proxyTarget.prototype.toString = () => "###"; +proxyTarget.prototype.valueOf = () => "@@@"; + +var proxy = new Proxy(proxyTarget, complainingHandler); + +assertEq(Reflect.getPrototypeOf(proxy), Function.prototype); + +assertEq(Object.getPrototypeOf(proxyTarget), Function.prototype); +assertEq(Reflect.setPrototypeOf(proxy, null), true); +assertEq(Object.getPrototypeOf(proxyTarget), null); + +assertEq(Reflect.isExtensible(proxy), true); + +assertEq(Reflect.isExtensible(proxyTarget), true); +assertEq(Reflect.preventExtensions(proxy), true); +assertEq(Reflect.isExtensible(proxy), false); +assertEq(Reflect.isExtensible(proxyTarget), false); + +var desc = Reflect.getOwnPropertyDescriptor(proxy, "length"); +assertEq(desc.value, 1); + +assertEq(desc.configurable, true); +assertEq(Reflect.defineProperty(proxy, "length", { value: 3, configurable: false }), true); +desc = Reflect.getOwnPropertyDescriptor(proxy, "length"); +assertEq(desc.configurable, false); + +assertEq(Reflect.has(proxy, "length"), true); + +assertEq(Reflect.get(proxy, "length"), 3); + +assertEq(Reflect.set(proxy, "length", 3), false); + +assertEq(Reflect.deleteProperty(proxy, "length"), false); + +var keys = Reflect.ownKeys(proxy); +assertEq(keys.length, 3); +keys.sort(); +assertEq(keys[0], "length"); +assertEq(keys[1], "name"); +assertEq(keys[2], "prototype"); + +assertEq(Reflect.apply(proxy, "hi!", [" "]), "hi! calling"); + +var res = Reflect.construct(proxy, [" - "]); +assertEq(typeof res, "object"); +assertEq(res instanceof String, true); +assertEq(res.valueOf(), "@@@ - constructing"); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); |