OLD | NEW |
| (Empty) |
1 // Copyright 2015 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Flags: --harmony-proxies --harmony-reflect | |
6 | |
7 | |
8 function sloppyDefaultSet(o, p, v) { return o[p] = v } | |
9 function sloppyReflectSet(o, p, v) { return Reflect.set(o, p, v) } | |
10 function strictDefaultSet(o, p, v) { "use strict"; return o[p] = v } | |
11 function strictReflectSet(o, p, v) { "use strict"; return Reflect.set(o, p, v) } | |
12 | |
13 sloppyDefaultSet.shouldThrow = false; | |
14 sloppyReflectSet.shouldThrow = false; | |
15 strictDefaultSet.shouldThrow = true; | |
16 strictReflectSet.shouldThrow = false; | |
17 | |
18 sloppyDefaultSet.returnsBool = false; | |
19 sloppyReflectSet.returnsBool = true; | |
20 strictDefaultSet.returnsBool = false; | |
21 strictReflectSet.returnsBool = true; | |
22 | |
23 | |
24 function assertTrueIf(flag, x) { if (flag) assertTrue(x) } | |
25 function assertFalseIf(flag, x) { if (flag) assertFalse(x) } | |
26 function assertSetFails(mySet, o, p, v) { | |
27 if (mySet.shouldThrow) { | |
28 assertThrows(() => mySet(o, p, v), TypeError); | |
29 } else { | |
30 assertFalseIf(mySet.returnsBool, mySet(o, p, v)); | |
31 } | |
32 } | |
33 | |
34 | |
35 function dataDescriptor(x) { | |
36 return {value: x, writable: true, enumerable: true, configurable: true}; | |
37 } | |
38 | |
39 | |
40 function toKey(x) { | |
41 if (typeof x === "symbol") return x; | |
42 return String(x); | |
43 } | |
44 | |
45 | |
46 var properties = | |
47 ["bla", "0", 1, Symbol(), {[Symbol.toPrimitive]() {return "a"}}]; | |
48 | |
49 | |
50 function TestForwarding(handler, mySet) { | |
51 assertTrue(undefined == handler.set); | |
52 assertTrue(undefined == handler.getOwnPropertyDescriptor); | |
53 assertTrue(undefined == handler.defineProperty); | |
54 | |
55 var target = {}; | |
56 var proxy = new Proxy(target, handler); | |
57 | |
58 // Property does not exist on target. | |
59 for (var p of properties) { | |
60 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 42)); | |
61 assertSame(42, target[p]); | |
62 } | |
63 | |
64 // Property exists as writable data on target. | |
65 for (var p of properties) { | |
66 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); | |
67 assertSame(0, target[p]); | |
68 } | |
69 | |
70 // Property exists as non-writable data on target. | |
71 for (var p of properties) { | |
72 Object.defineProperty(target, p, | |
73 {value: 42, configurable: true, writable: false}); | |
74 assertSetFails(mySet, proxy, p, 42); | |
75 assertSetFails(mySet, proxy, p, 0); | |
76 assertEquals(42, target[p]); | |
77 } | |
78 }; | |
79 | |
80 (function () { | |
81 // No trap. | |
82 var handler = {}; | |
83 TestForwarding(handler, sloppyDefaultSet); | |
84 TestForwarding(handler, sloppyReflectSet); | |
85 TestForwarding(handler, strictDefaultSet); | |
86 TestForwarding(handler, strictReflectSet); | |
87 })(); | |
88 | |
89 (function () { | |
90 // "Undefined" trap. | |
91 var handler = { set: null }; | |
92 TestForwarding(handler, sloppyDefaultSet); | |
93 TestForwarding(handler, sloppyReflectSet); | |
94 TestForwarding(handler, strictDefaultSet); | |
95 TestForwarding(handler, strictReflectSet); | |
96 })(); | |
97 | |
98 | |
99 function TestForwarding2(mySet) { | |
100 // Check that setting on a proxy without "set" trap correctly triggers its | |
101 // "getOwnProperty" trap and its "defineProperty" trap. | |
102 | |
103 var target = {}; | |
104 var handler = {}; | |
105 var observations = []; | |
106 var proxy = new Proxy(target, handler); | |
107 | |
108 handler.getOwnPropertyDescriptor = function() { | |
109 observations.push(arguments); | |
110 return Reflect.getOwnPropertyDescriptor(...arguments); | |
111 } | |
112 | |
113 handler.defineProperty = function() { | |
114 observations.push(arguments); | |
115 return Reflect.defineProperty(...arguments); | |
116 } | |
117 | |
118 for (var p of properties) { | |
119 mySet(proxy, p, 42); | |
120 assertEquals(2, observations.length) | |
121 assertArrayEquals([target, toKey(p)], observations[0]); | |
122 assertSame(target, observations[0][0]); | |
123 assertArrayEquals([target, toKey(p), dataDescriptor(42)], observations[1]); | |
124 assertSame(target, observations[1][0]); | |
125 observations = []; | |
126 | |
127 mySet(proxy, p, 42); | |
128 assertEquals(2, observations.length) | |
129 assertArrayEquals([target, toKey(p)], observations[0]); | |
130 assertSame(target, observations[0][0]); | |
131 assertArrayEquals([target, toKey(p), {value: 42}], observations[1]); | |
132 assertSame(target, observations[1][0]); | |
133 observations = []; | |
134 } | |
135 } | |
136 | |
137 TestForwarding2(sloppyDefaultSet); | |
138 TestForwarding2(sloppyReflectSet); | |
139 TestForwarding2(strictDefaultSet); | |
140 TestForwarding2(strictReflectSet); | |
141 | |
142 | |
143 function TestInvalidTrap(proxy, mySet) { | |
144 for (var p of properties) { | |
145 assertThrows(() => mySet(proxy, p, 42), TypeError); | |
146 } | |
147 } | |
148 | |
149 (function () { | |
150 var target = {}; | |
151 var handler = { set: true }; | |
152 var proxy = new Proxy(target, handler); | |
153 | |
154 TestInvalidTrap(proxy, sloppyDefaultSet); | |
155 TestInvalidTrap(proxy, sloppyReflectSet); | |
156 TestInvalidTrap(proxy, strictDefaultSet); | |
157 TestInvalidTrap(proxy, strictReflectSet); | |
158 })(); | |
159 | |
160 | |
161 function TestTrappingFalsish(mySet) { | |
162 var target = {}; | |
163 var handler = { set() {return ""} }; | |
164 var proxy = new Proxy(target, handler); | |
165 | |
166 for (var p of properties) { | |
167 assertSetFails(mySet, proxy, p, 42); | |
168 } | |
169 } | |
170 | |
171 TestTrappingFalsish(sloppyDefaultSet); | |
172 TestTrappingFalsish(sloppyReflectSet); | |
173 TestTrappingFalsish(strictDefaultSet); | |
174 TestTrappingFalsish(strictReflectSet); | |
175 | |
176 | |
177 function TestTrappingTrueish(mySet) { | |
178 var target = {}; | |
179 var handler = { set() {return 42} }; | |
180 var proxy = new Proxy(target, handler); | |
181 | |
182 // Trap returns trueish and property does not exist in target. | |
183 for (var p of properties) { | |
184 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); | |
185 } | |
186 | |
187 // Trap returns trueish and target property is configurable or writable data. | |
188 for (var p of properties) { | |
189 Object.defineProperty(target, p, {configurable: true, writable: true}); | |
190 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); | |
191 Object.defineProperty(target, p, {configurable: true, writable: false}); | |
192 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); | |
193 Object.defineProperty(target, p, {configurable: false, writable: true}); | |
194 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); | |
195 } | |
196 } | |
197 | |
198 TestTrappingTrueish(sloppyDefaultSet); | |
199 TestTrappingTrueish(sloppyReflectSet); | |
200 TestTrappingTrueish(strictDefaultSet); | |
201 TestTrappingTrueish(strictReflectSet); | |
202 | |
203 | |
204 function TestTrappingTrueish2(mySet) { | |
205 var target = {}; | |
206 var handler = { set() {return 42} }; | |
207 var proxy = new Proxy(target, handler); | |
208 | |
209 // Trap returns trueish but target property is frozen data. | |
210 for (var p of properties) { | |
211 Object.defineProperty(target, p, { | |
212 configurable: false, writable: false, value: 0 | |
213 }); | |
214 assertThrows(() => mySet(proxy, p, 666), TypeError); // New value. | |
215 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); // Old value. | |
216 } | |
217 }; | |
218 | |
219 TestTrappingTrueish2(sloppyDefaultSet); | |
220 TestTrappingTrueish2(sloppyReflectSet); | |
221 TestTrappingTrueish2(strictDefaultSet); | |
222 TestTrappingTrueish2(strictReflectSet); | |
223 | |
224 | |
225 function TestTrappingTrueish3(mySet) { | |
226 var target = {}; | |
227 var handler = { set() {return 42} }; | |
228 var proxy = new Proxy(target, handler); | |
229 | |
230 // Trap returns trueish and target property is configurable accessor. | |
231 for (var p of properties) { | |
232 Object.defineProperty(target, p, { configurable: true, set: undefined }); | |
233 assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); | |
234 } | |
235 | |
236 // Trap returns trueish and target property is non-configurable accessor. | |
237 for (var p of properties) { | |
238 Object.defineProperty(target, p, { configurable: false, set: undefined }); | |
239 assertThrows(() => mySet(proxy, p, 0)); | |
240 } | |
241 }; | |
242 | |
243 TestTrappingTrueish3(sloppyDefaultSet); | |
244 TestTrappingTrueish3(sloppyReflectSet); | |
245 TestTrappingTrueish3(strictDefaultSet); | |
246 TestTrappingTrueish3(strictReflectSet); | |
247 | |
248 | |
249 function TestTrapReceiverArgument(mySet) { | |
250 var target = {}; | |
251 var handler = {}; | |
252 var observations = []; | |
253 var proxy = new Proxy(target, handler); | |
254 var object = Object.create(proxy); | |
255 | |
256 handler.set = function() { | |
257 observations.push(arguments); | |
258 return Reflect.set(...arguments); | |
259 } | |
260 | |
261 for (var p of properties) { | |
262 mySet(object, p, 42); | |
263 assertEquals(1, observations.length) | |
264 assertArrayEquals([target, toKey(p), 42, object], observations[0]); | |
265 assertSame(target, observations[0][0]); | |
266 assertSame(object, observations[0][3]); | |
267 observations = []; | |
268 } | |
269 }; | |
270 | |
271 TestTrapReceiverArgument(sloppyDefaultSet); | |
272 TestTrapReceiverArgument(sloppyReflectSet); | |
273 TestTrapReceiverArgument(strictDefaultSet); | |
274 TestTrapReceiverArgument(strictReflectSet); | |
275 | |
276 | |
277 (function TestTrapReceiverArgument2() { | |
278 // Check that non-object receiver is passed through as well. | |
279 | |
280 var target = {}; | |
281 var handler = {}; | |
282 var observations = []; | |
283 var proxy = new Proxy(target, handler); | |
284 | |
285 handler.set = function() { | |
286 observations.push(arguments); | |
287 return Reflect.set(...arguments); | |
288 } | |
289 | |
290 for (var p of properties) { | |
291 for (var receiver of [null, undefined, 1]) { | |
292 Reflect.set(proxy, p, 42, receiver); | |
293 assertEquals(1, observations.length) | |
294 assertArrayEquals([target, toKey(p), 42, receiver], observations[0]); | |
295 assertSame(target, observations[0][0]); | |
296 assertSame(receiver, observations[0][3]); | |
297 observations = []; | |
298 } | |
299 } | |
300 | |
301 var object = Object.create(proxy); | |
302 for (var p of properties) { | |
303 for (var receiver of [null, undefined, 1]) { | |
304 Reflect.set(object, p, 42, receiver); | |
305 assertEquals(1, observations.length); | |
306 assertArrayEquals([target, toKey(p), 42, receiver], observations[0]); | |
307 assertSame(target, observations[0][0]); | |
308 assertSame(receiver, observations[0][3]); | |
309 observations = []; | |
310 } | |
311 } | |
312 })(); | |
OLD | NEW |