OLD | NEW |
| (Empty) |
1 // Copyright 2014 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-unscopables | |
6 // Flags: --harmony-collections | |
7 | |
8 var global = this; | |
9 var globalProto = Object.getPrototypeOf(global); | |
10 | |
11 // Number of objects being tested. There is an assert ensuring this is correct. | |
12 var objectCount = 21; | |
13 | |
14 | |
15 function runTest(f) { | |
16 function restore(object, oldProto) { | |
17 delete object[Symbol.unscopables]; | |
18 delete object.x; | |
19 delete object.x_; | |
20 delete object.y; | |
21 delete object.z; | |
22 Object.setPrototypeOf(object, oldProto); | |
23 } | |
24 | |
25 function getObject(i) { | |
26 var objects = [ | |
27 {}, | |
28 [], | |
29 function() {}, | |
30 function() { | |
31 return arguments; | |
32 }(), | |
33 function() { | |
34 'use strict'; | |
35 return arguments; | |
36 }(), | |
37 Object(1), | |
38 Object(true), | |
39 Object('bla'), | |
40 new Date, | |
41 new RegExp, | |
42 new Set, | |
43 new Map, | |
44 new WeakMap, | |
45 new WeakSet, | |
46 new ArrayBuffer(10), | |
47 new Int32Array(5), | |
48 Object, | |
49 Function, | |
50 Date, | |
51 RegExp, | |
52 global | |
53 ]; | |
54 | |
55 assertEquals(objectCount, objects.length); | |
56 return objects[i]; | |
57 } | |
58 | |
59 // Tests depends on this not being there to start with. | |
60 delete Array.prototype[Symbol.unscopables]; | |
61 | |
62 if (f.length === 1) { | |
63 for (var i = 0; i < objectCount; i++) { | |
64 var object = getObject(i); | |
65 var oldObjectProto = Object.getPrototypeOf(object); | |
66 f(object); | |
67 restore(object, oldObjectProto); | |
68 } | |
69 } else { | |
70 for (var i = 0; i < objectCount; i++) { | |
71 for (var j = 0; j < objectCount; j++) { | |
72 var object = getObject(i); | |
73 var proto = getObject(j); | |
74 if (object === proto) { | |
75 continue; | |
76 } | |
77 var oldObjectProto = Object.getPrototypeOf(object); | |
78 var oldProtoProto = Object.getPrototypeOf(proto); | |
79 f(object, proto); | |
80 restore(object, oldObjectProto); | |
81 restore(proto, oldProtoProto); | |
82 } | |
83 } | |
84 } | |
85 } | |
86 | |
87 // Test array first, since other tests are changing | |
88 // Array.prototype[Symbol.unscopables]. | |
89 function TestArrayPrototypeUnscopables() { | |
90 var descr = Object.getOwnPropertyDescriptor(Array.prototype, | |
91 Symbol.unscopables); | |
92 assertFalse(descr.enumerable); | |
93 assertFalse(descr.writable); | |
94 assertTrue(descr.configurable); | |
95 assertEquals(null, Object.getPrototypeOf(descr.value)); | |
96 | |
97 var copyWithin = 'local copyWithin'; | |
98 var entries = 'local entries'; | |
99 var fill = 'local fill'; | |
100 var find = 'local find'; | |
101 var findIndex = 'local findIndex'; | |
102 var keys = 'local keys'; | |
103 var values = 'local values'; | |
104 | |
105 var array = []; | |
106 array.toString = 42; | |
107 | |
108 with (array) { | |
109 assertEquals('local copyWithin', copyWithin); | |
110 assertEquals('local entries', entries); | |
111 assertEquals('local fill', fill); | |
112 assertEquals('local find', find); | |
113 assertEquals('local findIndex', findIndex); | |
114 assertEquals('local keys', keys); | |
115 assertEquals('local values', values); | |
116 assertEquals(42, toString); | |
117 } | |
118 } | |
119 TestArrayPrototypeUnscopables(); | |
120 | |
121 | |
122 | |
123 function TestBasics(object) { | |
124 var x = 1; | |
125 var y = 2; | |
126 var z = 3; | |
127 object.x = 4; | |
128 object.y = 5; | |
129 | |
130 with (object) { | |
131 assertEquals(4, x); | |
132 assertEquals(5, y); | |
133 assertEquals(3, z); | |
134 } | |
135 | |
136 object[Symbol.unscopables] = {x: true}; | |
137 with (object) { | |
138 assertEquals(1, x); | |
139 assertEquals(5, y); | |
140 assertEquals(3, z); | |
141 } | |
142 | |
143 object[Symbol.unscopables] = {x: 0, y: true}; | |
144 with (object) { | |
145 assertEquals(1, x); | |
146 assertEquals(2, y); | |
147 assertEquals(3, z); | |
148 } | |
149 } | |
150 runTest(TestBasics); | |
151 | |
152 | |
153 function TestUnscopableChain(object) { | |
154 var x = 1; | |
155 object.x = 2; | |
156 | |
157 with (object) { | |
158 assertEquals(2, x); | |
159 } | |
160 | |
161 object[Symbol.unscopables] = { | |
162 __proto__: {x: true} | |
163 }; | |
164 with (object) { | |
165 assertEquals(1, x); | |
166 } | |
167 } | |
168 runTest(TestUnscopableChain); | |
169 | |
170 | |
171 function TestBasicsSet(object) { | |
172 var x = 1; | |
173 object.x = 2; | |
174 | |
175 with (object) { | |
176 assertEquals(2, x); | |
177 } | |
178 | |
179 object[Symbol.unscopables] = {x: true}; | |
180 with (object) { | |
181 assertEquals(1, x); | |
182 x = 3; | |
183 assertEquals(3, x); | |
184 } | |
185 | |
186 assertEquals(3, x); | |
187 assertEquals(2, object.x); | |
188 } | |
189 runTest(TestBasicsSet); | |
190 | |
191 | |
192 function TestOnProto(object, proto) { | |
193 var x = 1; | |
194 var y = 2; | |
195 var z = 3; | |
196 proto.x = 4; | |
197 | |
198 Object.setPrototypeOf(object, proto); | |
199 object.y = 5; | |
200 | |
201 with (object) { | |
202 assertEquals(4, x); | |
203 assertEquals(5, y); | |
204 assertEquals(3, z); | |
205 } | |
206 | |
207 proto[Symbol.unscopables] = {x: true}; | |
208 with (object) { | |
209 assertEquals(1, x); | |
210 assertEquals(5, y); | |
211 assertEquals(3, z); | |
212 } | |
213 | |
214 object[Symbol.unscopables] = {y: true}; | |
215 with (object) { | |
216 assertEquals(4, x); | |
217 assertEquals(2, y); | |
218 assertEquals(3, z); | |
219 } | |
220 | |
221 proto[Symbol.unscopables] = {y: true}; | |
222 object[Symbol.unscopables] = {x: true}; | |
223 with (object) { | |
224 assertEquals(1, x); | |
225 assertEquals(5, y); | |
226 assertEquals(3, z); | |
227 } | |
228 } | |
229 runTest(TestOnProto); | |
230 | |
231 | |
232 function TestSetBlockedOnProto(object, proto) { | |
233 var x = 1; | |
234 object.x = 2; | |
235 | |
236 with (object) { | |
237 assertEquals(2, x); | |
238 } | |
239 | |
240 Object.setPrototypeOf(object, proto); | |
241 proto[Symbol.unscopables] = {x: true}; | |
242 with (object) { | |
243 assertEquals(1, x); | |
244 x = 3; | |
245 assertEquals(3, x); | |
246 } | |
247 | |
248 assertEquals(3, x); | |
249 assertEquals(2, object.x); | |
250 } | |
251 runTest(TestSetBlockedOnProto); | |
252 | |
253 | |
254 function TestNonObject(object) { | |
255 var x = 1; | |
256 var y = 2; | |
257 object.x = 3; | |
258 object.y = 4; | |
259 | |
260 object[Symbol.unscopables] = 'xy'; | |
261 with (object) { | |
262 assertEquals(3, x); | |
263 assertEquals(4, y); | |
264 } | |
265 | |
266 object[Symbol.unscopables] = null; | |
267 with (object) { | |
268 assertEquals(3, x); | |
269 assertEquals(4, y); | |
270 } | |
271 } | |
272 runTest(TestNonObject); | |
273 | |
274 | |
275 function TestChangeDuringWith(object) { | |
276 var x = 1; | |
277 var y = 2; | |
278 object.x = 3; | |
279 object.y = 4; | |
280 | |
281 with (object) { | |
282 assertEquals(3, x); | |
283 assertEquals(4, y); | |
284 object[Symbol.unscopables] = {x: true}; | |
285 assertEquals(1, x); | |
286 assertEquals(4, y); | |
287 } | |
288 } | |
289 runTest(TestChangeDuringWith); | |
290 | |
291 | |
292 function TestChangeDuringWithWithPossibleOptimization(object) { | |
293 var x = 1; | |
294 object.x = 2; | |
295 with (object) { | |
296 for (var i = 0; i < 1000; i++) { | |
297 if (i === 500) object[Symbol.unscopables] = {x: true}; | |
298 assertEquals(i < 500 ? 2: 1, x); | |
299 } | |
300 } | |
301 } | |
302 TestChangeDuringWithWithPossibleOptimization({}); | |
303 | |
304 | |
305 function TestChangeDuringWithWithPossibleOptimization2(object) { | |
306 var x = 1; | |
307 object.x = 2; | |
308 object[Symbol.unscopables] = {x: true}; | |
309 with (object) { | |
310 for (var i = 0; i < 1000; i++) { | |
311 if (i === 500) delete object[Symbol.unscopables]; | |
312 assertEquals(i < 500 ? 1 : 2, x); | |
313 } | |
314 } | |
315 } | |
316 TestChangeDuringWithWithPossibleOptimization2({}); | |
317 | |
318 | |
319 function TestChangeDuringWithWithPossibleOptimization3(object) { | |
320 var x = 1; | |
321 object.x = 2; | |
322 object[Symbol.unscopables] = {}; | |
323 with (object) { | |
324 for (var i = 0; i < 1000; i++) { | |
325 if (i === 500) object[Symbol.unscopables].x = true; | |
326 assertEquals(i < 500 ? 2 : 1, x); | |
327 } | |
328 } | |
329 } | |
330 TestChangeDuringWithWithPossibleOptimization3({}); | |
331 | |
332 | |
333 function TestChangeDuringWithWithPossibleOptimization4(object) { | |
334 var x = 1; | |
335 object.x = 2; | |
336 object[Symbol.unscopables] = {x: true}; | |
337 with (object) { | |
338 for (var i = 0; i < 1000; i++) { | |
339 if (i === 500) delete object[Symbol.unscopables].x; | |
340 assertEquals(i < 500 ? 1 : 2, x); | |
341 } | |
342 } | |
343 } | |
344 TestChangeDuringWithWithPossibleOptimization4({}); | |
345 | |
346 | |
347 function TestAccessorReceiver(object, proto) { | |
348 var x = 'local'; | |
349 | |
350 Object.defineProperty(proto, 'x', { | |
351 get: function() { | |
352 assertEquals(object, this); | |
353 return this.x_; | |
354 }, | |
355 configurable: true | |
356 }); | |
357 proto.x_ = 'proto'; | |
358 | |
359 Object.setPrototypeOf(object, proto); | |
360 proto.x_ = 'object'; | |
361 | |
362 with (object) { | |
363 assertEquals('object', x); | |
364 } | |
365 } | |
366 runTest(TestAccessorReceiver); | |
367 | |
368 | |
369 function TestUnscopablesGetter(object) { | |
370 // This test gets really messy when object is the global since the assert | |
371 // functions are properties on the global object and the call count gets | |
372 // completely different. | |
373 if (object === global) return; | |
374 | |
375 var x = 'local'; | |
376 object.x = 'object'; | |
377 | |
378 var callCount = 0; | |
379 Object.defineProperty(object, Symbol.unscopables, { | |
380 get: function() { | |
381 callCount++; | |
382 return {}; | |
383 }, | |
384 configurable: true | |
385 }); | |
386 with (object) { | |
387 assertEquals('object', x); | |
388 } | |
389 // Once for HasBinding | |
390 assertEquals(1, callCount); | |
391 | |
392 callCount = 0; | |
393 Object.defineProperty(object, Symbol.unscopables, { | |
394 get: function() { | |
395 callCount++; | |
396 return {x: true}; | |
397 }, | |
398 configurable: true | |
399 }); | |
400 with (object) { | |
401 assertEquals('local', x); | |
402 } | |
403 // Once for HasBinding | |
404 assertEquals(1, callCount); | |
405 | |
406 callCount = 0; | |
407 Object.defineProperty(object, Symbol.unscopables, { | |
408 get: function() { | |
409 callCount++; | |
410 return callCount == 1 ? {} : {x: true}; | |
411 }, | |
412 configurable: true | |
413 }); | |
414 with (object) { | |
415 x = 1; | |
416 } | |
417 // Once for HasBinding | |
418 assertEquals(1, callCount); | |
419 assertEquals(1, object.x); | |
420 assertEquals('local', x); | |
421 with (object) { | |
422 x = 2; | |
423 } | |
424 // One more HasBinding. | |
425 assertEquals(2, callCount); | |
426 assertEquals(1, object.x); | |
427 assertEquals(2, x); | |
428 } | |
429 runTest(TestUnscopablesGetter); | |
430 | |
431 | |
432 var global = this; | |
433 function TestUnscopablesGetter2() { | |
434 var x = 'local'; | |
435 | |
436 var globalProto = Object.getPrototypeOf(global); | |
437 var protos = [{}, [], function() {}, global]; | |
438 var objects = [{}, [], function() {}]; | |
439 | |
440 protos.forEach(function(proto) { | |
441 objects.forEach(function(object) { | |
442 Object.defineProperty(proto, 'x', { | |
443 get: function() { | |
444 assertEquals(object, this); | |
445 return 'proto'; | |
446 }, | |
447 configurable: true | |
448 }); | |
449 | |
450 object.__proto__ = proto; | |
451 Object.defineProperty(object, 'x', { | |
452 get: function() { | |
453 assertEquals(object, this); | |
454 return 'object'; | |
455 }, | |
456 configurable: true | |
457 }); | |
458 | |
459 with (object) { | |
460 assertEquals('object', x); | |
461 } | |
462 | |
463 object[Symbol.unscopables] = {x: true}; | |
464 with (object) { | |
465 assertEquals('local', x); | |
466 } | |
467 | |
468 delete proto[Symbol.unscopables]; | |
469 delete object[Symbol.unscopables]; | |
470 }); | |
471 }); | |
472 | |
473 delete global.x; | |
474 Object.setPrototypeOf(global, globalProto); | |
475 } | |
476 TestUnscopablesGetter2(); | |
477 | |
478 | |
479 function TestSetterOnBlacklisted(object, proto) { | |
480 var x = 'local'; | |
481 Object.defineProperty(proto, 'x', { | |
482 set: function(x) { | |
483 assertUnreachable(); | |
484 }, | |
485 get: function() { | |
486 return 'proto'; | |
487 }, | |
488 configurable: true | |
489 }); | |
490 Object.setPrototypeOf(object, proto); | |
491 Object.defineProperty(object, 'x', { | |
492 get: function() { | |
493 return this.x_; | |
494 }, | |
495 set: function(x) { | |
496 this.x_ = x; | |
497 }, | |
498 configurable: true | |
499 }); | |
500 object.x_ = 1; | |
501 | |
502 with (object) { | |
503 x = 2; | |
504 assertEquals(2, x); | |
505 } | |
506 | |
507 assertEquals(2, object.x); | |
508 | |
509 object[Symbol.unscopables] = {x: true}; | |
510 | |
511 with (object) { | |
512 x = 3; | |
513 assertEquals(3, x); | |
514 } | |
515 | |
516 assertEquals(2, object.x); | |
517 } | |
518 runTest(TestSetterOnBlacklisted); | |
519 | |
520 | |
521 function TestObjectsAsUnscopables(object, unscopables) { | |
522 var x = 1; | |
523 object.x = 2; | |
524 | |
525 with (object) { | |
526 assertEquals(2, x); | |
527 object[Symbol.unscopables] = unscopables; | |
528 assertEquals(2, x); | |
529 } | |
530 } | |
531 runTest(TestObjectsAsUnscopables); | |
532 | |
533 | |
534 function TestAccessorOnUnscopables(object) { | |
535 var x = 1; | |
536 object.x = 2; | |
537 | |
538 var unscopables = { | |
539 get x() { | |
540 assertUnreachable(); | |
541 } | |
542 }; | |
543 | |
544 with (object) { | |
545 assertEquals(2, x); | |
546 object[Symbol.unscopables] = unscopables; | |
547 assertEquals(1, x); | |
548 } | |
549 } | |
550 runTest(TestAccessorOnUnscopables); | |
551 | |
552 | |
553 function TestLengthUnscopables(object, proto) { | |
554 var length = 2; | |
555 with (object) { | |
556 assertEquals(1, length); | |
557 object[Symbol.unscopables] = {length: true}; | |
558 assertEquals(2, length); | |
559 delete object[Symbol.unscopables]; | |
560 assertEquals(1, length); | |
561 } | |
562 } | |
563 TestLengthUnscopables([1], Array.prototype); | |
564 TestLengthUnscopables(function(x) {}, Function.prototype); | |
565 TestLengthUnscopables(new String('x'), String.prototype); | |
566 | |
567 | |
568 function TestFunctionNameUnscopables(object) { | |
569 var name = 'local'; | |
570 with (object) { | |
571 assertEquals('f', name); | |
572 object[Symbol.unscopables] = {name: true}; | |
573 assertEquals('local', name); | |
574 delete object[Symbol.unscopables]; | |
575 assertEquals('f', name); | |
576 } | |
577 } | |
578 TestFunctionNameUnscopables(function f() {}); | |
579 | |
580 | |
581 function TestFunctionPrototypeUnscopables() { | |
582 var prototype = 'local'; | |
583 var f = function() {}; | |
584 var g = function() {}; | |
585 Object.setPrototypeOf(f, g); | |
586 var fp = f.prototype; | |
587 var gp = g.prototype; | |
588 with (f) { | |
589 assertEquals(fp, prototype); | |
590 f[Symbol.unscopables] = {prototype: true}; | |
591 assertEquals('local', prototype); | |
592 delete f[Symbol.unscopables]; | |
593 assertEquals(fp, prototype); | |
594 } | |
595 } | |
596 TestFunctionPrototypeUnscopables(function() {}); | |
597 | |
598 | |
599 function TestFunctionArgumentsUnscopables() { | |
600 var func = function() { | |
601 var arguments = 'local'; | |
602 var args = func.arguments; | |
603 with (func) { | |
604 assertEquals(args, arguments); | |
605 func[Symbol.unscopables] = {arguments: true}; | |
606 assertEquals('local', arguments); | |
607 delete func[Symbol.unscopables]; | |
608 assertEquals(args, arguments); | |
609 } | |
610 } | |
611 func(1); | |
612 } | |
613 TestFunctionArgumentsUnscopables(); | |
614 | |
615 | |
616 function TestArgumentsLengthUnscopables() { | |
617 var func = function() { | |
618 var length = 'local'; | |
619 with (arguments) { | |
620 assertEquals(1, length); | |
621 arguments[Symbol.unscopables] = {length: true}; | |
622 assertEquals('local', length); | |
623 } | |
624 } | |
625 func(1); | |
626 } | |
627 TestArgumentsLengthUnscopables(); | |
628 | |
629 | |
630 function TestFunctionCallerUnscopables() { | |
631 var func = function() { | |
632 var caller = 'local'; | |
633 with (func) { | |
634 assertEquals(TestFunctionCallerUnscopables, caller); | |
635 func[Symbol.unscopables] = {caller: true}; | |
636 assertEquals('local', caller); | |
637 delete func[Symbol.unscopables]; | |
638 assertEquals(TestFunctionCallerUnscopables, caller); | |
639 } | |
640 } | |
641 func(1); | |
642 } | |
643 TestFunctionCallerUnscopables(); | |
644 | |
645 | |
646 function TestGetUnscopablesGetterThrows() { | |
647 var object = { | |
648 get x() { | |
649 assertUnreachable(); | |
650 } | |
651 }; | |
652 function CustomError() {} | |
653 Object.defineProperty(object, Symbol.unscopables, { | |
654 get: function() { | |
655 throw new CustomError(); | |
656 } | |
657 }); | |
658 assertThrows(function() { | |
659 with (object) { | |
660 x; | |
661 } | |
662 }, CustomError); | |
663 } | |
664 TestGetUnscopablesGetterThrows(); | |
OLD | NEW |