| function assert(b) { |
| if (!b) |
| throw new Error("Bad assertion"); |
| } |
| |
| { |
| let error = null; |
| let target = { }; |
| let handler = { |
| ownKeys: function() { |
| error = new Error; |
| throw error; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e === error); |
| } |
| assert(threw); |
| } |
| } |
| |
| { |
| let error = null; |
| let target = { }; |
| let handler = { |
| get ownKeys() { |
| error = new Error; |
| throw error; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e === error); |
| } |
| assert(threw); |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return ["1", 2, 3]; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' method must return an array-like object containing only Strings and Symbols"); |
| } |
| assert(threw); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { }; |
| Object.defineProperty(target, "x", { |
| configurable: false, |
| enumerable: true, |
| value: 400 |
| }); |
| let called = false; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return []; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e.toString() === "TypeError: Proxy object's 'target' has the non-configurable property 'x' that was not in the result from the 'ownKeys' trap"); |
| } |
| assert(threw); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { }; |
| Object.defineProperty(target, "x", { |
| configurable: true, |
| enumerable: true, |
| value: 400 |
| }); |
| Object.preventExtensions(target); |
| let called = false; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return []; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e.toString() === "TypeError: Proxy object's non-extensible 'target' has configurable property 'x' that was not in the result from the 'ownKeys' trap"); |
| } |
| assert(threw); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { }; |
| Object.defineProperty(target, "x", { |
| configurable: true, |
| enumerable: true, |
| value: 400 |
| }); |
| Object.preventExtensions(target); |
| let called = false; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return ["x", "y"]; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' method returned a key that was not present in its non-extensible target"); |
| } |
| assert(threw); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = {}; |
| let called1 = false; |
| let called2 = false; |
| Object.defineProperty(target, 'a', { value: 42, configurable: false }); |
| let p1 = new Proxy(target, { |
| ownKeys() { |
| called1 = true; |
| return ['a', 'a']; |
| } |
| }); |
| let p2 = new Proxy(p1, { |
| ownKeys() { |
| called2 = true; |
| return ['a']; |
| } |
| }); |
| |
| for (let i = 0; i < 500; i++) { |
| // FIXME: we may update the spec to make this test not throw. |
| // see: https://github.com/tc39/ecma262/pull/594 |
| let threw = false; |
| try { |
| Reflect.ownKeys(p2); |
| } catch(e) { |
| assert(e.toString() === "TypeError: Proxy object's 'target' has the non-configurable property 'a' that was not in the result from the 'ownKeys' trap"); |
| threw = true; |
| } |
| assert(threw); |
| assert(called1); |
| assert(called2); |
| } |
| } |
| |
| { |
| let target = {}; |
| let called1 = false; |
| let called2 = false; |
| Object.defineProperty(target, 'a', { value: 42, configurable: true }); |
| Object.preventExtensions(target); |
| let p1 = new Proxy(target, { |
| ownKeys() { |
| called1 = true; |
| return ['a', 'a']; |
| } |
| }); |
| let p2 = new Proxy(p1, { |
| ownKeys() { |
| called2 = true; |
| return ['a']; |
| } |
| }); |
| |
| for (let i = 0; i < 500; i++) { |
| // FIXME: we may update the spec to make this test not throw. |
| // see: https://github.com/tc39/ecma262/pull/594 |
| let threw = false; |
| try { |
| Reflect.ownKeys(p2); |
| } catch(e) { |
| assert(e.toString() === "TypeError: Proxy object's non-extensible 'target' has configurable property 'a' that was not in the result from the 'ownKeys' trap"); |
| threw = true; |
| } |
| assert(threw); |
| assert(called1); |
| assert(called2); |
| } |
| } |
| |
| { |
| let target = { }; |
| Object.defineProperty(target, "x", { |
| configurable: true, |
| enumerable: true, |
| value: 400 |
| }); |
| Object.preventExtensions(target); |
| let called = false; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return ["x", "x"]; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| Object.keys(proxy); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { }; |
| let handler = { |
| ownKeys: 45 |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e.toString() === "TypeError: 'ownKeys' property of a Proxy's handler should be callable"); |
| } |
| assert(threw); |
| } |
| } |
| |
| function shallowEq(a, b) { |
| if (a.length !== b.length) |
| return false; |
| for (let i = 0; i < a.length; i++) { |
| if (a[i] !== b[i]) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let arr = ["a", "b", "c"]; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let result = Object.keys(proxy); |
| assert(result !== arr); |
| assert(shallowEq(result, [])); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let arr = ["a", "b", "c"]; |
| let handler = { |
| getOwnPropertyDescriptor: function(theTarget, propertyName) { |
| if (arr.indexOf(propertyName) >= 0) { |
| return { |
| enumerable: true, |
| configurable: true |
| }; |
| } |
| return Reflect.getOwnPropertyDescriptor(theTarget, propertyName); |
| }, |
| |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let result = Object.keys(proxy); |
| assert(result !== arr); |
| assert(shallowEq(result, arr)); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let arr = ["a", "b", "c"]; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let result = Reflect.ownKeys(proxy); |
| assert(result !== arr); |
| assert(shallowEq(result, arr)); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let result = Object.getOwnPropertySymbols(proxy); |
| assert(shallowEq(result, [s1, s2])); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| getOwnPropertyDescriptor(theTarget, propertyName) { |
| if (arr.indexOf(propertyName) >= 0) { |
| return { |
| enumerable: true, |
| configurable: true |
| } |
| } |
| return Reflect.getOwnPropertyDescriptor(theTarget, propertyName); |
| }, |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let result = Object.keys(proxy); |
| assert(shallowEq(result, ["a", "b", "c"])); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let result = Reflect.ownKeys(proxy); |
| assert(shallowEq(result, ["a", "b", "c", s1, s2])); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| getOwnPropertyDescriptor: () => { |
| return { enumerable: true, configurable: true } |
| }, |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let set = new Set; |
| for (let p in proxy) |
| set.add(p); |
| assert(set.size === 3); |
| assert(set.has("a")); |
| assert(set.has("b")); |
| assert(set.has("c")); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| getOwnPropertyDescriptor: () => { |
| return { enumerable: true, configurable: true } |
| }, |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let set = new Set; |
| for (let p in proxy) |
| set.add(p); |
| if (i === 40) { // Make sure we don't cache the result. |
| arr.push("d"); |
| } |
| assert(set.size === i > 40 ? 4 : 3); |
| assert(set.has("a")); |
| assert(set.has("b")); |
| assert(set.has("c")); |
| if (i > 40) |
| assert(set.has("d")); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| getOwnPropertyDescriptor: () => { |
| return { enumerable: true, configurable: true } |
| }, |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| let proxyish = Object.create(proxy, { |
| d: { enumerable: true, configurable: true } |
| }); |
| for (let i = 0; i < 500; i++) { |
| let set = new Set; |
| for (let p in proxyish) |
| set.add(p); |
| assert(set.size === 4); |
| assert(set.has("a")); |
| assert(set.has("b")); |
| assert(set.has("c")); |
| assert(set.has("d")); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let target = { |
| x: 40 |
| }; |
| let called = false; |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| getOwnPropertyDescriptor: () => { |
| return { enumerable: true, configurable: true } |
| }, |
| ownKeys: function(theTarget) { |
| called = true; |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| let proxyish = Object.create(proxy, { |
| d: { enumerable: true, configurable: true } |
| }); |
| for (let i = 0; i < 500; i++) { |
| let set = new Set; |
| for (let p in proxyish) |
| set.add(p); |
| assert(set.size === 4); |
| assert(set.has("a")); |
| assert(set.has("b")); |
| assert(set.has("c")); |
| assert(set.has("d")); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let called = false; |
| let target = {x: 20, y: 40}; |
| let handler = { |
| ownKeys: null |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let keys = Object.keys(proxy); |
| assert(keys.indexOf("x") !== -1); |
| assert(keys.indexOf("y") !== -1); |
| } |
| } |
| |
| { |
| let called = false; |
| let target = new Proxy({}, { |
| ownKeys: function(theTarget) { |
| called = true; |
| return Reflect.ownKeys(theTarget); |
| } |
| }); |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| ownKeys: function(theTarget) { |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let keys = Object.keys(proxy); |
| assert(called); |
| called = false; |
| } |
| } |
| |
| { |
| let error = null; |
| let target = new Proxy({}, { |
| ownKeys: function(theTarget) { |
| error = new Error; |
| throw error; |
| } |
| }); |
| let s1 = Symbol(); |
| let s2 = Symbol(); |
| let arr = ["a", "b", s1, "c", s2]; |
| let handler = { |
| ownKeys: function(theTarget) { |
| return arr; |
| } |
| }; |
| |
| let proxy = new Proxy(target, handler); |
| for (let i = 0; i < 500; i++) { |
| let threw = false; |
| try { |
| Object.keys(proxy); |
| } catch(e) { |
| threw = true; |
| assert(e === error); |
| } |
| assert(threw); |
| error = null; |
| } |
| } |