blob: 03612bec533a6c51a0ffd6340ec08ef295d28e12 [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
133 object[Symbol.unscopables] = {x: true};
134 with (object) {
135 assertEquals(1, x);
136 assertEquals(5, y);
137 assertEquals(3, z);
138 }
139
140 object[Symbol.unscopables] = {x: 0, y: true};
141 with (object) {
142 assertEquals(1, x);
143 assertEquals(2, y);
144 assertEquals(3, z);
145 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400146
147 object[Symbol.unscopables] = {x: 0, y: undefined};
148 with (object) {
149 assertEquals(1, x);
150 assertEquals(5, y);
151 assertEquals(3, z);
152 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153}
154runTest(TestBasics);
155
156
157function TestUnscopableChain(object) {
158 var x = 1;
159 object.x = 2;
160
161 with (object) {
162 assertEquals(2, x);
163 }
164
165 object[Symbol.unscopables] = {
166 __proto__: {x: true}
167 };
168 with (object) {
169 assertEquals(1, x);
170 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400171
172 object[Symbol.unscopables] = {
173 __proto__: {x: undefined}
174 };
175 with (object) {
176 assertEquals(2, x);
177 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178}
179runTest(TestUnscopableChain);
180
181
182function TestBasicsSet(object) {
183 var x = 1;
184 object.x = 2;
185
186 with (object) {
187 assertEquals(2, x);
188 }
189
190 object[Symbol.unscopables] = {x: true};
191 with (object) {
192 assertEquals(1, x);
193 x = 3;
194 assertEquals(3, x);
195 }
196
197 assertEquals(3, x);
198 assertEquals(2, object.x);
199}
200runTest(TestBasicsSet);
201
202
203function TestOnProto(object, proto) {
204 var x = 1;
205 var y = 2;
206 var z = 3;
207 proto.x = 4;
208
209 Object.setPrototypeOf(object, proto);
210 object.y = 5;
211
212 with (object) {
213 assertEquals(4, x);
214 assertEquals(5, y);
215 assertEquals(3, z);
216 }
217
218 proto[Symbol.unscopables] = {x: true};
219 with (object) {
220 assertEquals(1, x);
221 assertEquals(5, y);
222 assertEquals(3, z);
223 }
224
225 object[Symbol.unscopables] = {y: true};
226 with (object) {
227 assertEquals(4, x);
228 assertEquals(2, y);
229 assertEquals(3, z);
230 }
231
232 proto[Symbol.unscopables] = {y: true};
233 object[Symbol.unscopables] = {x: true};
234 with (object) {
235 assertEquals(1, x);
236 assertEquals(5, y);
237 assertEquals(3, z);
238 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239
240 proto[Symbol.unscopables] = {y: true};
241 object[Symbol.unscopables] = {x: true, y: undefined};
242 with (object) {
243 assertEquals(1, x);
244 assertEquals(5, y);
245 assertEquals(3, z);
246 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247}
248runTest(TestOnProto);
249
250
251function TestSetBlockedOnProto(object, proto) {
252 var x = 1;
253 object.x = 2;
254
255 with (object) {
256 assertEquals(2, x);
257 }
258
259 Object.setPrototypeOf(object, proto);
260 proto[Symbol.unscopables] = {x: true};
261 with (object) {
262 assertEquals(1, x);
263 x = 3;
264 assertEquals(3, x);
265 }
266
267 assertEquals(3, x);
268 assertEquals(2, object.x);
269}
270runTest(TestSetBlockedOnProto);
271
272
273function TestNonObject(object) {
274 var x = 1;
275 var y = 2;
276 object.x = 3;
277 object.y = 4;
278
279 object[Symbol.unscopables] = 'xy';
280 with (object) {
281 assertEquals(3, x);
282 assertEquals(4, y);
283 }
284
285 object[Symbol.unscopables] = null;
286 with (object) {
287 assertEquals(3, x);
288 assertEquals(4, y);
289 }
290}
291runTest(TestNonObject);
292
293
294function TestChangeDuringWith(object) {
295 var x = 1;
296 var y = 2;
297 object.x = 3;
298 object.y = 4;
299
300 with (object) {
301 assertEquals(3, x);
302 assertEquals(4, y);
303 object[Symbol.unscopables] = {x: true};
304 assertEquals(1, x);
305 assertEquals(4, y);
306 }
307}
308runTest(TestChangeDuringWith);
309
310
311function TestChangeDuringWithWithPossibleOptimization(object) {
312 var x = 1;
313 object.x = 2;
314 with (object) {
315 for (var i = 0; i < 1000; i++) {
316 if (i === 500) object[Symbol.unscopables] = {x: true};
317 assertEquals(i < 500 ? 2: 1, x);
318 }
319 }
320}
321TestChangeDuringWithWithPossibleOptimization({});
322
323
324function TestChangeDuringWithWithPossibleOptimization2(object) {
325 var x = 1;
326 object.x = 2;
327 object[Symbol.unscopables] = {x: true};
328 with (object) {
329 for (var i = 0; i < 1000; i++) {
330 if (i === 500) delete object[Symbol.unscopables];
331 assertEquals(i < 500 ? 1 : 2, x);
332 }
333 }
334}
335TestChangeDuringWithWithPossibleOptimization2({});
336
337
338function TestChangeDuringWithWithPossibleOptimization3(object) {
339 var x = 1;
340 object.x = 2;
341 object[Symbol.unscopables] = {};
342 with (object) {
343 for (var i = 0; i < 1000; i++) {
344 if (i === 500) object[Symbol.unscopables].x = true;
345 assertEquals(i < 500 ? 2 : 1, x);
346 }
347 }
348}
349TestChangeDuringWithWithPossibleOptimization3({});
350
351
352function TestChangeDuringWithWithPossibleOptimization4(object) {
353 var x = 1;
354 object.x = 2;
355 object[Symbol.unscopables] = {x: true};
356 with (object) {
357 for (var i = 0; i < 1000; i++) {
358 if (i === 500) delete object[Symbol.unscopables].x;
359 assertEquals(i < 500 ? 1 : 2, x);
360 }
361 }
362}
363TestChangeDuringWithWithPossibleOptimization4({});
364
365
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400366function TestChangeDuringWithWithPossibleOptimization4(object) {
367 var x = 1;
368 object.x = 2;
369 object[Symbol.unscopables] = {x: true};
370 with (object) {
371 for (var i = 0; i < 1000; i++) {
372 if (i === 500) object[Symbol.unscopables].x = undefined;
373 assertEquals(i < 500 ? 1 : 2, x);
374 }
375 }
376}
377TestChangeDuringWithWithPossibleOptimization4({});
378
379
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380function TestAccessorReceiver(object, proto) {
381 var x = 'local';
382
383 Object.defineProperty(proto, 'x', {
384 get: function() {
385 assertEquals(object, this);
386 return this.x_;
387 },
388 configurable: true
389 });
390 proto.x_ = 'proto';
391
392 Object.setPrototypeOf(object, proto);
393 proto.x_ = 'object';
394
395 with (object) {
396 assertEquals('object', x);
397 }
398}
399runTest(TestAccessorReceiver);
400
401
402function TestUnscopablesGetter(object) {
403 // This test gets really messy when object is the global since the assert
404 // functions are properties on the global object and the call count gets
405 // completely different.
406 if (object === global) return;
407
408 var x = 'local';
409 object.x = 'object';
410
411 var callCount = 0;
412 Object.defineProperty(object, Symbol.unscopables, {
413 get: function() {
414 callCount++;
415 return {};
416 },
417 configurable: true
418 });
419 with (object) {
420 assertEquals('object', x);
421 }
422 // Once for HasBinding
423 assertEquals(1, callCount);
424
425 callCount = 0;
426 Object.defineProperty(object, Symbol.unscopables, {
427 get: function() {
428 callCount++;
429 return {x: true};
430 },
431 configurable: true
432 });
433 with (object) {
434 assertEquals('local', x);
435 }
436 // Once for HasBinding
437 assertEquals(1, callCount);
438
439 callCount = 0;
440 Object.defineProperty(object, Symbol.unscopables, {
441 get: function() {
442 callCount++;
443 return callCount == 1 ? {} : {x: true};
444 },
445 configurable: true
446 });
447 with (object) {
448 x = 1;
449 }
450 // Once for HasBinding
451 assertEquals(1, callCount);
452 assertEquals(1, object.x);
453 assertEquals('local', x);
454 with (object) {
455 x = 2;
456 }
457 // One more HasBinding.
458 assertEquals(2, callCount);
459 assertEquals(1, object.x);
460 assertEquals(2, x);
461}
462runTest(TestUnscopablesGetter);
463
464
465var global = this;
466function TestUnscopablesGetter2() {
467 var x = 'local';
468
469 var globalProto = Object.getPrototypeOf(global);
470 var protos = [{}, [], function() {}, global];
471 var objects = [{}, [], function() {}];
472
473 protos.forEach(function(proto) {
474 objects.forEach(function(object) {
475 Object.defineProperty(proto, 'x', {
476 get: function() {
477 assertEquals(object, this);
478 return 'proto';
479 },
480 configurable: true
481 });
482
483 object.__proto__ = proto;
484 Object.defineProperty(object, 'x', {
485 get: function() {
486 assertEquals(object, this);
487 return 'object';
488 },
489 configurable: true
490 });
491
492 with (object) {
493 assertEquals('object', x);
494 }
495
496 object[Symbol.unscopables] = {x: true};
497 with (object) {
498 assertEquals('local', x);
499 }
500
501 delete proto[Symbol.unscopables];
502 delete object[Symbol.unscopables];
503 });
504 });
505
506 delete global.x;
507 Object.setPrototypeOf(global, globalProto);
508}
509TestUnscopablesGetter2();
510
511
512function TestSetterOnBlacklisted(object, proto) {
513 var x = 'local';
514 Object.defineProperty(proto, 'x', {
515 set: function(x) {
516 assertUnreachable();
517 },
518 get: function() {
519 return 'proto';
520 },
521 configurable: true
522 });
523 Object.setPrototypeOf(object, proto);
524 Object.defineProperty(object, 'x', {
525 get: function() {
526 return this.x_;
527 },
528 set: function(x) {
529 this.x_ = x;
530 },
531 configurable: true
532 });
533 object.x_ = 1;
534
535 with (object) {
536 x = 2;
537 assertEquals(2, x);
538 }
539
540 assertEquals(2, object.x);
541
542 object[Symbol.unscopables] = {x: true};
543
544 with (object) {
545 x = 3;
546 assertEquals(3, x);
547 }
548
549 assertEquals(2, object.x);
550}
551runTest(TestSetterOnBlacklisted);
552
553
554function TestObjectsAsUnscopables(object, unscopables) {
555 var x = 1;
556 object.x = 2;
557
558 with (object) {
559 assertEquals(2, x);
560 object[Symbol.unscopables] = unscopables;
561 assertEquals(2, x);
562 }
563}
564runTest(TestObjectsAsUnscopables);
565
566
567function TestAccessorOnUnscopables(object) {
568 var x = 1;
569 object.x = 2;
570
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400571 var calls = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000572 var unscopables = {
573 get x() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400574 calls++;
575 return calls === 1 ? true : undefined;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576 }
577 };
578
579 with (object) {
580 assertEquals(2, x);
581 object[Symbol.unscopables] = unscopables;
582 assertEquals(1, x);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400583 assertEquals(2, x);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000584 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400585 assertEquals(2, calls);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586}
587runTest(TestAccessorOnUnscopables);
588
589
590function TestLengthUnscopables(object, proto) {
591 var length = 2;
592 with (object) {
593 assertEquals(1, length);
594 object[Symbol.unscopables] = {length: true};
595 assertEquals(2, length);
596 delete object[Symbol.unscopables];
597 assertEquals(1, length);
598 }
599}
600TestLengthUnscopables([1], Array.prototype);
601TestLengthUnscopables(function(x) {}, Function.prototype);
602TestLengthUnscopables(new String('x'), String.prototype);
603
604
605function TestFunctionNameUnscopables(object) {
606 var name = 'local';
607 with (object) {
608 assertEquals('f', name);
609 object[Symbol.unscopables] = {name: true};
610 assertEquals('local', name);
611 delete object[Symbol.unscopables];
612 assertEquals('f', name);
613 }
614}
615TestFunctionNameUnscopables(function f() {});
616
617
618function TestFunctionPrototypeUnscopables() {
619 var prototype = 'local';
620 var f = function() {};
621 var g = function() {};
622 Object.setPrototypeOf(f, g);
623 var fp = f.prototype;
624 var gp = g.prototype;
625 with (f) {
626 assertEquals(fp, prototype);
627 f[Symbol.unscopables] = {prototype: true};
628 assertEquals('local', prototype);
629 delete f[Symbol.unscopables];
630 assertEquals(fp, prototype);
631 }
632}
633TestFunctionPrototypeUnscopables(function() {});
634
635
636function TestFunctionArgumentsUnscopables() {
637 var func = function() {
638 var arguments = 'local';
639 var args = func.arguments;
640 with (func) {
641 assertEquals(args, arguments);
642 func[Symbol.unscopables] = {arguments: true};
643 assertEquals('local', arguments);
644 delete func[Symbol.unscopables];
645 assertEquals(args, arguments);
646 }
647 }
648 func(1);
649}
650TestFunctionArgumentsUnscopables();
651
652
653function TestArgumentsLengthUnscopables() {
654 var func = function() {
655 var length = 'local';
656 with (arguments) {
657 assertEquals(1, length);
658 arguments[Symbol.unscopables] = {length: true};
659 assertEquals('local', length);
660 }
661 }
662 func(1);
663}
664TestArgumentsLengthUnscopables();
665
666
667function TestFunctionCallerUnscopables() {
668 var func = function() {
669 var caller = 'local';
670 with (func) {
671 assertEquals(TestFunctionCallerUnscopables, caller);
672 func[Symbol.unscopables] = {caller: true};
673 assertEquals('local', caller);
674 delete func[Symbol.unscopables];
675 assertEquals(TestFunctionCallerUnscopables, caller);
676 }
677 }
678 func(1);
679}
680TestFunctionCallerUnscopables();
681
682
683function TestGetUnscopablesGetterThrows() {
684 var object = {
685 get x() {
686 assertUnreachable();
687 }
688 };
689 function CustomError() {}
690 Object.defineProperty(object, Symbol.unscopables, {
691 get: function() {
692 throw new CustomError();
693 }
694 });
695 assertThrows(function() {
696 with (object) {
697 x;
698 }
699 }, CustomError);
700}
701TestGetUnscopablesGetterThrows();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400702
703
704function TestGetUnscopablesGetterThrows2() {
705 var object = {
706 get x() {
707 assertUnreachable();
708 }
709 };
710 function CustomError() {}
711
712 object[Symbol.unscopables] = {
713 get x() {
714 throw new CustomError();
715 }
716 };
717 assertThrows(function() {
718 with (object) {
719 x;
720 }
721 }, CustomError);
722}
723TestGetUnscopablesGetterThrows();