OLD | NEW |
| (Empty) |
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 --harmony-iteration | |
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(set, 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(map, 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 | |
991 | |
992 (function TestSetConstructor() { | |
993 var s = new Set(null); | |
994 assertEquals(s.size, 0); | |
995 | |
996 s = new Set(undefined); | |
997 assertEquals(s.size, 0); | |
998 | |
999 // No @@iterator | |
1000 assertThrows(function() { | |
1001 new Set({}); | |
1002 }, TypeError); | |
1003 | |
1004 // @@iterator not callable | |
1005 assertThrows(function() { | |
1006 var object = {}; | |
1007 object[Symbol.iterator] = 42; | |
1008 new Set(object); | |
1009 }, TypeError); | |
1010 | |
1011 // @@iterator result not object | |
1012 assertThrows(function() { | |
1013 var object = {}; | |
1014 object[Symbol.iterator] = function() { | |
1015 return 42; | |
1016 }; | |
1017 new Set(object); | |
1018 }, TypeError); | |
1019 | |
1020 var s2 = new Set(); | |
1021 s2.add('a'); | |
1022 s2.add('b'); | |
1023 s2.add('c'); | |
1024 s = new Set(s2.values()); | |
1025 assertEquals(s.size, 3); | |
1026 assertTrue(s.has('a')); | |
1027 assertTrue(s.has('b')); | |
1028 assertTrue(s.has('c')); | |
1029 })(); | |
1030 | |
1031 | |
1032 (function TestSetConstructorAddNotCallable() { | |
1033 var originalSetPrototypeAdd = Set.prototype.add; | |
1034 assertThrows(function() { | |
1035 Set.prototype.add = 42; | |
1036 new Set([1, 2].values()); | |
1037 }, TypeError); | |
1038 Set.prototype.add = originalSetPrototypeAdd; | |
1039 })(); | |
1040 | |
1041 | |
1042 (function TestSetConstructorGetAddOnce() { | |
1043 var originalSetPrototypeAdd = Set.prototype.add; | |
1044 var getAddCount = 0; | |
1045 Object.defineProperty(Set.prototype, 'add', { | |
1046 get: function() { | |
1047 getAddCount++; | |
1048 return function() {}; | |
1049 } | |
1050 }); | |
1051 var s = new Set([1, 2].values()); | |
1052 assertEquals(getAddCount, 1); | |
1053 assertEquals(s.size, 0); | |
1054 Object.defineProperty(Set.prototype, 'add', { | |
1055 value: originalSetPrototypeAdd, | |
1056 writable: true | |
1057 }); | |
1058 })(); | |
1059 | |
1060 | |
1061 (function TestSetConstructorAddReplaced() { | |
1062 var originalSetPrototypeAdd = Set.prototype.add; | |
1063 var addCount = 0; | |
1064 Set.prototype.add = function(value) { | |
1065 addCount++; | |
1066 originalSetPrototypeAdd.call(this, value); | |
1067 Set.prototype.add = null; | |
1068 }; | |
1069 var s = new Set([1, 2].values()); | |
1070 assertEquals(addCount, 2); | |
1071 assertEquals(s.size, 2); | |
1072 Set.prototype.add = originalSetPrototypeAdd; | |
1073 })(); | |
1074 | |
1075 | |
1076 (function TestSetConstructorOrderOfDoneValue() { | |
1077 var valueCount = 0, doneCount = 0; | |
1078 var iterator = { | |
1079 next: function() { | |
1080 return { | |
1081 get value() { | |
1082 valueCount++; | |
1083 }, | |
1084 get done() { | |
1085 doneCount++; | |
1086 throw new Error(); | |
1087 } | |
1088 }; | |
1089 } | |
1090 }; | |
1091 iterator[Symbol.iterator] = function() { | |
1092 return this; | |
1093 }; | |
1094 assertThrows(function() { | |
1095 new Set(iterator); | |
1096 }); | |
1097 assertEquals(doneCount, 1); | |
1098 assertEquals(valueCount, 0); | |
1099 })(); | |
1100 | |
1101 | |
1102 (function TestSetConstructorNextNotAnObject() { | |
1103 var iterator = { | |
1104 next: function() { | |
1105 return 'abc'; | |
1106 } | |
1107 }; | |
1108 iterator[Symbol.iterator] = function() { | |
1109 return this; | |
1110 }; | |
1111 assertThrows(function() { | |
1112 new Set(iterator); | |
1113 }, TypeError); | |
1114 })(); | |
1115 | |
1116 | |
1117 (function TestMapConstructor() { | |
1118 var m = new Map(null); | |
1119 assertEquals(m.size, 0); | |
1120 | |
1121 m = new Map(undefined); | |
1122 assertEquals(m.size, 0); | |
1123 | |
1124 // No @@iterator | |
1125 assertThrows(function() { | |
1126 new Map({}); | |
1127 }, TypeError); | |
1128 | |
1129 // @@iterator not callable | |
1130 assertThrows(function() { | |
1131 var object = {}; | |
1132 object[Symbol.iterator] = 42; | |
1133 new Map(object); | |
1134 }, TypeError); | |
1135 | |
1136 // @@iterator result not object | |
1137 assertThrows(function() { | |
1138 var object = {}; | |
1139 object[Symbol.iterator] = function() { | |
1140 return 42; | |
1141 }; | |
1142 new Map(object); | |
1143 }, TypeError); | |
1144 | |
1145 var m2 = new Map(); | |
1146 m2.set(0, 'a'); | |
1147 m2.set(1, 'b'); | |
1148 m2.set(2, 'c'); | |
1149 m = new Map(m2.entries()); | |
1150 assertEquals(m.size, 3); | |
1151 assertEquals(m.get(0), 'a'); | |
1152 assertEquals(m.get(1), 'b'); | |
1153 assertEquals(m.get(2), 'c'); | |
1154 })(); | |
1155 | |
1156 | |
1157 (function TestMapConstructorSetNotCallable() { | |
1158 var originalMapPrototypeSet = Map.prototype.set; | |
1159 assertThrows(function() { | |
1160 Map.prototype.set = 42; | |
1161 new Map([1, 2].entries()); | |
1162 }, TypeError); | |
1163 Map.prototype.set = originalMapPrototypeSet; | |
1164 })(); | |
1165 | |
1166 | |
1167 (function TestMapConstructorGetAddOnce() { | |
1168 var originalMapPrototypeSet = Map.prototype.set; | |
1169 var getSetCount = 0; | |
1170 Object.defineProperty(Map.prototype, 'set', { | |
1171 get: function() { | |
1172 getSetCount++; | |
1173 return function() {}; | |
1174 } | |
1175 }); | |
1176 var m = new Map([1, 2].entries()); | |
1177 assertEquals(getSetCount, 1); | |
1178 assertEquals(m.size, 0); | |
1179 Object.defineProperty(Map.prototype, 'set', { | |
1180 value: originalMapPrototypeSet, | |
1181 writable: true | |
1182 }); | |
1183 })(); | |
1184 | |
1185 | |
1186 (function TestMapConstructorSetReplaced() { | |
1187 var originalMapPrototypeSet = Map.prototype.set; | |
1188 var setCount = 0; | |
1189 Map.prototype.set = function(key, value) { | |
1190 setCount++; | |
1191 originalMapPrototypeSet.call(this, key, value); | |
1192 Map.prototype.set = null; | |
1193 }; | |
1194 var m = new Map([1, 2].entries()); | |
1195 assertEquals(setCount, 2); | |
1196 assertEquals(m.size, 2); | |
1197 Map.prototype.set = originalMapPrototypeSet; | |
1198 })(); | |
1199 | |
1200 | |
1201 (function TestMapConstructorOrderOfDoneValue() { | |
1202 var valueCount = 0, doneCount = 0; | |
1203 function FakeError() {} | |
1204 var iterator = { | |
1205 next: function() { | |
1206 return { | |
1207 get value() { | |
1208 valueCount++; | |
1209 }, | |
1210 get done() { | |
1211 doneCount++; | |
1212 throw new FakeError(); | |
1213 } | |
1214 }; | |
1215 } | |
1216 }; | |
1217 iterator[Symbol.iterator] = function() { | |
1218 return this; | |
1219 }; | |
1220 assertThrows(function() { | |
1221 new Map(iterator); | |
1222 }, FakeError); | |
1223 assertEquals(doneCount, 1); | |
1224 assertEquals(valueCount, 0); | |
1225 })(); | |
1226 | |
1227 | |
1228 (function TestMapConstructorNextNotAnObject() { | |
1229 var iterator = { | |
1230 next: function() { | |
1231 return 'abc'; | |
1232 } | |
1233 }; | |
1234 iterator[Symbol.iterator] = function() { | |
1235 return this; | |
1236 }; | |
1237 assertThrows(function() { | |
1238 new Map(iterator); | |
1239 }, TypeError); | |
1240 })(); | |
1241 | |
1242 | |
1243 (function TestMapConstructorIteratorNotObjectValues() { | |
1244 assertThrows(function() { | |
1245 new Map([1, 2].values()); | |
1246 }, TypeError); | |
1247 })(); | |
OLD | NEW |