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