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