Home | History | Annotate | Download | only in harmony
      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: --harmony-collections
     29 // Flags: --expose-gc --allow-natives-syntax
     30 
     31 
     32 // Test valid getter and setter calls on Sets and WeakSets
     33 function TestValidSetCalls(m) {
     34   assertDoesNotThrow(function () { m.add(new Object) });
     35   assertDoesNotThrow(function () { m.has(new Object) });
     36   assertDoesNotThrow(function () { m.delete(new Object) });
     37 }
     38 TestValidSetCalls(new Set);
     39 TestValidSetCalls(new WeakSet);
     40 
     41 
     42 // Test valid getter and setter calls on Maps and WeakMaps
     43 function TestValidMapCalls(m) {
     44   assertDoesNotThrow(function () { m.get(new Object) });
     45   assertDoesNotThrow(function () { m.set(new Object) });
     46   assertDoesNotThrow(function () { m.has(new Object) });
     47   assertDoesNotThrow(function () { m.delete(new Object) });
     48 }
     49 TestValidMapCalls(new Map);
     50 TestValidMapCalls(new WeakMap);
     51 
     52 
     53 // Test invalid getter and setter calls for WeakMap only
     54 function TestInvalidCalls(m) {
     55   assertThrows(function () { m.get(undefined) }, TypeError);
     56   assertThrows(function () { m.set(undefined, 0) }, TypeError);
     57   assertThrows(function () { m.get(null) }, TypeError);
     58   assertThrows(function () { m.set(null, 0) }, TypeError);
     59   assertThrows(function () { m.get(0) }, TypeError);
     60   assertThrows(function () { m.set(0, 0) }, TypeError);
     61   assertThrows(function () { m.get('a-key') }, TypeError);
     62   assertThrows(function () { m.set('a-key', 0) }, TypeError);
     63 }
     64 TestInvalidCalls(new WeakMap);
     65 
     66 
     67 // Test expected behavior for Sets and WeakSets
     68 function TestSet(set, key) {
     69   assertFalse(set.has(key));
     70   assertSame(undefined, set.add(key));
     71   assertTrue(set.has(key));
     72   assertTrue(set.delete(key));
     73   assertFalse(set.has(key));
     74   assertFalse(set.delete(key));
     75   assertFalse(set.has(key));
     76 }
     77 function TestSetBehavior(set) {
     78   for (var i = 0; i < 20; i++) {
     79     TestSet(set, new Object);
     80     TestSet(set, i);
     81     TestSet(set, i / 100);
     82     TestSet(set, 'key-' + i);
     83   }
     84   var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ];
     85   for (var i = 0; i < keys.length; i++) {
     86     TestSet(set, keys[i]);
     87   }
     88 }
     89 TestSetBehavior(new Set);
     90 TestSet(new WeakSet, new Object);
     91 
     92 
     93 // Test expected mapping behavior for Maps and WeakMaps
     94 function TestMapping(map, key, value) {
     95   assertSame(undefined, map.set(key, value));
     96   assertSame(value, map.get(key));
     97 }
     98 function TestMapBehavior1(m) {
     99   TestMapping(m, new Object, 23);
    100   TestMapping(m, new Object, 'the-value');
    101   TestMapping(m, new Object, new Object);
    102 }
    103 TestMapBehavior1(new Map);
    104 TestMapBehavior1(new WeakMap);
    105 
    106 
    107 // Test expected mapping behavior for Maps only
    108 function TestMapBehavior2(m) {
    109   for (var i = 0; i < 20; i++) {
    110     TestMapping(m, i, new Object);
    111     TestMapping(m, i / 10, new Object);
    112     TestMapping(m, 'key-' + i, new Object);
    113   }
    114   var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ];
    115   for (var i = 0; i < keys.length; i++) {
    116     TestMapping(m, keys[i], new Object);
    117   }
    118 }
    119 TestMapBehavior2(new Map);
    120 
    121 
    122 // Test expected querying behavior of Maps and WeakMaps
    123 function TestQuery(m) {
    124   var key = new Object;
    125   var values = [ 'x', 0, +Infinity, -Infinity, true, false, null, undefined ];
    126   for (var i = 0; i < values.length; i++) {
    127     TestMapping(m, key, values[i]);
    128     assertTrue(m.has(key));
    129     assertFalse(m.has(new Object));
    130   }
    131 }
    132 TestQuery(new Map);
    133 TestQuery(new WeakMap);
    134 
    135 
    136 // Test expected deletion behavior of Maps and WeakMaps
    137 function TestDelete(m) {
    138   var key = new Object;
    139   TestMapping(m, key, 'to-be-deleted');
    140   assertTrue(m.delete(key));
    141   assertFalse(m.delete(key));
    142   assertFalse(m.delete(new Object));
    143   assertSame(m.get(key), undefined);
    144 }
    145 TestDelete(new Map);
    146 TestDelete(new WeakMap);
    147 
    148 
    149 // Test GC of Maps and WeakMaps with entry
    150 function TestGC1(m) {
    151   var key = new Object;
    152   m.set(key, 'not-collected');
    153   gc();
    154   assertSame('not-collected', m.get(key));
    155 }
    156 TestGC1(new Map);
    157 TestGC1(new WeakMap);
    158 
    159 
    160 // Test GC of Maps and WeakMaps with chained entries
    161 function TestGC2(m) {
    162   var head = new Object;
    163   for (key = head, i = 0; i < 10; i++, key = m.get(key)) {
    164     m.set(key, new Object);
    165   }
    166   gc();
    167   var count = 0;
    168   for (key = head; key != undefined; key = m.get(key)) {
    169     count++;
    170   }
    171   assertEquals(11, count);
    172 }
    173 TestGC2(new Map);
    174 TestGC2(new WeakMap);
    175 
    176 
    177 // Test property attribute [[Enumerable]]
    178 function TestEnumerable(func) {
    179   function props(x) {
    180     var array = [];
    181     for (var p in x) array.push(p);
    182     return array.sort();
    183   }
    184   assertArrayEquals([], props(func));
    185   assertArrayEquals([], props(func.prototype));
    186   assertArrayEquals([], props(new func()));
    187 }
    188 TestEnumerable(Set);
    189 TestEnumerable(Map);
    190 TestEnumerable(WeakMap);
    191 TestEnumerable(WeakSet);
    192 
    193 
    194 // Test arbitrary properties on Maps and WeakMaps
    195 function TestArbitrary(m) {
    196   function TestProperty(map, property, value) {
    197     map[property] = value;
    198     assertEquals(value, map[property]);
    199   }
    200   for (var i = 0; i < 20; i++) {
    201     TestProperty(m, i, 'val' + i);
    202     TestProperty(m, 'foo' + i, 'bar' + i);
    203   }
    204   TestMapping(m, new Object, 'foobar');
    205 }
    206 TestArbitrary(new Map);
    207 TestArbitrary(new WeakMap);
    208 
    209 
    210 // Test direct constructor call
    211 assertThrows(function() { Set(); }, TypeError);
    212 assertThrows(function() { Map(); }, TypeError);
    213 assertThrows(function() { WeakMap(); }, TypeError);
    214 assertThrows(function() { WeakSet(); }, TypeError);
    215 
    216 
    217 // Test whether NaN values as keys are treated correctly.
    218 var s = new Set;
    219 assertFalse(s.has(NaN));
    220 assertFalse(s.has(NaN + 1));
    221 assertFalse(s.has(23));
    222 s.add(NaN);
    223 assertTrue(s.has(NaN));
    224 assertTrue(s.has(NaN + 1));
    225 assertFalse(s.has(23));
    226 var m = new Map;
    227 assertFalse(m.has(NaN));
    228 assertFalse(m.has(NaN + 1));
    229 assertFalse(m.has(23));
    230 m.set(NaN, 'a-value');
    231 assertTrue(m.has(NaN));
    232 assertTrue(m.has(NaN + 1));
    233 assertFalse(m.has(23));
    234 
    235 
    236 // Test some common JavaScript idioms for Sets
    237 var s = new Set;
    238 assertTrue(s instanceof Set);
    239 assertTrue(Set.prototype.add instanceof Function)
    240 assertTrue(Set.prototype.has instanceof Function)
    241 assertTrue(Set.prototype.delete instanceof Function)
    242 assertTrue(Set.prototype.clear instanceof Function)
    243 
    244 
    245 // Test some common JavaScript idioms for Maps
    246 var m = new Map;
    247 assertTrue(m instanceof Map);
    248 assertTrue(Map.prototype.set instanceof Function)
    249 assertTrue(Map.prototype.get instanceof Function)
    250 assertTrue(Map.prototype.has instanceof Function)
    251 assertTrue(Map.prototype.delete instanceof Function)
    252 assertTrue(Map.prototype.clear instanceof Function)
    253 
    254 
    255 // Test some common JavaScript idioms for WeakMaps
    256 var m = new WeakMap;
    257 assertTrue(m instanceof WeakMap);
    258 assertTrue(WeakMap.prototype.set instanceof Function)
    259 assertTrue(WeakMap.prototype.get instanceof Function)
    260 assertTrue(WeakMap.prototype.has instanceof Function)
    261 assertTrue(WeakMap.prototype.delete instanceof Function)
    262 assertTrue(WeakMap.prototype.clear instanceof Function)
    263 
    264 
    265 // Test some common JavaScript idioms for WeakSets
    266 var s = new WeakSet;
    267 assertTrue(s instanceof WeakSet);
    268 assertTrue(WeakSet.prototype.add instanceof Function)
    269 assertTrue(WeakSet.prototype.has instanceof Function)
    270 assertTrue(WeakSet.prototype.delete instanceof Function)
    271 assertTrue(WeakSet.prototype.clear instanceof Function)
    272 
    273 
    274 // Test class of instance and prototype.
    275 assertEquals("Set", %_ClassOf(new Set))
    276 assertEquals("Object", %_ClassOf(Set.prototype))
    277 assertEquals("Map", %_ClassOf(new Map))
    278 assertEquals("Object", %_ClassOf(Map.prototype))
    279 assertEquals("WeakMap", %_ClassOf(new WeakMap))
    280 assertEquals("Object", %_ClassOf(WeakMap.prototype))
    281 assertEquals("WeakSet", %_ClassOf(new WeakSet))
    282 assertEquals("Object", %_ClassOf(WeakMap.prototype))
    283 
    284 
    285 // Test name of constructor.
    286 assertEquals("Set", Set.name);
    287 assertEquals("Map", Map.name);
    288 assertEquals("WeakMap", WeakMap.name);
    289 assertEquals("WeakSet", WeakSet.name);
    290 
    291 
    292 // Test prototype property of Set, Map, WeakMap and WeakSet.
    293 // TODO(2793): Should all be non-writable, and the extra flag removed.
    294 function TestPrototype(C, writable) {
    295   assertTrue(C.prototype instanceof Object);
    296   assertEquals({
    297     value: {},
    298     writable: writable,
    299     enumerable: false,
    300     configurable: false
    301   }, Object.getOwnPropertyDescriptor(C, "prototype"));
    302 }
    303 TestPrototype(Set, true);
    304 TestPrototype(Map, true);
    305 TestPrototype(WeakMap, false);
    306 TestPrototype(WeakSet, false);
    307 
    308 
    309 // Test constructor property of the Set, Map, WeakMap and WeakSet prototype.
    310 function TestConstructor(C) {
    311   assertFalse(C === Object.prototype.constructor);
    312   assertSame(C, C.prototype.constructor);
    313   assertSame(C, (new C).__proto__.constructor);
    314 }
    315 TestConstructor(Set);
    316 TestConstructor(Map);
    317 TestConstructor(WeakMap);
    318 TestConstructor(WeakSet);
    319 
    320 
    321 // Test the Set, Map, WeakMap and WeakSet global properties themselves.
    322 function TestDescriptor(global, C) {
    323   assertEquals({
    324     value: C,
    325     writable: true,
    326     enumerable: false,
    327     configurable: true
    328   }, Object.getOwnPropertyDescriptor(global, C.name));
    329 }
    330 TestDescriptor(this, Set);
    331 TestDescriptor(this, Map);
    332 TestDescriptor(this, WeakMap);
    333 TestDescriptor(this, WeakSet);
    334 
    335 
    336 // Regression test for WeakMap prototype.
    337 assertTrue(WeakMap.prototype.constructor === WeakMap)
    338 assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype)
    339 
    340 
    341 // Regression test for issue 1617: The prototype of the WeakMap constructor
    342 // needs to be unique (i.e. different from the one of the Object constructor).
    343 assertFalse(WeakMap.prototype === Object.prototype);
    344 var o = Object.create({});
    345 assertFalse("get" in o);
    346 assertFalse("set" in o);
    347 assertEquals(undefined, o.get);
    348 assertEquals(undefined, o.set);
    349 var o = Object.create({}, { myValue: {
    350   value: 10,
    351   enumerable: false,
    352   configurable: true,
    353   writable: true
    354 }});
    355 assertEquals(10, o.myValue);
    356 
    357 
    358 // Regression test for issue 1884: Invoking any of the methods for Harmony
    359 // maps, sets, or weak maps, with a wrong type of receiver should be throwing
    360 // a proper TypeError.
    361 var alwaysBogus = [ undefined, null, true, "x", 23, {} ];
    362 var bogusReceiversTestSet = [
    363   { proto: Set.prototype,
    364     funcs: [ 'add', 'has', 'delete' ],
    365     receivers: alwaysBogus.concat([ new Map, new WeakMap, new WeakSet ]),
    366   },
    367   { proto: Map.prototype,
    368     funcs: [ 'get', 'set', 'has', 'delete' ],
    369     receivers: alwaysBogus.concat([ new Set, new WeakMap, new WeakSet ]),
    370   },
    371   { proto: WeakMap.prototype,
    372     funcs: [ 'get', 'set', 'has', 'delete' ],
    373     receivers: alwaysBogus.concat([ new Set, new Map, new WeakSet ]),
    374   },
    375   { proto: WeakSet.prototype,
    376     funcs: [ 'add', 'has', 'delete' ],
    377     receivers: alwaysBogus.concat([ new Set, new Map, new WeakMap ]),
    378   },
    379 ];
    380 function TestBogusReceivers(testSet) {
    381   for (var i = 0; i < testSet.length; i++) {
    382     var proto = testSet[i].proto;
    383     var funcs = testSet[i].funcs;
    384     var receivers = testSet[i].receivers;
    385     for (var j = 0; j < funcs.length; j++) {
    386       var func = proto[funcs[j]];
    387       for (var k = 0; k < receivers.length; k++) {
    388         assertThrows(function () { func.call(receivers[k], {}) }, TypeError);
    389       }
    390     }
    391   }
    392 }
    393 TestBogusReceivers(bogusReceiversTestSet);
    394 
    395 
    396 // Stress Test
    397 // There is a proposed stress-test available at the es-discuss mailing list
    398 // which cannot be reasonably automated.  Check it out by hand if you like:
    399 // https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html
    400 
    401 
    402 // Set and Map size getters
    403 var setSizeDescriptor = Object.getOwnPropertyDescriptor(Set.prototype, 'size');
    404 assertEquals(undefined, setSizeDescriptor.value);
    405 assertEquals(undefined, setSizeDescriptor.set);
    406 assertTrue(setSizeDescriptor.get instanceof Function);
    407 assertEquals(undefined, setSizeDescriptor.get.prototype);
    408 assertFalse(setSizeDescriptor.enumerable);
    409 assertTrue(setSizeDescriptor.configurable);
    410 
    411 var s = new Set();
    412 assertFalse(s.hasOwnProperty('size'));
    413 for (var i = 0; i < 10; i++) {
    414   assertEquals(i, s.size);
    415   s.add(i);
    416 }
    417 for (var i = 9; i >= 0; i--) {
    418   s.delete(i);
    419   assertEquals(i, s.size);
    420 }
    421 
    422 
    423 var mapSizeDescriptor = Object.getOwnPropertyDescriptor(Map.prototype, 'size');
    424 assertEquals(undefined, mapSizeDescriptor.value);
    425 assertEquals(undefined, mapSizeDescriptor.set);
    426 assertTrue(mapSizeDescriptor.get instanceof Function);
    427 assertEquals(undefined, mapSizeDescriptor.get.prototype);
    428 assertFalse(mapSizeDescriptor.enumerable);
    429 assertTrue(mapSizeDescriptor.configurable);
    430 
    431 var m = new Map();
    432 assertFalse(m.hasOwnProperty('size'));
    433 for (var i = 0; i < 10; i++) {
    434   assertEquals(i, m.size);
    435   m.set(i, i);
    436 }
    437 for (var i = 9; i >= 0; i--) {
    438   m.delete(i);
    439   assertEquals(i, m.size);
    440 }
    441 
    442 
    443 // Test Set clear
    444 (function() {
    445   var s = new Set();
    446   s.add(42);
    447   assertTrue(s.has(42));
    448   assertEquals(1, s.size);
    449   s.clear();
    450   assertFalse(s.has(42));
    451   assertEquals(0, s.size);
    452 })();
    453 
    454 
    455 // Test Map clear
    456 (function() {
    457   var m = new Map();
    458   m.set(42, true);
    459   assertTrue(m.has(42));
    460   assertEquals(1, m.size);
    461   m.clear();
    462   assertFalse(m.has(42));
    463   assertEquals(0, m.size);
    464 })();
    465 
    466 
    467 // Test WeakMap clear
    468 (function() {
    469   var k = new Object();
    470   var w = new WeakMap();
    471   w.set(k, 23);
    472   assertTrue(w.has(k));
    473   assertEquals(23, w.get(k));
    474   w.clear();
    475   assertFalse(w.has(k));
    476   assertEquals(undefined, w.get(k));
    477 })();
    478 
    479 
    480 // Test WeakSet clear
    481 (function() {
    482   var k = new Object();
    483   var w = new WeakSet();
    484   w.add(k);
    485   assertTrue(w.has(k));
    486   w.clear();
    487   assertFalse(w.has(k));
    488 })();
    489 
    490 
    491 (function TestMinusZeroSet() {
    492   var m = new Set();
    493   m.add(0);
    494   m.add(-0);
    495   assertEquals(1, m.size);
    496   assertTrue(m.has(0));
    497   assertTrue(m.has(-0));
    498 })();
    499 
    500 
    501 (function TestMinusZeroMap() {
    502   var m = new Map();
    503   m.set(0, 'plus');
    504   m.set(-0, 'minus');
    505   assertEquals(1, m.size);
    506   assertTrue(m.has(0));
    507   assertTrue(m.has(-0));
    508   assertEquals('minus', m.get(0));
    509   assertEquals('minus', m.get(-0));
    510 })();
    511 
    512 
    513 (function TestSetForEachInvalidTypes() {
    514   assertThrows(function() {
    515     Set.prototype.set.forEach.call({});
    516   }, TypeError);
    517 
    518   var set = new Set();
    519   assertThrows(function() {
    520     set.forEach({});
    521   }, TypeError);
    522 })();
    523 
    524 
    525 (function TestSetForEach() {
    526   var set = new Set();
    527   set.add('a');
    528   set.add('b');
    529   set.add('c');
    530 
    531   var buffer = '';
    532   var receiver = {};
    533   set.forEach(function(v, k, s) {
    534     assertSame(v, k);
    535     assertSame(set, s);
    536     assertSame(this, receiver);
    537     buffer += v;
    538     if (v === 'a') {
    539       set.delete('b');
    540       set.add('d');
    541       set.add('e');
    542       set.add('f');
    543     } else if (v === 'c') {
    544       set.add('b');
    545       set.delete('e');
    546     }
    547   }, receiver);
    548 
    549   assertEquals('acdfb', buffer);
    550 })();
    551 
    552 
    553 (function TestSetForEachAddAtEnd() {
    554   var set = new Set();
    555   set.add('a');
    556   set.add('b');
    557 
    558   var buffer = '';
    559   set.forEach(function(v) {
    560     buffer += v;
    561     if (v === 'b') {
    562       set.add('c');
    563     }
    564   });
    565 
    566   assertEquals('abc', buffer);
    567 })();
    568 
    569 
    570 (function TestSetForEachDeleteNext() {
    571   var set = new Set();
    572   set.add('a');
    573   set.add('b');
    574   set.add('c');
    575 
    576   var buffer = '';
    577   set.forEach(function(v) {
    578     buffer += v;
    579     if (v === 'b') {
    580       set.delete('c');
    581     }
    582   });
    583 
    584   assertEquals('ab', buffer);
    585 })();
    586 
    587 
    588 (function TestSetForEachDeleteVisitedAndAddAgain() {
    589   var set = new Set();
    590   set.add('a');
    591   set.add('b');
    592   set.add('c');
    593 
    594   var buffer = '';
    595   set.forEach(function(v) {
    596     buffer += v;
    597     if (v === 'b') {
    598       set.delete('a');
    599     } else if (v === 'c') {
    600       set.add('a');
    601     }
    602   });
    603 
    604   assertEquals('abca', buffer);
    605 })();
    606 
    607 
    608 (function TestSetForEachClear() {
    609   var set = new Set();
    610   set.add('a');
    611   set.add('b');
    612   set.add('c');
    613 
    614   var buffer = '';
    615   set.forEach(function(v) {
    616     buffer += v;
    617     if (v === 'a') {
    618       set.clear();
    619       set.add('d');
    620       set.add('e');
    621     }
    622   });
    623 
    624   assertEquals('ade', buffer);
    625 })();
    626 
    627 
    628 (function TestSetForEachNested() {
    629   var set = new Set();
    630   set.add('a');
    631   set.add('b');
    632   set.add('c');
    633 
    634   var buffer = '';
    635   set.forEach(function(v) {
    636     buffer += v;
    637     set.forEach(function(v) {
    638       buffer += v;
    639       if (v === 'a') {
    640         set.delete('b');
    641       }
    642     });
    643   });
    644 
    645   assertEquals('aaccac', buffer);
    646 })();
    647 
    648 
    649 (function TestSetForEachEarlyExit() {
    650   var set = new Set();
    651   set.add('a');
    652   set.add('b');
    653   set.add('c');
    654 
    655   var buffer = '';
    656   var ex = {};
    657   try {
    658     set.forEach(function(v) {
    659       buffer += v;
    660       throw ex;
    661     });
    662   } catch (e) {
    663     assertEquals(ex, e);
    664   }
    665   assertEquals('a', buffer);
    666 })();
    667 
    668 
    669 (function TestSetForEachGC() {
    670   var set = new Set();
    671   for (var i = 0; i < 100; i++) {
    672     set.add(i);
    673   }
    674 
    675   var accumulated = 0;
    676   set.forEach(function(v) {
    677     accumulated += v;
    678     if (v % 10 === 0) {
    679       gc();
    680     }
    681   });
    682   assertEquals(4950, accumulated);
    683 })();
    684 
    685 (function TestMapForEachInvalidTypes() {
    686   assertThrows(function() {
    687     Map.prototype.map.forEach.call({});
    688   }, TypeError);
    689 
    690   var map = new Map();
    691   assertThrows(function() {
    692     map.forEach({});
    693   }, TypeError);
    694 })();
    695 
    696 
    697 (function TestMapForEach() {
    698   var map = new Map();
    699   map.set(0, 'a');
    700   map.set(1, 'b');
    701   map.set(2, 'c');
    702 
    703   var buffer = [];
    704   var receiver = {};
    705   map.forEach(function(v, k, m) {
    706     assertEquals(map, m);
    707     assertEquals(this, receiver);
    708     buffer.push(k, v);
    709     if (k === 0) {
    710       map.delete(1);
    711       map.set(3, 'd');
    712       map.set(4, 'e');
    713       map.set(5, 'f');
    714     } else if (k === 2) {
    715       map.set(1, 'B');
    716       map.delete(4);
    717     }
    718   }, receiver);
    719 
    720   assertArrayEquals([0, 'a', 2, 'c', 3, 'd', 5, 'f', 1, 'B'], buffer);
    721 })();
    722 
    723 
    724 (function TestMapForEachAddAtEnd() {
    725   var map = new Map();
    726   map.set(0, 'a');
    727   map.set(1, 'b');
    728 
    729   var buffer = [];
    730   map.forEach(function(v, k) {
    731     buffer.push(k, v);
    732     if (k === 1) {
    733       map.set(2, 'c');
    734     }
    735   });
    736 
    737   assertArrayEquals([0, 'a', 1, 'b', 2, 'c'], buffer);
    738 })();
    739 
    740 
    741 (function TestMapForEachDeleteNext() {
    742   var map = new Map();
    743   map.set(0, 'a');
    744   map.set(1, 'b');
    745   map.set(2, 'c');
    746 
    747   var buffer = [];
    748   map.forEach(function(v, k) {
    749     buffer.push(k, v);
    750     if (k === 1) {
    751       map.delete(2);
    752     }
    753   });
    754 
    755   assertArrayEquals([0, 'a', 1, 'b'], buffer);
    756 })();
    757 
    758 
    759 (function TestSetForEachDeleteVisitedAndAddAgain() {
    760   var map = new Map();
    761   map.set(0, 'a');
    762   map.set(1, 'b');
    763   map.set(2, 'c');
    764 
    765   var buffer = [];
    766   map.forEach(function(v, k) {
    767     buffer.push(k, v);
    768     if (k === 1) {
    769       map.delete(0);
    770     } else if (k === 2) {
    771       map.set(0, 'a');
    772     }
    773   });
    774 
    775   assertArrayEquals([0, 'a', 1, 'b', 2, 'c', 0, 'a'], buffer);
    776 })();
    777 
    778 
    779 (function TestMapForEachClear() {
    780   var map = new Map();
    781   map.set(0, 'a');
    782   map.set(1, 'b');
    783   map.set(2, 'c');
    784 
    785   var buffer = [];
    786   map.forEach(function(v, k) {
    787     buffer.push(k, v);
    788     if (k === 0) {
    789       map.clear();
    790       map.set(3, 'd');
    791       map.set(4, 'e');
    792     }
    793   });
    794 
    795   assertArrayEquals([0, 'a', 3, 'd', 4, 'e'], buffer);
    796 })();
    797 
    798 
    799 (function TestMapForEachNested() {
    800   var map = new Map();
    801   map.set(0, 'a');
    802   map.set(1, 'b');
    803   map.set(2, 'c');
    804 
    805   var buffer = [];
    806   map.forEach(function(v, k) {
    807     buffer.push(k, v);
    808     map.forEach(function(v, k) {
    809       buffer.push(k, v);
    810       if (k === 0) {
    811         map.delete(1);
    812       }
    813     });
    814   });
    815 
    816   assertArrayEquals([0, 'a', 0, 'a', 2, 'c', 2, 'c', 0, 'a', 2, 'c'], buffer);
    817 })();
    818 
    819 
    820 (function TestMapForEachEarlyExit() {
    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   var ex = {};
    828   try {
    829     map.forEach(function(v, k) {
    830       buffer.push(k, v);
    831       throw ex;
    832     });
    833   } catch (e) {
    834     assertEquals(ex, e);
    835   }
    836   assertArrayEquals([0, 'a'], buffer);
    837 })();
    838 
    839 
    840 (function TestMapForEachGC() {
    841   var map = new Map();
    842   for (var i = 0; i < 100; i++) {
    843     map.set(i, i);
    844   }
    845 
    846   var accumulated = 0;
    847   map.forEach(function(v) {
    848     accumulated += v;
    849     if (v % 10 === 0) {
    850       gc();
    851     }
    852   });
    853   assertEquals(4950, accumulated);
    854 })();
    855 
    856 
    857 (function TestMapForEachAllRemovedTransition() {
    858   var map = new Map;
    859   map.set(0, 0);
    860 
    861   var buffer = [];
    862   map.forEach(function(v) {
    863     buffer.push(v);
    864     if (v === 0) {
    865       for (var i = 1; i < 4; i++) {
    866         map.set(i, i);
    867       }
    868     }
    869 
    870     if (v === 3) {
    871       for (var i = 0; i < 4; i++) {
    872         map.delete(i);
    873       }
    874       for (var i = 4; i < 8; i++) {
    875         map.set(i, i);
    876       }
    877     }
    878   });
    879 
    880   assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7], buffer);
    881 })();
    882 
    883 
    884 (function TestMapForEachClearTransition() {
    885   var map = new Map;
    886   map.set(0, 0);
    887 
    888   var i = 0;
    889   var buffer = [];
    890   map.forEach(function(v) {
    891     buffer.push(v);
    892     if (++i < 5) {
    893       for (var j = 0; j < 5; j++) {
    894         map.clear();
    895         map.set(i, i);
    896       }
    897     }
    898   });
    899 
    900   assertArrayEquals([0, 1, 2, 3, 4], buffer);
    901 })();
    902 
    903 
    904 (function TestMapForEachNestedNonTrivialTransition() {
    905   var map = new Map;
    906   map.set(0, 0);
    907   map.set(1, 1);
    908   map.set(2, 2);
    909   map.set(3, 3);
    910   map.delete(0);
    911 
    912   var i = 0;
    913   var buffer = [];
    914   map.forEach(function(v) {
    915     if (++i > 10) return;
    916 
    917     buffer.push(v);
    918 
    919     if (v == 3) {
    920       map.delete(1);
    921       for (var j = 4; j < 10; j++) {
    922         map.set(j, j);
    923       }
    924       for (var j = 4; j < 10; j += 2) {
    925         map.delete(j);
    926       }
    927       map.delete(2);
    928 
    929       for (var j = 10; j < 20; j++) {
    930         map.set(j, j);
    931       }
    932       for (var j = 10; j < 20; j += 2) {
    933         map.delete(j);
    934       }
    935 
    936       map.delete(3);
    937     }
    938   });
    939 
    940   assertArrayEquals([1, 2, 3, 5, 7, 9, 11, 13, 15, 17], buffer);
    941 })();
    942 
    943 
    944 (function TestMapForEachAllRemovedTransitionNoClear() {
    945   var map = new Map;
    946   map.set(0, 0);
    947 
    948   var buffer = [];
    949   map.forEach(function(v) {
    950     buffer.push(v);
    951     if (v === 0) {
    952       for (var i = 1; i < 8; i++) {
    953         map.set(i, i);
    954       }
    955     }
    956 
    957     if (v === 4) {
    958       for (var i = 0; i < 8; i++) {
    959         map.delete(i);
    960       }
    961     }
    962   });
    963 
    964   assertArrayEquals([0, 1, 2, 3, 4], buffer);
    965 })();
    966 
    967 
    968 (function TestMapForEachNoMoreElementsAfterTransition() {
    969   var map = new Map;
    970   map.set(0, 0);
    971 
    972   var buffer = [];
    973   map.forEach(function(v) {
    974     buffer.push(v);
    975     if (v === 0) {
    976       for (var i = 1; i < 16; i++) {
    977         map.set(i, i);
    978       }
    979     }
    980 
    981     if (v === 4) {
    982       for (var i = 5; i < 16; i++) {
    983         map.delete(i);
    984       }
    985     }
    986   });
    987 
    988   assertArrayEquals([0, 1, 2, 3, 4], buffer);
    989 })();
    990