1// Copyright 2011 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 --expose-gc 29 30 31// Test valid getter and setter calls on Sets. 32function TestValidSetCalls(m) { 33 assertDoesNotThrow(function () { m.add(new Object) }); 34 assertDoesNotThrow(function () { m.has(new Object) }); 35 assertDoesNotThrow(function () { m.delete(new Object) }); 36} 37TestValidSetCalls(new Set); 38 39 40// Test valid getter and setter calls on Maps and WeakMaps 41function TestValidMapCalls(m) { 42 assertDoesNotThrow(function () { m.get(new Object) }); 43 assertDoesNotThrow(function () { m.set(new Object) }); 44 assertDoesNotThrow(function () { m.has(new Object) }); 45 assertDoesNotThrow(function () { m.delete(new Object) }); 46} 47TestValidMapCalls(new Map); 48TestValidMapCalls(new WeakMap); 49 50 51// Test invalid getter and setter calls for WeakMap only 52function TestInvalidCalls(m) { 53 assertThrows(function () { m.get(undefined) }, TypeError); 54 assertThrows(function () { m.set(undefined, 0) }, TypeError); 55 assertThrows(function () { m.get(null) }, TypeError); 56 assertThrows(function () { m.set(null, 0) }, TypeError); 57 assertThrows(function () { m.get(0) }, TypeError); 58 assertThrows(function () { m.set(0, 0) }, TypeError); 59 assertThrows(function () { m.get('a-key') }, TypeError); 60 assertThrows(function () { m.set('a-key', 0) }, TypeError); 61} 62TestInvalidCalls(new WeakMap); 63 64 65// Test expected behavior for Sets 66function TestSet(set, key) { 67 assertFalse(set.has(key)); 68 set.add(key); 69 assertTrue(set.has(key)); 70 set.delete(key); 71 assertFalse(set.has(key)); 72} 73function TestSetBehavior(set) { 74 for (var i = 0; i < 20; i++) { 75 TestSet(set, new Object); 76 TestSet(set, i); 77 TestSet(set, i / 100); 78 TestSet(set, 'key-' + i); 79 } 80 var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ]; 81 for (var i = 0; i < keys.length; i++) { 82 TestSet(set, keys[i]); 83 } 84} 85TestSetBehavior(new Set); 86 87 88// Test expected mapping behavior for Maps and WeakMaps 89function TestMapping(map, key, value) { 90 map.set(key, value); 91 assertSame(value, map.get(key)); 92} 93function TestMapBehavior1(m) { 94 TestMapping(m, new Object, 23); 95 TestMapping(m, new Object, 'the-value'); 96 TestMapping(m, new Object, new Object); 97} 98TestMapBehavior1(new Map); 99TestMapBehavior1(new WeakMap); 100 101 102// Test expected mapping behavior for Maps only 103function TestMapBehavior2(m) { 104 for (var i = 0; i < 20; i++) { 105 TestMapping(m, i, new Object); 106 TestMapping(m, i / 10, new Object); 107 TestMapping(m, 'key-' + i, new Object); 108 } 109 var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ]; 110 for (var i = 0; i < keys.length; i++) { 111 TestMapping(m, keys[i], new Object); 112 } 113} 114TestMapBehavior2(new Map); 115 116 117// Test expected querying behavior of Maps and WeakMaps 118function TestQuery(m) { 119 var key = new Object; 120 TestMapping(m, key, 'to-be-present'); 121 assertTrue(m.has(key)); 122 assertFalse(m.has(new Object)); 123 TestMapping(m, key, undefined); 124 assertFalse(m.has(key)); 125 assertFalse(m.has(new Object)); 126} 127TestQuery(new Map); 128TestQuery(new WeakMap); 129 130 131// Test expected deletion behavior of Maps and WeakMaps 132function TestDelete(m) { 133 var key = new Object; 134 TestMapping(m, key, 'to-be-deleted'); 135 assertTrue(m.delete(key)); 136 assertFalse(m.delete(key)); 137 assertFalse(m.delete(new Object)); 138 assertSame(m.get(key), undefined); 139} 140TestDelete(new Map); 141TestDelete(new WeakMap); 142 143 144// Test GC of Maps and WeakMaps with entry 145function TestGC1(m) { 146 var key = new Object; 147 m.set(key, 'not-collected'); 148 gc(); 149 assertSame('not-collected', m.get(key)); 150} 151TestGC1(new Map); 152TestGC1(new WeakMap); 153 154 155// Test GC of Maps and WeakMaps with chained entries 156function TestGC2(m) { 157 var head = new Object; 158 for (key = head, i = 0; i < 10; i++, key = m.get(key)) { 159 m.set(key, new Object); 160 } 161 gc(); 162 var count = 0; 163 for (key = head; key != undefined; key = m.get(key)) { 164 count++; 165 } 166 assertEquals(11, count); 167} 168TestGC2(new Map); 169TestGC2(new WeakMap); 170 171 172// Test property attribute [[Enumerable]] 173function TestEnumerable(func) { 174 function props(x) { 175 var array = []; 176 for (var p in x) array.push(p); 177 return array.sort(); 178 } 179 assertArrayEquals([], props(func)); 180 assertArrayEquals([], props(func.prototype)); 181 assertArrayEquals([], props(new func())); 182} 183TestEnumerable(Set); 184TestEnumerable(Map); 185TestEnumerable(WeakMap); 186 187 188// Test arbitrary properties on Maps and WeakMaps 189function TestArbitrary(m) { 190 function TestProperty(map, property, value) { 191 map[property] = value; 192 assertEquals(value, map[property]); 193 } 194 for (var i = 0; i < 20; i++) { 195 TestProperty(m, i, 'val' + i); 196 TestProperty(m, 'foo' + i, 'bar' + i); 197 } 198 TestMapping(m, new Object, 'foobar'); 199} 200TestArbitrary(new Map); 201TestArbitrary(new WeakMap); 202 203 204// Test direct constructor call 205assertTrue(Set() instanceof Set); 206assertTrue(Map() instanceof Map); 207assertTrue(WeakMap() instanceof WeakMap); 208 209 210// Test whether NaN values as keys are treated correctly. 211var s = new Set; 212assertFalse(s.has(NaN)); 213assertFalse(s.has(NaN + 1)); 214assertFalse(s.has(23)); 215s.add(NaN); 216assertTrue(s.has(NaN)); 217assertTrue(s.has(NaN + 1)); 218assertFalse(s.has(23)); 219var m = new Map; 220assertFalse(m.has(NaN)); 221assertFalse(m.has(NaN + 1)); 222assertFalse(m.has(23)); 223m.set(NaN, 'a-value'); 224assertTrue(m.has(NaN)); 225assertTrue(m.has(NaN + 1)); 226assertFalse(m.has(23)); 227 228 229// Test some common JavaScript idioms for Sets 230var s = new Set; 231assertTrue(s instanceof Set); 232assertTrue(Set.prototype.add instanceof Function) 233assertTrue(Set.prototype.has instanceof Function) 234assertTrue(Set.prototype.delete instanceof Function) 235 236 237// Test some common JavaScript idioms for Maps 238var m = new Map; 239assertTrue(m instanceof Map); 240assertTrue(Map.prototype.set instanceof Function) 241assertTrue(Map.prototype.get instanceof Function) 242assertTrue(Map.prototype.has instanceof Function) 243assertTrue(Map.prototype.delete instanceof Function) 244 245 246// Test some common JavaScript idioms for WeakMaps 247var m = new WeakMap; 248assertTrue(m instanceof WeakMap); 249assertTrue(WeakMap.prototype.set instanceof Function) 250assertTrue(WeakMap.prototype.get instanceof Function) 251assertTrue(WeakMap.prototype.has instanceof Function) 252assertTrue(WeakMap.prototype.delete instanceof Function) 253 254 255// Regression test for WeakMap prototype. 256assertTrue(WeakMap.prototype.constructor === WeakMap) 257assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype) 258 259 260// Regression test for issue 1617: The prototype of the WeakMap constructor 261// needs to be unique (i.e. different from the one of the Object constructor). 262assertFalse(WeakMap.prototype === Object.prototype); 263var o = Object.create({}); 264assertFalse("get" in o); 265assertFalse("set" in o); 266assertEquals(undefined, o.get); 267assertEquals(undefined, o.set); 268var o = Object.create({}, { myValue: { 269 value: 10, 270 enumerable: false, 271 configurable: true, 272 writable: true 273}}); 274assertEquals(10, o.myValue); 275 276 277// Regression test for issue 1884: Invoking any of the methods for Harmony 278// maps, sets, or weak maps, with a wrong type of receiver should be throwing 279// a proper TypeError. 280var alwaysBogus = [ undefined, null, true, "x", 23, {} ]; 281var bogusReceiversTestSet = [ 282 { proto: Set.prototype, 283 funcs: [ 'add', 'has', 'delete' ], 284 receivers: alwaysBogus.concat([ new Map, new WeakMap ]), 285 }, 286 { proto: Map.prototype, 287 funcs: [ 'get', 'set', 'has', 'delete' ], 288 receivers: alwaysBogus.concat([ new Set, new WeakMap ]), 289 }, 290 { proto: WeakMap.prototype, 291 funcs: [ 'get', 'set', 'has', 'delete' ], 292 receivers: alwaysBogus.concat([ new Set, new Map ]), 293 }, 294]; 295function TestBogusReceivers(testSet) { 296 for (var i = 0; i < testSet.length; i++) { 297 var proto = testSet[i].proto; 298 var funcs = testSet[i].funcs; 299 var receivers = testSet[i].receivers; 300 for (var j = 0; j < funcs.length; j++) { 301 var func = proto[funcs[j]]; 302 for (var k = 0; k < receivers.length; k++) { 303 assertThrows(function () { func.call(receivers[k], {}) }, TypeError); 304 } 305 } 306 } 307} 308TestBogusReceivers(bogusReceiversTestSet); 309 310 311// Stress Test 312// There is a proposed stress-test available at the es-discuss mailing list 313// which cannot be reasonably automated. Check it out by hand if you like: 314// https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html