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