1// Copyright 2012 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// Flags: --expose-gc --allow-natives-syntax 29 30 31// Note: this test is superseded by harmony/collections.js. 32// IF YOU CHANGE THIS FILE, apply the same changes to harmony/collections.js! 33// TODO(rossberg): Remove once non-weak collections have caught up. 34 35// Test valid getter and setter calls on WeakSets. 36function TestValidSetCalls(m) { 37 assertDoesNotThrow(function () { m.add(new Object) }); 38 assertDoesNotThrow(function () { m.has(new Object) }); 39 assertDoesNotThrow(function () { m.delete(new Object) }); 40} 41TestValidSetCalls(new WeakSet); 42 43 44// Test valid getter and setter calls on WeakMaps 45function TestValidMapCalls(m) { 46 assertDoesNotThrow(function () { m.get(new Object) }); 47 assertDoesNotThrow(function () { m.set(new Object) }); 48 assertDoesNotThrow(function () { m.has(new Object) }); 49 assertDoesNotThrow(function () { m.delete(new Object) }); 50} 51TestValidMapCalls(new WeakMap); 52 53 54// Test invalid getter and setter calls for WeakMap 55function TestInvalidCalls(m) { 56 assertThrows(function () { m.get(undefined) }, TypeError); 57 assertThrows(function () { m.set(undefined, 0) }, TypeError); 58 assertThrows(function () { m.get(null) }, TypeError); 59 assertThrows(function () { m.set(null, 0) }, TypeError); 60 assertThrows(function () { m.get(0) }, TypeError); 61 assertThrows(function () { m.set(0, 0) }, TypeError); 62 assertThrows(function () { m.get('a-key') }, TypeError); 63 assertThrows(function () { m.set('a-key', 0) }, TypeError); 64} 65TestInvalidCalls(new WeakMap); 66 67 68// Test expected behavior for WeakSets 69function TestSet(set, key) { 70 assertFalse(set.has(key)); 71 assertSame(undefined, set.add(key)); 72 assertTrue(set.has(key)); 73 assertTrue(set.delete(key)); 74 assertFalse(set.has(key)); 75 assertFalse(set.delete(key)); 76 assertFalse(set.has(key)); 77} 78function TestSetBehavior(set) { 79 for (var i = 0; i < 20; i++) { 80 TestSet(set, new Object); 81 TestSet(set, i); 82 TestSet(set, i / 100); 83 TestSet(set, 'key-' + i); 84 } 85 var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ]; 86 for (var i = 0; i < keys.length; i++) { 87 TestSet(set, keys[i]); 88 } 89} 90TestSet(new WeakSet, new Object); 91 92 93// Test expected mapping behavior for WeakMaps 94function TestMapping(map, key, value) { 95 assertSame(undefined, map.set(key, value)); 96 assertSame(value, map.get(key)); 97} 98function TestMapBehavior1(m) { 99 TestMapping(m, new Object, 23); 100 TestMapping(m, new Object, 'the-value'); 101 TestMapping(m, new Object, new Object); 102} 103TestMapBehavior1(new WeakMap); 104 105 106// Test expected querying behavior of WeakMaps 107function TestQuery(m) { 108 var key = new Object; 109 var values = [ 'x', 0, +Infinity, -Infinity, true, false, null, undefined ]; 110 for (var i = 0; i < values.length; i++) { 111 TestMapping(m, key, values[i]); 112 assertTrue(m.has(key)); 113 assertFalse(m.has(new Object)); 114 } 115} 116TestQuery(new WeakMap); 117 118 119// Test expected deletion behavior of WeakMaps 120function TestDelete(m) { 121 var key = new Object; 122 TestMapping(m, key, 'to-be-deleted'); 123 assertTrue(m.delete(key)); 124 assertFalse(m.delete(key)); 125 assertFalse(m.delete(new Object)); 126 assertSame(m.get(key), undefined); 127} 128TestDelete(new WeakMap); 129 130 131// Test GC of WeakMaps with entry 132function TestGC1(m) { 133 var key = new Object; 134 m.set(key, 'not-collected'); 135 gc(); 136 assertSame('not-collected', m.get(key)); 137} 138TestGC1(new WeakMap); 139 140 141// Test GC of WeakMaps with chained entries 142function TestGC2(m) { 143 var head = new Object; 144 for (key = head, i = 0; i < 10; i++, key = m.get(key)) { 145 m.set(key, new Object); 146 } 147 gc(); 148 var count = 0; 149 for (key = head; key != undefined; key = m.get(key)) { 150 count++; 151 } 152 assertEquals(11, count); 153} 154TestGC2(new WeakMap); 155 156 157// Test property attribute [[Enumerable]] 158function TestEnumerable(func) { 159 function props(x) { 160 var array = []; 161 for (var p in x) array.push(p); 162 return array.sort(); 163 } 164 assertArrayEquals([], props(func)); 165 assertArrayEquals([], props(func.prototype)); 166 assertArrayEquals([], props(new func())); 167} 168TestEnumerable(WeakMap); 169TestEnumerable(WeakSet); 170 171 172// Test arbitrary properties on WeakMaps 173function TestArbitrary(m) { 174 function TestProperty(map, property, value) { 175 map[property] = value; 176 assertEquals(value, map[property]); 177 } 178 for (var i = 0; i < 20; i++) { 179 TestProperty(m, i, 'val' + i); 180 TestProperty(m, 'foo' + i, 'bar' + i); 181 } 182 TestMapping(m, new Object, 'foobar'); 183} 184TestArbitrary(new WeakMap); 185 186 187// Test direct constructor call 188assertThrows(function() { WeakMap(); }, TypeError); 189assertThrows(function() { WeakSet(); }, TypeError); 190 191 192// Test some common JavaScript idioms for WeakMaps 193var m = new WeakMap; 194assertTrue(m instanceof WeakMap); 195assertTrue(WeakMap.prototype.set instanceof Function) 196assertTrue(WeakMap.prototype.get instanceof Function) 197assertTrue(WeakMap.prototype.has instanceof Function) 198assertTrue(WeakMap.prototype.delete instanceof Function) 199assertTrue(WeakMap.prototype.clear instanceof Function) 200 201 202// Test some common JavaScript idioms for WeakSets 203var s = new WeakSet; 204assertTrue(s instanceof WeakSet); 205assertTrue(WeakSet.prototype.add instanceof Function) 206assertTrue(WeakSet.prototype.has instanceof Function) 207assertTrue(WeakSet.prototype.delete instanceof Function) 208assertTrue(WeakSet.prototype.clear instanceof Function) 209 210 211// Test class of instance and prototype. 212assertEquals("WeakMap", %_ClassOf(new WeakMap)) 213assertEquals("Object", %_ClassOf(WeakMap.prototype)) 214assertEquals("WeakSet", %_ClassOf(new WeakSet)) 215assertEquals("Object", %_ClassOf(WeakMap.prototype)) 216 217 218// Test name of constructor. 219assertEquals("WeakMap", WeakMap.name); 220assertEquals("WeakSet", WeakSet.name); 221 222 223// Test prototype property of WeakMap and WeakSet. 224function TestPrototype(C) { 225 assertTrue(C.prototype instanceof Object); 226 assertEquals({ 227 value: {}, 228 writable: false, 229 enumerable: false, 230 configurable: false 231 }, Object.getOwnPropertyDescriptor(C, "prototype")); 232} 233TestPrototype(WeakMap); 234TestPrototype(WeakSet); 235 236 237// Test constructor property of the WeakMap and WeakSet prototype. 238function TestConstructor(C) { 239 assertFalse(C === Object.prototype.constructor); 240 assertSame(C, C.prototype.constructor); 241 assertSame(C, (new C).__proto__.constructor); 242} 243TestConstructor(WeakMap); 244TestConstructor(WeakSet); 245 246 247// Test the WeakMap and WeakSet global properties themselves. 248function TestDescriptor(global, C) { 249 assertEquals({ 250 value: C, 251 writable: true, 252 enumerable: false, 253 configurable: true 254 }, Object.getOwnPropertyDescriptor(global, C.name)); 255} 256TestDescriptor(this, WeakMap); 257TestDescriptor(this, WeakSet); 258 259 260// Regression test for WeakMap prototype. 261assertTrue(WeakMap.prototype.constructor === WeakMap) 262assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype) 263 264 265// Regression test for issue 1617: The prototype of the WeakMap constructor 266// needs to be unique (i.e. different from the one of the Object constructor). 267assertFalse(WeakMap.prototype === Object.prototype); 268var o = Object.create({}); 269assertFalse("get" in o); 270assertFalse("set" in o); 271assertEquals(undefined, o.get); 272assertEquals(undefined, o.set); 273var o = Object.create({}, { myValue: { 274 value: 10, 275 enumerable: false, 276 configurable: true, 277 writable: true 278}}); 279assertEquals(10, o.myValue); 280 281 282// Regression test for issue 1884: Invoking any of the methods for Harmony 283// maps, sets, or weak maps, with a wrong type of receiver should be throwing 284// a proper TypeError. 285var alwaysBogus = [ undefined, null, true, "x", 23, {} ]; 286var bogusReceiversTestSet = [ 287 { proto: WeakMap.prototype, 288 funcs: [ 'get', 'set', 'has', 'delete' ], 289 receivers: alwaysBogus.concat([ new WeakSet ]), 290 }, 291 { proto: WeakSet.prototype, 292 funcs: [ 'add', 'has', 'delete' ], 293 receivers: alwaysBogus.concat([ new WeakMap ]), 294 }, 295]; 296function TestBogusReceivers(testSet) { 297 for (var i = 0; i < testSet.length; i++) { 298 var proto = testSet[i].proto; 299 var funcs = testSet[i].funcs; 300 var receivers = testSet[i].receivers; 301 for (var j = 0; j < funcs.length; j++) { 302 var func = proto[funcs[j]]; 303 for (var k = 0; k < receivers.length; k++) { 304 assertThrows(function () { func.call(receivers[k], {}) }, TypeError); 305 } 306 } 307 } 308} 309TestBogusReceivers(bogusReceiversTestSet); 310 311 312// Test WeakMap clear 313(function() { 314 var k = new Object(); 315 var w = new WeakMap(); 316 w.set(k, 23); 317 assertTrue(w.has(k)); 318 assertEquals(23, w.get(k)); 319 w.clear(); 320 assertFalse(w.has(k)); 321 assertEquals(undefined, w.get(k)); 322})(); 323 324 325// Test WeakSet clear 326(function() { 327 var k = new Object(); 328 var w = new WeakSet(); 329 w.add(k); 330 assertTrue(w.has(k)); 331 w.clear(); 332 assertFalse(w.has(k)); 333})(); 334