blob: 2b3060b17e781edd553615d52b0afb1da2900254 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
Ben Murdoch3ef787d2012-04-12 10:51:47 +010028// Helper.
29
30function TestWithProxies(test, x, y, z) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 test(function(h){ return new Proxy({}, h) }, x, y, z)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010032}
33
34
35// Iterate over a proxy.
36
37function TestForIn(properties, handler) {
38 TestWithProxies(TestForIn2, properties, handler)
39}
40
41function TestForIn2(create, properties, handler) {
42 var p = create(handler)
43 var found = []
44 for (var x in p) found.push(x)
45 assertArrayEquals(properties, found)
46}
47
48TestForIn(["0", "a"], {
Ben Murdoch097c5b22016-05-18 11:27:45 +010049 ownKeys() { return ["0", "a"] },
50 has(target, property) { return true },
51 getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010052})
53
54TestForIn(["null", "a"], {
Ben Murdoch097c5b22016-05-18 11:27:45 +010055 ownKeys() { return this.enumerate() },
56 enumerate() { return ["null", "a"] },
57 has(target, property) { return true },
58 getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010059})
60
Ben Murdoch3ef787d2012-04-12 10:51:47 +010061
62// Iterate over an object with a proxy prototype.
63
64function TestForInDerived(properties, handler) {
65 TestWithProxies(TestForInDerived2, properties, handler)
66}
67
68function TestForInDerived2(create, properties, handler) {
69 var p = create(handler)
70 var o = Object.create(p)
71 o.z = 0
72 var found = []
73 for (var x in o) found.push(x)
74 assertArrayEquals(["z"].concat(properties), found)
75
76 var oo = Object.create(o)
77 oo.y = 0
78 var found = []
79 for (var x in oo) found.push(x)
80 assertArrayEquals(["y", "z"].concat(properties), found)
81}
82
83TestForInDerived(["0", "a"], {
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 ownKeys: function() { return ["0", "a"] },
85 has: function(t, k) { return k == "0" || k == "a" },
86 getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010087})
88
89TestForInDerived(["null", "a"], {
Ben Murdoch097c5b22016-05-18 11:27:45 +010090 ownKeys: function() { return this.enumerate() },
91 enumerate: function() { return ["null", "a"] },
92 has: function(t, k) { return k == "null" || k == "a" },
93 getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010094})
95
96
97
Ben Murdoch097c5b22016-05-18 11:27:45 +010098// Throw exception in ownKeys trap.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010099
100function TestForInThrow(handler) {
101 TestWithProxies(TestForInThrow2, handler)
102}
103
104function TestForInThrow2(create, handler) {
105 var p = create(handler)
106 var o = Object.create(p)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 assertThrowsEquals(function(){ for (var x in p) {} }, "myexn")
108 assertThrowsEquals(function(){ for (var x in o) {} }, "myexn")
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100109}
110
111TestForInThrow({
Ben Murdoch097c5b22016-05-18 11:27:45 +0100112 ownKeys: function() { throw "myexn" }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100113})
114
115TestForInThrow({
Ben Murdoch097c5b22016-05-18 11:27:45 +0100116 ownKeys: function() { return this.enumerate() },
117 enumerate: function() { throw "myexn" }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100118})
119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120TestForInThrow(new Proxy({}, {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100121 get: function(pr, pk) {
122 return function() { throw "myexn" }
123 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124}));
125
Ben Murdochda12d292016-06-02 14:46:10 +0100126
127function keys(object) {
128 var keys = [];
129 for (var k in object) {
130 keys.push(k);
131 }
132 return keys;
133}
134
135(function testKeysProxyOnProtoEmpty() {
136 var p = new Proxy({}, {
137 ownKeys() { return []; },
138 });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 var o = [0];
140 o.__proto__ = p;
Ben Murdochda12d292016-06-02 14:46:10 +0100141 assertEquals(["0"], keys(o));
142
143 delete o[0];
144 assertEquals([], keys(o));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145})();
146
Ben Murdochda12d292016-06-02 14:46:10 +0100147(function testKeysProxyOnProto() {
148 var handler = {ownKeys() { return ["0"]; }};
149 var proxy = new Proxy({}, handler);
150 var object = [0];
151 object.__proto__ = proxy;
152 assertEquals(["0"], keys(object));
153
Ben Murdoch61f157c2016-09-16 13:49:30 +0100154 // The Proxy doesn't set its ownKeys enumerable.
Ben Murdochda12d292016-06-02 14:46:10 +0100155 delete object[0];
156 assertEquals([], keys(object));
157
158 // The [[Has]] trap has no influence on which are enumerable properties are
159 // shown in for-in.
160 handler.has = function() { return true };
161 assertEquals([], keys(object));
162
163 handler.getOwnPropertyDescriptor = function() {
164 return {enumerable: true, configurable: true}
165 }
166 assertEquals(["0"], keys(object));
167})();
168
169(function testKeysProxyProto() {
170 var target = {t1:true, t2:true};
171 var handler = {};
172 var proxy = new Proxy(target, handler);
173
174 assertEquals(["t1", "t2"], keys(proxy));
175
176 target.__proto__ = {p1:true, p2:true};
177 assertEquals(["t1", "t2", "p1", "p2"], keys(proxy));
178
179 handler.getPrototypeOf = function(target) {
180 return {p3:true, p4:true};
181 };
182 // for-in walks the prototype chain for the [[Has]] / Enumerable check.
183 assertEquals(["t1", "t2", "p3", "p4"], keys(proxy));
184
185 // [[Has]] is not used in for-in.
186 handler.has = function() { return false };
187 assertEquals(["t1", "t2", "p3", "p4"], keys(proxy));
188
189 // Proxy intercepts enumerability check.
190 handler.getOwnPropertyDescriptor = function() {
191 return {enumerable: false, configurable: true}
192 }
193 assertEquals([], keys(proxy));
194
195 handler.getOwnPropertyDescriptor = function() {
196 return {enumerable: true, configurable: true}
197 }
198 assertEquals(["t1", "t2", "p3", "p4"], keys(proxy));
199
200 handler.getOwnPropertyDescriptor = function(target, key) {
201 return {
202 enumerable: key in target,
203 configurable: true
204 }
205 }
206 assertEquals(["t1", "t2"], keys(proxy));
207
208 handler.getPrototypeOf = function() { throw "error" };
209 assertThrowsEquals(() => {keys(proxy)}, "error");
210})();
211
Ben Murdochc5610432016-08-08 18:44:38 +0100212(function testNestedProxy() {
213 var handler = {
214 ownKeys() {
215 return ['c'];
216 },
217 getOwnPropertyDescriptor() { return {configurable: true, enumerable: true } }
218 }
219 var proxy = new Proxy({}, handler);
220 var proxy2 = new Proxy(proxy, {});
221 assertEquals(['c'], keys(proxy));
222 assertEquals(['c'], keys(proxy2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223})();