deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / test / mjsunit / es6 / collections.js
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 // Flags: --expose-gc --allow-natives-syntax --harmony-tostring
29
30
31 function assertSize(expected, collection) {
32   if (collection instanceof Map || collection instanceof Set) {
33     assertEquals(expected, collection.size);
34   }
35 }
36
37
38 // Test valid getter and setter calls on Sets and WeakSets
39 function TestValidSetCalls(m) {
40   assertDoesNotThrow(function () { m.add(new Object) });
41   assertDoesNotThrow(function () { m.has(new Object) });
42   assertDoesNotThrow(function () { m.delete(new Object) });
43 }
44 TestValidSetCalls(new Set);
45 TestValidSetCalls(new WeakSet);
46
47
48 // Test valid getter and setter calls on Maps and WeakMaps
49 function TestValidMapCalls(m) {
50   assertDoesNotThrow(function () { m.get(new Object) });
51   assertDoesNotThrow(function () { m.set(new Object) });
52   assertDoesNotThrow(function () { m.has(new Object) });
53   assertDoesNotThrow(function () { m.delete(new Object) });
54   assertDoesNotThrow(function () { m.get(undefined) });
55   assertDoesNotThrow(function () { m.get(null) });
56   assertDoesNotThrow(function () { m.get(0) });
57   assertDoesNotThrow(function () { m.get('a-key') });
58   assertDoesNotThrow(function () { m.get(Symbol()) });
59   assertDoesNotThrow(function () { m.has(undefined) });
60   assertDoesNotThrow(function () { m.has(null) });
61   assertDoesNotThrow(function () { m.has(0) });
62   assertDoesNotThrow(function () { m.has('a-key') });
63   assertDoesNotThrow(function () { m.has(Symbol()) });
64   assertDoesNotThrow(function () { m.delete(undefined) });
65   assertDoesNotThrow(function () { m.delete(null) });
66   assertDoesNotThrow(function () { m.delete(0) });
67   assertDoesNotThrow(function () { m.delete('a-key') });
68   assertDoesNotThrow(function () { m.delete(Symbol()) });
69 }
70 TestValidMapCalls(new Map);
71 TestValidMapCalls(new WeakMap);
72
73
74 // Test invalid getter and setter calls for WeakMap only
75 function TestInvalidCalls(m) {
76   assertThrows(function () { m.set(undefined, 0) }, TypeError);
77   assertThrows(function () { m.set(null, 0) }, TypeError);
78   assertThrows(function () { m.set(0, 0) }, TypeError);
79   assertThrows(function () { m.set('a-key', 0) }, TypeError);
80   assertThrows(function () { m.set(Symbol(), 0) }, TypeError);
81 }
82 TestInvalidCalls(new WeakMap);
83
84
85 // Test expected behavior for Sets and WeakSets
86 function TestSet(set, key) {
87   assertFalse(set.has(key));
88   assertFalse(set.delete(key));
89   if (typeof key === 'object' && !(set instanceof WeakSet)) {
90     assertSame(set, set.add(key));
91     assertTrue(set.has(key));
92     assertTrue(set.delete(key));
93   }
94   assertFalse(set.has(key));
95   assertFalse(set.delete(key));
96   assertFalse(set.has(key));
97 }
98 function TestSetBehavior(set) {
99   // Fill
100   for (var i = 0; i < 20; i++) {
101     TestSet(set, new Object);
102     TestSet(set, i);
103     TestSet(set, i / 100);
104     TestSet(set, 'key-' + i);
105     TestSet(set, Symbol(i));
106   }
107
108   var keys = [
109     -0, +0, 1, 1/3, 10, +Infinity, -Infinity, NaN, true, false, null, undefined,
110     'x', Symbol(), {}, function(){}
111   ];
112   for (var i = 0; i < keys.length; i++) {
113     TestSet(set, keys[i]);
114   }
115 }
116 TestSetBehavior(new Set);
117 TestSetBehavior(new WeakSet);
118
119
120 // Test expected mapping behavior for Maps and WeakMaps
121 function TestMapping(map, key, value) {
122   assertFalse(map.has(key));
123   assertSame(undefined, map.get(key));
124   assertFalse(map.delete(key));
125   if (typeof key === 'object' && !(map instanceof WeakMap)) {
126     assertSame(map, map.set(key, value));
127     assertSame(value, map.get(key));
128     assertTrue(map.has(key));
129     assertTrue(map.delete(key));
130   }
131   assertFalse(map.has(key));
132   assertSame(undefined, map.get(key));
133   assertFalse(map.delete(key));
134   assertFalse(map.has(key));
135   assertSame(undefined, map.get(key));
136 }
137 function TestMapBehavior(m) {
138   // Fill
139   TestMapping(m, new Object, 23);
140   TestMapping(m, new Object, 'the-value');
141   TestMapping(m, new Object, new Object);
142   for (var i = 0; i < 20; i++) {
143     TestMapping(m, i, new Object);
144     TestMapping(m, i / 10, new Object);
145     TestMapping(m, 'key-' + i, new Object);
146     TestMapping(m, Symbol(i), new Object);
147   }
148
149   var keys = [
150     -0, +0, 1, 1/3, 10, +Infinity, -Infinity, NaN, true, false, null, undefined,
151     'x', Symbol(), {}, function(){}
152   ];
153   for (var i = 0; i < keys.length; i++) {
154     TestMapping(m, keys[i], 23);
155     TestMapping(m, keys[i], 'the-value');
156     TestMapping(m, keys[i], new Object);
157   }
158 }
159 TestMapBehavior(new Map);
160 TestMapBehavior(new WeakMap);
161
162
163 // Test expected querying behavior of Maps and WeakMaps
164 function TestQuery(m) {
165   var key = new Object;
166   var values = [ 'x', 0, +Infinity, -Infinity, true, false, null, undefined ];
167   for (var i = 0; i < values.length; i++) {
168     TestMapping(m, key, values[i]);
169   }
170 }
171 TestQuery(new Map);
172 TestQuery(new WeakMap);
173
174
175 // Test expected deletion behavior of Maps and WeakMaps
176 function TestDelete(m) {
177   var key = new Object;
178   TestMapping(m, key, 'to-be-deleted');
179   assertFalse(m.delete(key));
180   assertFalse(m.delete(new Object));
181   assertSame(m.get(key), undefined);
182 }
183 TestDelete(new Map);
184 TestDelete(new WeakMap);
185
186
187 // Test GC of Maps and WeakMaps with entry
188 function TestGC1(m) {
189   var key = new Object;
190   m.set(key, 'not-collected');
191   gc();
192   assertSame('not-collected', m.get(key));
193 }
194 TestGC1(new Map);
195 TestGC1(new WeakMap);
196
197
198 // Test GC of Maps and WeakMaps with chained entries
199 function TestGC2(m) {
200   var head = new Object;
201   for (key = head, i = 0; i < 10; i++, key = m.get(key)) {
202     m.set(key, new Object);
203   }
204   gc();
205   var count = 0;
206   for (key = head; key != undefined; key = m.get(key)) {
207     count++;
208   }
209   assertEquals(11, count);
210 }
211 TestGC2(new Map);
212 TestGC2(new WeakMap);
213
214
215 // Test property attribute [[Enumerable]]
216 function TestEnumerable(func) {
217   function props(x) {
218     var array = [];
219     for (var p in x) array.push(p);
220     return array.sort();
221   }
222   assertArrayEquals([], props(func));
223   assertArrayEquals([], props(func.prototype));
224   assertArrayEquals([], props(new func()));
225 }
226 TestEnumerable(Set);
227 TestEnumerable(Map);
228 TestEnumerable(WeakMap);
229 TestEnumerable(WeakSet);
230
231
232 // Test arbitrary properties on Maps and WeakMaps
233 function TestArbitrary(m) {
234   function TestProperty(map, property, value) {
235     map[property] = value;
236     assertEquals(value, map[property]);
237   }
238   for (var i = 0; i < 20; i++) {
239     TestProperty(m, i, 'val' + i);
240     TestProperty(m, 'foo' + i, 'bar' + i);
241   }
242   TestMapping(m, new Object, 'foobar');
243 }
244 TestArbitrary(new Map);
245 TestArbitrary(new WeakMap);
246
247
248 // Test direct constructor call
249 assertThrows(function() { Set(); }, TypeError);
250 assertThrows(function() { Map(); }, TypeError);
251 assertThrows(function() { WeakMap(); }, TypeError);
252 assertThrows(function() { WeakSet(); }, TypeError);
253
254
255 // Test whether NaN values as keys are treated correctly.
256 var s = new Set;
257 assertFalse(s.has(NaN));
258 assertFalse(s.has(NaN + 1));
259 assertFalse(s.has(23));
260 s.add(NaN);
261 assertTrue(s.has(NaN));
262 assertTrue(s.has(NaN + 1));
263 assertFalse(s.has(23));
264 var m = new Map;
265 assertFalse(m.has(NaN));
266 assertFalse(m.has(NaN + 1));
267 assertFalse(m.has(23));
268 m.set(NaN, 'a-value');
269 assertTrue(m.has(NaN));
270 assertTrue(m.has(NaN + 1));
271 assertFalse(m.has(23));
272
273
274 // Test some common JavaScript idioms for Sets
275 var s = new Set;
276 assertTrue(s instanceof Set);
277 assertTrue(Set.prototype.add instanceof Function)
278 assertTrue(Set.prototype.has instanceof Function)
279 assertTrue(Set.prototype.delete instanceof Function)
280 assertTrue(Set.prototype.clear instanceof Function)
281
282
283 // Test some common JavaScript idioms for Maps
284 var m = new Map;
285 assertTrue(m instanceof Map);
286 assertTrue(Map.prototype.set instanceof Function)
287 assertTrue(Map.prototype.get instanceof Function)
288 assertTrue(Map.prototype.has instanceof Function)
289 assertTrue(Map.prototype.delete instanceof Function)
290 assertTrue(Map.prototype.clear instanceof Function)
291
292
293 // Test some common JavaScript idioms for WeakMaps
294 var m = new WeakMap;
295 assertTrue(m instanceof WeakMap);
296 assertTrue(WeakMap.prototype.set instanceof Function)
297 assertTrue(WeakMap.prototype.get instanceof Function)
298 assertTrue(WeakMap.prototype.has instanceof Function)
299 assertTrue(WeakMap.prototype.delete instanceof Function)
300
301
302 // Test some common JavaScript idioms for WeakSets
303 var s = new WeakSet;
304 assertTrue(s instanceof WeakSet);
305 assertTrue(WeakSet.prototype.add instanceof Function)
306 assertTrue(WeakSet.prototype.has instanceof Function)
307 assertTrue(WeakSet.prototype.delete instanceof Function)
308
309
310 // Test class of instance and prototype.
311 assertEquals("Set", %_ClassOf(new Set))
312 assertEquals("Object", %_ClassOf(Set.prototype))
313 assertEquals("Map", %_ClassOf(new Map))
314 assertEquals("Object", %_ClassOf(Map.prototype))
315 assertEquals("WeakMap", %_ClassOf(new WeakMap))
316 assertEquals("Object", %_ClassOf(WeakMap.prototype))
317 assertEquals("WeakSet", %_ClassOf(new WeakSet))
318 assertEquals("Object", %_ClassOf(WeakMap.prototype))
319
320
321 // Test name of constructor.
322 assertEquals("Set", Set.name);
323 assertEquals("Map", Map.name);
324 assertEquals("WeakMap", WeakMap.name);
325 assertEquals("WeakSet", WeakSet.name);
326
327
328 // Test prototype property of Set, Map, WeakMap and WeakSet.
329 function TestPrototype(C) {
330   assertTrue(C.prototype instanceof Object);
331   assertEquals({
332     value: C.prototype,
333     writable: false,
334     enumerable: false,
335     configurable: false
336   }, Object.getOwnPropertyDescriptor(C, "prototype"));
337 }
338 TestPrototype(Set);
339 TestPrototype(Map);
340 TestPrototype(WeakMap);
341 TestPrototype(WeakSet);
342
343
344 // Test constructor property of the Set, Map, WeakMap and WeakSet prototype.
345 function TestConstructor(C) {
346   assertFalse(C === Object.prototype.constructor);
347   assertSame(C, C.prototype.constructor);
348   assertSame(C, (new C).__proto__.constructor);
349   assertEquals(1, C.length);
350 }
351 TestConstructor(Set);
352 TestConstructor(Map);
353 TestConstructor(WeakMap);
354 TestConstructor(WeakSet);
355
356
357 // Test the Set, Map, WeakMap and WeakSet global properties themselves.
358 function TestDescriptor(global, C) {
359   assertEquals({
360     value: C,
361     writable: true,
362     enumerable: false,
363     configurable: true
364   }, Object.getOwnPropertyDescriptor(global, C.name));
365 }
366 TestDescriptor(this, Set);
367 TestDescriptor(this, Map);
368 TestDescriptor(this, WeakMap);
369 TestDescriptor(this, WeakSet);
370
371
372 // Regression test for WeakMap prototype.
373 assertTrue(WeakMap.prototype.constructor === WeakMap)
374 assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype)
375
376
377 // Regression test for issue 1617: The prototype of the WeakMap constructor
378 // needs to be unique (i.e. different from the one of the Object constructor).
379 assertFalse(WeakMap.prototype === Object.prototype);
380 var o = Object.create({});
381 assertFalse("get" in o);
382 assertFalse("set" in o);
383 assertEquals(undefined, o.get);
384 assertEquals(undefined, o.set);
385 var o = Object.create({}, { myValue: {
386   value: 10,
387   enumerable: false,
388   configurable: true,
389   writable: true
390 }});
391 assertEquals(10, o.myValue);
392
393
394 // Regression test for issue 1884: Invoking any of the methods for Harmony
395 // maps, sets, or weak maps, with a wrong type of receiver should be throwing
396 // a proper TypeError.
397 var alwaysBogus = [ undefined, null, true, "x", 23, {} ];
398 var bogusReceiversTestSet = [
399   { proto: Set.prototype,
400     funcs: [ 'add', 'has', 'delete' ],
401     receivers: alwaysBogus.concat([ new Map, new WeakMap, new WeakSet ]),
402   },
403   { proto: Map.prototype,
404     funcs: [ 'get', 'set', 'has', 'delete' ],
405     receivers: alwaysBogus.concat([ new Set, new WeakMap, new WeakSet ]),
406   },
407   { proto: WeakMap.prototype,
408     funcs: [ 'get', 'set', 'has', 'delete' ],
409     receivers: alwaysBogus.concat([ new Set, new Map, new WeakSet ]),
410   },
411   { proto: WeakSet.prototype,
412     funcs: [ 'add', 'has', 'delete' ],
413     receivers: alwaysBogus.concat([ new Set, new Map, new WeakMap ]),
414   },
415 ];
416 function TestBogusReceivers(testSet) {
417   for (var i = 0; i < testSet.length; i++) {
418     var proto = testSet[i].proto;
419     var funcs = testSet[i].funcs;
420     var receivers = testSet[i].receivers;
421     for (var j = 0; j < funcs.length; j++) {
422       var func = proto[funcs[j]];
423       for (var k = 0; k < receivers.length; k++) {
424         assertThrows(function () { func.call(receivers[k], {}) }, TypeError);
425       }
426     }
427   }
428 }
429 TestBogusReceivers(bogusReceiversTestSet);
430
431
432 // Stress Test
433 // There is a proposed stress-test available at the es-discuss mailing list
434 // which cannot be reasonably automated.  Check it out by hand if you like:
435 // https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html
436
437
438 // Set and Map size getters
439 var setSizeDescriptor = Object.getOwnPropertyDescriptor(Set.prototype, 'size');
440 assertEquals(undefined, setSizeDescriptor.value);
441 assertEquals(undefined, setSizeDescriptor.set);
442 assertTrue(setSizeDescriptor.get instanceof Function);
443 assertEquals(undefined, setSizeDescriptor.get.prototype);
444 assertFalse(setSizeDescriptor.enumerable);
445 assertTrue(setSizeDescriptor.configurable);
446
447 var s = new Set();
448 assertFalse(s.hasOwnProperty('size'));
449 for (var i = 0; i < 10; i++) {
450   assertEquals(i, s.size);
451   s.add(i);
452 }
453 for (var i = 9; i >= 0; i--) {
454   s.delete(i);
455   assertEquals(i, s.size);
456 }
457
458
459 var mapSizeDescriptor = Object.getOwnPropertyDescriptor(Map.prototype, 'size');
460 assertEquals(undefined, mapSizeDescriptor.value);
461 assertEquals(undefined, mapSizeDescriptor.set);
462 assertTrue(mapSizeDescriptor.get instanceof Function);
463 assertEquals(undefined, mapSizeDescriptor.get.prototype);
464 assertFalse(mapSizeDescriptor.enumerable);
465 assertTrue(mapSizeDescriptor.configurable);
466
467 var m = new Map();
468 assertFalse(m.hasOwnProperty('size'));
469 for (var i = 0; i < 10; i++) {
470   assertEquals(i, m.size);
471   m.set(i, i);
472 }
473 for (var i = 9; i >= 0; i--) {
474   m.delete(i);
475   assertEquals(i, m.size);
476 }
477
478
479 // Test Set clear
480 (function() {
481   var s = new Set();
482   s.add(42);
483   assertTrue(s.has(42));
484   assertEquals(1, s.size);
485   s.clear();
486   assertFalse(s.has(42));
487   assertEquals(0, s.size);
488 })();
489
490
491 // Test Map clear
492 (function() {
493   var m = new Map();
494   m.set(42, true);
495   assertTrue(m.has(42));
496   assertEquals(1, m.size);
497   m.clear();
498   assertFalse(m.has(42));
499   assertEquals(0, m.size);
500 })();
501
502
503 (function TestMinusZeroSet() {
504   var s = new Set();
505   s.add(-0);
506   assertSame(0, s.values().next().value);
507   s.add(0);
508   assertEquals(1, s.size);
509   assertTrue(s.has(0));
510   assertTrue(s.has(-0));
511 })();
512
513
514 (function TestMinusZeroMap() {
515   var m = new Map();
516   m.set(-0, 'minus');
517   assertSame(0, m.keys().next().value);
518   m.set(0, 'plus');
519   assertEquals(1, m.size);
520   assertTrue(m.has(0));
521   assertTrue(m.has(-0));
522   assertEquals('plus', m.get(0));
523   assertEquals('plus', m.get(-0));
524 })();
525
526
527 (function TestSetForEachInvalidTypes() {
528   assertThrows(function() {
529     Set.prototype.set.forEach.call({});
530   }, TypeError);
531
532   var set = new Set();
533   assertThrows(function() {
534     set.forEach({});
535   }, TypeError);
536 })();
537
538
539 (function TestSetForEach() {
540   var set = new Set();
541   set.add('a');
542   set.add('b');
543   set.add('c');
544
545   var buffer = '';
546   var receiver = {};
547   set.forEach(function(v, k, s) {
548     assertSame(v, k);
549     assertSame(set, s);
550     assertSame(this, receiver);
551     buffer += v;
552     if (v === 'a') {
553       set.delete('b');
554       set.add('d');
555       set.add('e');
556       set.add('f');
557     } else if (v === 'c') {
558       set.add('b');
559       set.delete('e');
560     }
561   }, receiver);
562
563   assertEquals('acdfb', buffer);
564 })();
565
566
567 (function TestSetForEachAddAtEnd() {
568   var set = new Set();
569   set.add('a');
570   set.add('b');
571
572   var buffer = '';
573   set.forEach(function(v) {
574     buffer += v;
575     if (v === 'b') {
576       set.add('c');
577     }
578   });
579
580   assertEquals('abc', buffer);
581 })();
582
583
584 (function TestSetForEachDeleteNext() {
585   var set = new Set();
586   set.add('a');
587   set.add('b');
588   set.add('c');
589
590   var buffer = '';
591   set.forEach(function(v) {
592     buffer += v;
593     if (v === 'b') {
594       set.delete('c');
595     }
596   });
597
598   assertEquals('ab', buffer);
599 })();
600
601
602 (function TestSetForEachDeleteVisitedAndAddAgain() {
603   var set = new Set();
604   set.add('a');
605   set.add('b');
606   set.add('c');
607
608   var buffer = '';
609   set.forEach(function(v) {
610     buffer += v;
611     if (v === 'b') {
612       set.delete('a');
613     } else if (v === 'c') {
614       set.add('a');
615     }
616   });
617
618   assertEquals('abca', buffer);
619 })();
620
621
622 (function TestSetForEachClear() {
623   var set = new Set();
624   set.add('a');
625   set.add('b');
626   set.add('c');
627
628   var buffer = '';
629   set.forEach(function(v) {
630     buffer += v;
631     if (v === 'a') {
632       set.clear();
633       set.add('d');
634       set.add('e');
635     }
636   });
637
638   assertEquals('ade', buffer);
639 })();
640
641
642 (function TestSetForEachNested() {
643   var set = new Set();
644   set.add('a');
645   set.add('b');
646   set.add('c');
647
648   var buffer = '';
649   set.forEach(function(v) {
650     buffer += v;
651     set.forEach(function(v) {
652       buffer += v;
653       if (v === 'a') {
654         set.delete('b');
655       }
656     });
657   });
658
659   assertEquals('aaccac', buffer);
660 })();
661
662
663 (function TestSetForEachEarlyExit() {
664   var set = new Set();
665   set.add('a');
666   set.add('b');
667   set.add('c');
668
669   var buffer = '';
670   var ex = {};
671   try {
672     set.forEach(function(v) {
673       buffer += v;
674       throw ex;
675     });
676   } catch (e) {
677     assertEquals(ex, e);
678   }
679   assertEquals('a', buffer);
680 })();
681
682
683 (function TestSetForEachGC() {
684   var set = new Set();
685   for (var i = 0; i < 100; i++) {
686     set.add(i);
687   }
688
689   var accumulated = 0;
690   set.forEach(function(v) {
691     accumulated += v;
692     if (v % 10 === 0) {
693       gc();
694     }
695   });
696   assertEquals(4950, accumulated);
697 })();
698
699
700 (function TestSetForEachReceiverAsObject() {
701   var set = new Set(["1", "2"]);
702
703   // Create a new object in each function call when receiver is a
704   // primitive value. See ECMA-262, Annex C.
705   var a = [];
706   set.forEach(function() { a.push(this) }, "");
707   assertTrue(a[0] !== a[1]);
708
709   // Do not create a new object otherwise.
710   a = [];
711   set.forEach(function() { a.push(this); }, {});
712   assertEquals(a[0], a[1]);
713 })();
714
715
716 (function TestSetForEachReceiverAsObjectInStrictMode() {
717   var set = new Set(["1", "2"]);
718
719   // In strict mode primitive values should not be coerced to an object.
720   var a = [];
721   set.forEach(function() { 'use strict'; a.push(this); }, "");
722   assertTrue(a[0] === "" && a[0] === a[1]);
723 })();
724
725
726 (function TestMapForEachInvalidTypes() {
727   assertThrows(function() {
728     Map.prototype.map.forEach.call({});
729   }, TypeError);
730
731   var map = new Map();
732   assertThrows(function() {
733     map.forEach({});
734   }, TypeError);
735 })();
736
737
738 (function TestMapForEach() {
739   var map = new Map();
740   map.set(0, 'a');
741   map.set(1, 'b');
742   map.set(2, 'c');
743
744   var buffer = [];
745   var receiver = {};
746   map.forEach(function(v, k, m) {
747     assertEquals(map, m);
748     assertEquals(this, receiver);
749     buffer.push(k, v);
750     if (k === 0) {
751       map.delete(1);
752       map.set(3, 'd');
753       map.set(4, 'e');
754       map.set(5, 'f');
755     } else if (k === 2) {
756       map.set(1, 'B');
757       map.delete(4);
758     }
759   }, receiver);
760
761   assertArrayEquals([0, 'a', 2, 'c', 3, 'd', 5, 'f', 1, 'B'], buffer);
762 })();
763
764
765 (function TestMapForEachAddAtEnd() {
766   var map = new Map();
767   map.set(0, 'a');
768   map.set(1, 'b');
769
770   var buffer = [];
771   map.forEach(function(v, k) {
772     buffer.push(k, v);
773     if (k === 1) {
774       map.set(2, 'c');
775     }
776   });
777
778   assertArrayEquals([0, 'a', 1, 'b', 2, 'c'], buffer);
779 })();
780
781
782 (function TestMapForEachDeleteNext() {
783   var map = new Map();
784   map.set(0, 'a');
785   map.set(1, 'b');
786   map.set(2, 'c');
787
788   var buffer = [];
789   map.forEach(function(v, k) {
790     buffer.push(k, v);
791     if (k === 1) {
792       map.delete(2);
793     }
794   });
795
796   assertArrayEquals([0, 'a', 1, 'b'], buffer);
797 })();
798
799
800 (function TestSetForEachDeleteVisitedAndAddAgain() {
801   var map = new Map();
802   map.set(0, 'a');
803   map.set(1, 'b');
804   map.set(2, 'c');
805
806   var buffer = [];
807   map.forEach(function(v, k) {
808     buffer.push(k, v);
809     if (k === 1) {
810       map.delete(0);
811     } else if (k === 2) {
812       map.set(0, 'a');
813     }
814   });
815
816   assertArrayEquals([0, 'a', 1, 'b', 2, 'c', 0, 'a'], buffer);
817 })();
818
819
820 (function TestMapForEachClear() {
821   var map = new Map();
822   map.set(0, 'a');
823   map.set(1, 'b');
824   map.set(2, 'c');
825
826   var buffer = [];
827   map.forEach(function(v, k) {
828     buffer.push(k, v);
829     if (k === 0) {
830       map.clear();
831       map.set(3, 'd');
832       map.set(4, 'e');
833     }
834   });
835
836   assertArrayEquals([0, 'a', 3, 'd', 4, 'e'], buffer);
837 })();
838
839
840 (function TestMapForEachNested() {
841   var map = new Map();
842   map.set(0, 'a');
843   map.set(1, 'b');
844   map.set(2, 'c');
845
846   var buffer = [];
847   map.forEach(function(v, k) {
848     buffer.push(k, v);
849     map.forEach(function(v, k) {
850       buffer.push(k, v);
851       if (k === 0) {
852         map.delete(1);
853       }
854     });
855   });
856
857   assertArrayEquals([0, 'a', 0, 'a', 2, 'c', 2, 'c', 0, 'a', 2, 'c'], buffer);
858 })();
859
860
861 (function TestMapForEachEarlyExit() {
862   var map = new Map();
863   map.set(0, 'a');
864   map.set(1, 'b');
865   map.set(2, 'c');
866
867   var buffer = [];
868   var ex = {};
869   try {
870     map.forEach(function(v, k) {
871       buffer.push(k, v);
872       throw ex;
873     });
874   } catch (e) {
875     assertEquals(ex, e);
876   }
877   assertArrayEquals([0, 'a'], buffer);
878 })();
879
880
881 (function TestMapForEachGC() {
882   var map = new Map();
883   for (var i = 0; i < 100; i++) {
884     map.set(i, i);
885   }
886
887   var accumulated = 0;
888   map.forEach(function(v) {
889     accumulated += v;
890     if (v % 10 === 0) {
891       gc();
892     }
893   });
894   assertEquals(4950, accumulated);
895 })();
896
897
898 (function TestMapForEachAllRemovedTransition() {
899   var map = new Map;
900   map.set(0, 0);
901
902   var buffer = [];
903   map.forEach(function(v) {
904     buffer.push(v);
905     if (v === 0) {
906       for (var i = 1; i < 4; i++) {
907         map.set(i, i);
908       }
909     }
910
911     if (v === 3) {
912       for (var i = 0; i < 4; i++) {
913         map.delete(i);
914       }
915       for (var i = 4; i < 8; i++) {
916         map.set(i, i);
917       }
918     }
919   });
920
921   assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7], buffer);
922 })();
923
924
925 (function TestMapForEachClearTransition() {
926   var map = new Map;
927   map.set(0, 0);
928
929   var i = 0;
930   var buffer = [];
931   map.forEach(function(v) {
932     buffer.push(v);
933     if (++i < 5) {
934       for (var j = 0; j < 5; j++) {
935         map.clear();
936         map.set(i, i);
937       }
938     }
939   });
940
941   assertArrayEquals([0, 1, 2, 3, 4], buffer);
942 })();
943
944
945 (function TestMapForEachNestedNonTrivialTransition() {
946   var map = new Map;
947   map.set(0, 0);
948   map.set(1, 1);
949   map.set(2, 2);
950   map.set(3, 3);
951   map.delete(0);
952
953   var i = 0;
954   var buffer = [];
955   map.forEach(function(v) {
956     if (++i > 10) return;
957
958     buffer.push(v);
959
960     if (v == 3) {
961       map.delete(1);
962       for (var j = 4; j < 10; j++) {
963         map.set(j, j);
964       }
965       for (var j = 4; j < 10; j += 2) {
966         map.delete(j);
967       }
968       map.delete(2);
969
970       for (var j = 10; j < 20; j++) {
971         map.set(j, j);
972       }
973       for (var j = 10; j < 20; j += 2) {
974         map.delete(j);
975       }
976
977       map.delete(3);
978     }
979   });
980
981   assertArrayEquals([1, 2, 3, 5, 7, 9, 11, 13, 15, 17], buffer);
982 })();
983
984
985 (function TestMapForEachAllRemovedTransitionNoClear() {
986   var map = new Map;
987   map.set(0, 0);
988
989   var buffer = [];
990   map.forEach(function(v) {
991     buffer.push(v);
992     if (v === 0) {
993       for (var i = 1; i < 8; i++) {
994         map.set(i, i);
995       }
996     }
997
998     if (v === 4) {
999       for (var i = 0; i < 8; i++) {
1000         map.delete(i);
1001       }
1002     }
1003   });
1004
1005   assertArrayEquals([0, 1, 2, 3, 4], buffer);
1006 })();
1007
1008
1009 (function TestMapForEachNoMoreElementsAfterTransition() {
1010   var map = new Map;
1011   map.set(0, 0);
1012
1013   var buffer = [];
1014   map.forEach(function(v) {
1015     buffer.push(v);
1016     if (v === 0) {
1017       for (var i = 1; i < 16; i++) {
1018         map.set(i, i);
1019       }
1020     }
1021
1022     if (v === 4) {
1023       for (var i = 5; i < 16; i++) {
1024         map.delete(i);
1025       }
1026     }
1027   });
1028
1029   assertArrayEquals([0, 1, 2, 3, 4], buffer);
1030 })();
1031
1032
1033 (function TestMapForEachReceiverAsObject() {
1034   var map = new Map();
1035   map.set("key1", "value1");
1036   map.set("key2", "value2");
1037
1038   // Create a new object in each function call when receiver is a
1039   // primitive value. See ECMA-262, Annex C.
1040   var a = [];
1041   map.forEach(function() { a.push(this) }, "");
1042   assertTrue(a[0] !== a[1]);
1043
1044   // Do not create a new object otherwise.
1045   a = [];
1046   map.forEach(function() { a.push(this); }, {});
1047   assertEquals(a[0], a[1]);
1048 })();
1049
1050
1051 (function TestMapForEachReceiverAsObjectInStrictMode() {
1052   var map = new Map();
1053   map.set("key1", "value1");
1054   map.set("key2", "value2");
1055
1056   // In strict mode primitive values should not be coerced to an object.
1057   var a = [];
1058   map.forEach(function() { 'use strict'; a.push(this); }, "");
1059   assertTrue(a[0] === "" && a[0] === a[1]);
1060 })();
1061
1062
1063 // Allows testing iterator-based constructors easily.
1064 var oneAndTwo = new Map();
1065 var k0 = {key: 0};
1066 var k1 = {key: 1};
1067 var k2 = {key: 2};
1068 oneAndTwo.set(k1, 1);
1069 oneAndTwo.set(k2, 2);
1070
1071
1072 function TestSetConstructor(ctor) {
1073   var s = new ctor(null);
1074   assertSize(0, s);
1075
1076   s = new ctor(undefined);
1077   assertSize(0, s);
1078
1079   // No @@iterator
1080   assertThrows(function() {
1081     new ctor({});
1082   }, TypeError);
1083   assertThrows(function() {
1084     new ctor(true);
1085   }, TypeError);
1086
1087   // @@iterator not callable
1088   assertThrows(function() {
1089     var object = {};
1090     object[Symbol.iterator] = 42;
1091     new ctor(object);
1092   }, TypeError);
1093
1094   // @@iterator result not object
1095   assertThrows(function() {
1096     var object = {};
1097     object[Symbol.iterator] = function() {
1098       return 42;
1099     };
1100     new ctor(object);
1101   }, TypeError);
1102
1103   var s2 = new Set();
1104   s2.add(k0);
1105   s2.add(k1);
1106   s2.add(k2);
1107   s = new ctor(s2.values());
1108   assertSize(3, s);
1109   assertTrue(s.has(k0));
1110   assertTrue(s.has(k1));
1111   assertTrue(s.has(k2));
1112 }
1113 TestSetConstructor(Set);
1114 TestSetConstructor(WeakSet);
1115
1116
1117 function TestSetConstructorAddNotCallable(ctor) {
1118   var originalPrototypeAdd = ctor.prototype.add;
1119   assertThrows(function() {
1120     ctor.prototype.add = 42;
1121     new ctor(oneAndTwo.values());
1122   }, TypeError);
1123   ctor.prototype.add = originalPrototypeAdd;
1124 }
1125 TestSetConstructorAddNotCallable(Set);
1126 TestSetConstructorAddNotCallable(WeakSet);
1127
1128
1129 function TestSetConstructorGetAddOnce(ctor) {
1130   var originalPrototypeAdd = ctor.prototype.add;
1131   var getAddCount = 0;
1132   Object.defineProperty(ctor.prototype, 'add', {
1133     get: function() {
1134       getAddCount++;
1135       return function() {};
1136     }
1137   });
1138   var s = new ctor(oneAndTwo.values());
1139   assertEquals(1, getAddCount);
1140   assertSize(0, s);
1141   Object.defineProperty(ctor.prototype, 'add', {
1142     value: originalPrototypeAdd,
1143     writable: true
1144   });
1145 }
1146 TestSetConstructorGetAddOnce(Set);
1147 TestSetConstructorGetAddOnce(WeakSet);
1148
1149
1150 function TestSetConstructorAddReplaced(ctor) {
1151   var originalPrototypeAdd = ctor.prototype.add;
1152   var addCount = 0;
1153   ctor.prototype.add = function(value) {
1154     addCount++;
1155     originalPrototypeAdd.call(this, value);
1156     ctor.prototype.add = null;
1157   };
1158   var s = new ctor(oneAndTwo.keys());
1159   assertEquals(2, addCount);
1160   assertSize(2, s);
1161   ctor.prototype.add = originalPrototypeAdd;
1162 }
1163 TestSetConstructorAddReplaced(Set);
1164 TestSetConstructorAddReplaced(WeakSet);
1165
1166
1167 function TestSetConstructorOrderOfDoneValue(ctor) {
1168   var valueCount = 0, doneCount = 0;
1169   var iterator = {
1170     next: function() {
1171       return {
1172         get value() {
1173           valueCount++;
1174         },
1175         get done() {
1176           doneCount++;
1177           throw new Error();
1178         }
1179       };
1180     }
1181   };
1182   iterator[Symbol.iterator] = function() {
1183     return this;
1184   };
1185   assertThrows(function() {
1186     new ctor(iterator);
1187   });
1188   assertEquals(1, doneCount);
1189   assertEquals(0, valueCount);
1190 }
1191 TestSetConstructorOrderOfDoneValue(Set);
1192 TestSetConstructorOrderOfDoneValue(WeakSet);
1193
1194
1195 function TestSetConstructorNextNotAnObject(ctor) {
1196   var iterator = {
1197     next: function() {
1198       return 'abc';
1199     }
1200   };
1201   iterator[Symbol.iterator] = function() {
1202     return this;
1203   };
1204   assertThrows(function() {
1205     new ctor(iterator);
1206   }, TypeError);
1207 }
1208 TestSetConstructorNextNotAnObject(Set);
1209 TestSetConstructorNextNotAnObject(WeakSet);
1210
1211
1212 (function TestWeakSetConstructorNonObjectKeys() {
1213   assertThrows(function() {
1214     new WeakSet([1]);
1215   }, TypeError);
1216 })();
1217
1218
1219 function TestSetConstructorIterableValue(ctor) {
1220   'use strict';
1221   // Strict mode is required to prevent implicit wrapping in the getter.
1222   Object.defineProperty(Number.prototype, Symbol.iterator, {
1223     get: function() {
1224       assertEquals('number', typeof this);
1225       return function() {
1226         assertEquals('number', typeof this);
1227         return oneAndTwo.keys();
1228       };
1229     },
1230     configurable: true
1231   });
1232
1233   var set = new ctor(42);
1234   assertSize(2, set);
1235   assertTrue(set.has(k1));
1236   assertTrue(set.has(k2));
1237
1238   delete Number.prototype[Symbol.iterator];
1239 }
1240 TestSetConstructorIterableValue(Set);
1241 TestSetConstructorIterableValue(WeakSet);
1242
1243
1244 (function TestSetConstructorStringValue() {
1245   var s = new Set('abc');
1246   assertSize(3, s);
1247   assertTrue(s.has('a'));
1248   assertTrue(s.has('b'));
1249   assertTrue(s.has('c'));
1250 })();
1251
1252
1253 function TestMapConstructor(ctor) {
1254   var m = new ctor(null);
1255   assertSize(0, m);
1256
1257   m = new ctor(undefined);
1258   assertSize(0, m);
1259
1260   // No @@iterator
1261   assertThrows(function() {
1262     new ctor({});
1263   }, TypeError);
1264   assertThrows(function() {
1265     new ctor(true);
1266   }, TypeError);
1267
1268   // @@iterator not callable
1269   assertThrows(function() {
1270     var object = {};
1271     object[Symbol.iterator] = 42;
1272     new ctor(object);
1273   }, TypeError);
1274
1275   // @@iterator result not object
1276   assertThrows(function() {
1277     var object = {};
1278     object[Symbol.iterator] = function() {
1279       return 42;
1280     };
1281     new ctor(object);
1282   }, TypeError);
1283
1284   var m2 = new Map();
1285   m2.set(k0, 'a');
1286   m2.set(k1, 'b');
1287   m2.set(k2, 'c');
1288   m = new ctor(m2.entries());
1289   assertSize(3, m);
1290   assertEquals('a', m.get(k0));
1291   assertEquals('b', m.get(k1));
1292   assertEquals('c', m.get(k2));
1293 }
1294 TestMapConstructor(Map);
1295 TestMapConstructor(WeakMap);
1296
1297
1298 function TestMapConstructorSetNotCallable(ctor) {
1299   var originalPrototypeSet = ctor.prototype.set;
1300   assertThrows(function() {
1301     ctor.prototype.set = 42;
1302     new ctor(oneAndTwo.entries());
1303   }, TypeError);
1304   ctor.prototype.set = originalPrototypeSet;
1305 }
1306 TestMapConstructorSetNotCallable(Map);
1307 TestMapConstructorSetNotCallable(WeakMap);
1308
1309
1310 function TestMapConstructorGetAddOnce(ctor) {
1311   var originalPrototypeSet = ctor.prototype.set;
1312   var getSetCount = 0;
1313   Object.defineProperty(ctor.prototype, 'set', {
1314     get: function() {
1315       getSetCount++;
1316       return function() {};
1317     }
1318   });
1319   var m = new ctor(oneAndTwo.entries());
1320   assertEquals(1, getSetCount);
1321   assertSize(0, m);
1322   Object.defineProperty(ctor.prototype, 'set', {
1323     value: originalPrototypeSet,
1324     writable: true
1325   });
1326 }
1327 TestMapConstructorGetAddOnce(Map);
1328 TestMapConstructorGetAddOnce(WeakMap);
1329
1330
1331 function TestMapConstructorSetReplaced(ctor) {
1332   var originalPrototypeSet = ctor.prototype.set;
1333   var setCount = 0;
1334   ctor.prototype.set = function(key, value) {
1335     setCount++;
1336     originalPrototypeSet.call(this, key, value);
1337     ctor.prototype.set = null;
1338   };
1339   var m = new ctor(oneAndTwo.entries());
1340   assertEquals(2, setCount);
1341   assertSize(2, m);
1342   ctor.prototype.set = originalPrototypeSet;
1343 }
1344 TestMapConstructorSetReplaced(Map);
1345 TestMapConstructorSetReplaced(WeakMap);
1346
1347
1348 function TestMapConstructorOrderOfDoneValue(ctor) {
1349   var valueCount = 0, doneCount = 0;
1350   function FakeError() {}
1351   var iterator = {
1352     next: function() {
1353       return {
1354         get value() {
1355           valueCount++;
1356         },
1357         get done() {
1358           doneCount++;
1359           throw new FakeError();
1360         }
1361       };
1362     }
1363   };
1364   iterator[Symbol.iterator] = function() {
1365     return this;
1366   };
1367   assertThrows(function() {
1368     new ctor(iterator);
1369   }, FakeError);
1370   assertEquals(1, doneCount);
1371   assertEquals(0, valueCount);
1372 }
1373 TestMapConstructorOrderOfDoneValue(Map);
1374 TestMapConstructorOrderOfDoneValue(WeakMap);
1375
1376
1377 function TestMapConstructorNextNotAnObject(ctor) {
1378   var iterator = {
1379     next: function() {
1380       return 'abc';
1381     }
1382   };
1383   iterator[Symbol.iterator] = function() {
1384     return this;
1385   };
1386   assertThrows(function() {
1387     new ctor(iterator);
1388   }, TypeError);
1389 }
1390 TestMapConstructorNextNotAnObject(Map);
1391 TestMapConstructorNextNotAnObject(WeakMap);
1392
1393
1394 function TestMapConstructorIteratorNotObjectValues(ctor) {
1395   assertThrows(function() {
1396     new ctor(oneAndTwo.values());
1397   }, TypeError);
1398 }
1399 TestMapConstructorIteratorNotObjectValues(Map);
1400 TestMapConstructorIteratorNotObjectValues(WeakMap);
1401
1402
1403 (function TestWeakMapConstructorNonObjectKeys() {
1404   assertThrows(function() {
1405     new WeakMap([[1, 2]])
1406   }, TypeError);
1407 })();
1408
1409
1410 function TestMapConstructorIterableValue(ctor) {
1411   'use strict';
1412   // Strict mode is required to prevent implicit wrapping in the getter.
1413   Object.defineProperty(Number.prototype, Symbol.iterator, {
1414     get: function() {
1415       assertEquals('number', typeof this);
1416       return function() {
1417         assertEquals('number', typeof this);
1418         return oneAndTwo.entries();
1419       };
1420     },
1421     configurable: true
1422   });
1423
1424   var map = new ctor(42);
1425   assertSize(2, map);
1426   assertEquals(1, map.get(k1));
1427   assertEquals(2, map.get(k2));
1428
1429   delete Number.prototype[Symbol.iterator];
1430 }
1431 TestMapConstructorIterableValue(Map);
1432 TestMapConstructorIterableValue(WeakMap);
1433
1434 function TestCollectionToString(C) {
1435   assertEquals("[object " + C.name + "]",
1436       Object.prototype.toString.call(new C()));
1437 }
1438 TestCollectionToString(Map);
1439 TestCollectionToString(Set);
1440 TestCollectionToString(WeakMap);
1441 TestCollectionToString(WeakSet);
1442
1443
1444 function TestConstructorOrderOfAdderIterator(ctor, adderName) {
1445   var iterable = new Map();
1446   iterable.set({}, {});
1447   iterable.set({}, {});
1448   var iterableFunction = iterable[Symbol.iterator];
1449   Object.defineProperty(iterable, Symbol.iterator, {
1450     get: function() {
1451       log += 'iterator';
1452       return iterableFunction;
1453     }
1454   });
1455
1456   var log = '';
1457   var adderFunction = ctor.prototype[adderName];
1458
1459   Object.defineProperty(ctor.prototype, adderName, {
1460     get: function() {
1461       log += adderName;
1462       return adderFunction;
1463     }
1464   });
1465
1466   new ctor(iterable);
1467   assertEquals(adderName + 'iterator', log);
1468
1469   Object.defineProperty(ctor.prototype, adderName, {
1470     value: adderFunction
1471   });
1472 }
1473 TestConstructorOrderOfAdderIterator(Map, 'set');
1474 TestConstructorOrderOfAdderIterator(Set, 'add');
1475 TestConstructorOrderOfAdderIterator(WeakMap, 'set');
1476 TestConstructorOrderOfAdderIterator(WeakSet, 'add');