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