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