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