Home | History | Annotate | Download | only in harmony
      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 --expose-gc --allow-natives-syntax
     29 
     30 
     31 // Test valid getter and setter calls on Sets.
     32 function TestValidSetCalls(m) {
     33   assertDoesNotThrow(function () { m.add(new Object) });
     34   assertDoesNotThrow(function () { m.has(new Object) });
     35   assertDoesNotThrow(function () { m.delete(new Object) });
     36 }
     37 TestValidSetCalls(new Set);
     38 TestValidSetCalls(new WeakSet);
     39 
     40 
     41 // Test valid getter and setter calls on Maps and WeakMaps
     42 function TestValidMapCalls(m) {
     43   assertDoesNotThrow(function () { m.get(new Object) });
     44   assertDoesNotThrow(function () { m.set(new Object) });
     45   assertDoesNotThrow(function () { m.has(new Object) });
     46   assertDoesNotThrow(function () { m.delete(new Object) });
     47 }
     48 TestValidMapCalls(new Map);
     49 TestValidMapCalls(new WeakMap);
     50 
     51 
     52 // Test invalid getter and setter calls for WeakMap only
     53 function TestInvalidCalls(m) {
     54   assertThrows(function () { m.get(undefined) }, TypeError);
     55   assertThrows(function () { m.set(undefined, 0) }, TypeError);
     56   assertThrows(function () { m.get(null) }, TypeError);
     57   assertThrows(function () { m.set(null, 0) }, TypeError);
     58   assertThrows(function () { m.get(0) }, TypeError);
     59   assertThrows(function () { m.set(0, 0) }, TypeError);
     60   assertThrows(function () { m.get('a-key') }, TypeError);
     61   assertThrows(function () { m.set('a-key', 0) }, TypeError);
     62 }
     63 TestInvalidCalls(new WeakMap);
     64 
     65 
     66 // Test expected behavior for Sets
     67 function TestSet(set, key) {
     68   assertFalse(set.has(key));
     69   assertSame(undefined, set.add(key));
     70   assertTrue(set.has(key));
     71   assertTrue(set.delete(key));
     72   assertFalse(set.has(key));
     73   assertFalse(set.delete(key));
     74   assertFalse(set.has(key));
     75 }
     76 function TestSetBehavior(set) {
     77   for (var i = 0; i < 20; i++) {
     78     TestSet(set, new Object);
     79     TestSet(set, i);
     80     TestSet(set, i / 100);
     81     TestSet(set, 'key-' + i);
     82   }
     83   var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ];
     84   for (var i = 0; i < keys.length; i++) {
     85     TestSet(set, keys[i]);
     86   }
     87 }
     88 TestSetBehavior(new Set);
     89 TestSet(new WeakSet, new Object);
     90 
     91 
     92 // Test expected mapping behavior for Maps and WeakMaps
     93 function TestMapping(map, key, value) {
     94   assertSame(undefined, map.set(key, value));
     95   assertSame(value, map.get(key));
     96 }
     97 function TestMapBehavior1(m) {
     98   TestMapping(m, new Object, 23);
     99   TestMapping(m, new Object, 'the-value');
    100   TestMapping(m, new Object, new Object);
    101 }
    102 TestMapBehavior1(new Map);
    103 TestMapBehavior1(new WeakMap);
    104 
    105 
    106 // Test expected mapping behavior for Maps only
    107 function TestMapBehavior2(m) {
    108   for (var i = 0; i < 20; i++) {
    109     TestMapping(m, i, new Object);
    110     TestMapping(m, i / 10, new Object);
    111     TestMapping(m, 'key-' + i, new Object);
    112   }
    113   var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ];
    114   for (var i = 0; i < keys.length; i++) {
    115     TestMapping(m, keys[i], new Object);
    116   }
    117 }
    118 TestMapBehavior2(new Map);
    119 
    120 
    121 // Test expected querying behavior of Maps and WeakMaps
    122 function TestQuery(m) {
    123   var key = new Object;
    124   var values = [ 'x', 0, +Infinity, -Infinity, true, false, null, undefined ];
    125   for (var i = 0; i < values.length; i++) {
    126     TestMapping(m, key, values[i]);
    127     assertTrue(m.has(key));
    128     assertFalse(m.has(new Object));
    129   }
    130 }
    131 TestQuery(new Map);
    132 TestQuery(new WeakMap);
    133 
    134 
    135 // Test expected deletion behavior of Maps and WeakMaps
    136 function TestDelete(m) {
    137   var key = new Object;
    138   TestMapping(m, key, 'to-be-deleted');
    139   assertTrue(m.delete(key));
    140   assertFalse(m.delete(key));
    141   assertFalse(m.delete(new Object));
    142   assertSame(m.get(key), undefined);
    143 }
    144 TestDelete(new Map);
    145 TestDelete(new WeakMap);
    146 
    147 
    148 // Test GC of Maps and WeakMaps with entry
    149 function TestGC1(m) {
    150   var key = new Object;
    151   m.set(key, 'not-collected');
    152   gc();
    153   assertSame('not-collected', m.get(key));
    154 }
    155 TestGC1(new Map);
    156 TestGC1(new WeakMap);
    157 
    158 
    159 // Test GC of Maps and WeakMaps with chained entries
    160 function TestGC2(m) {
    161   var head = new Object;
    162   for (key = head, i = 0; i < 10; i++, key = m.get(key)) {
    163     m.set(key, new Object);
    164   }
    165   gc();
    166   var count = 0;
    167   for (key = head; key != undefined; key = m.get(key)) {
    168     count++;
    169   }
    170   assertEquals(11, count);
    171 }
    172 TestGC2(new Map);
    173 TestGC2(new WeakMap);
    174 
    175 
    176 // Test property attribute [[Enumerable]]
    177 function TestEnumerable(func) {
    178   function props(x) {
    179     var array = [];
    180     for (var p in x) array.push(p);
    181     return array.sort();
    182   }
    183   assertArrayEquals([], props(func));
    184   assertArrayEquals([], props(func.prototype));
    185   assertArrayEquals([], props(new func()));
    186 }
    187 TestEnumerable(Set);
    188 TestEnumerable(Map);
    189 TestEnumerable(WeakMap);
    190 TestEnumerable(WeakSet);
    191 
    192 
    193 // Test arbitrary properties on Maps and WeakMaps
    194 function TestArbitrary(m) {
    195   function TestProperty(map, property, value) {
    196     map[property] = value;
    197     assertEquals(value, map[property]);
    198   }
    199   for (var i = 0; i < 20; i++) {
    200     TestProperty(m, i, 'val' + i);
    201     TestProperty(m, 'foo' + i, 'bar' + i);
    202   }
    203   TestMapping(m, new Object, 'foobar');
    204 }
    205 TestArbitrary(new Map);
    206 TestArbitrary(new WeakMap);
    207 
    208 
    209 // Test direct constructor call
    210 assertThrows(function() { Set(); }, TypeError);
    211 assertThrows(function() { Map(); }, TypeError);
    212 assertThrows(function() { WeakMap(); }, TypeError);
    213 assertThrows(function() { WeakSet(); }, TypeError);
    214 
    215 
    216 // Test whether NaN values as keys are treated correctly.
    217 var s = new Set;
    218 assertFalse(s.has(NaN));
    219 assertFalse(s.has(NaN + 1));
    220 assertFalse(s.has(23));
    221 s.add(NaN);
    222 assertTrue(s.has(NaN));
    223 assertTrue(s.has(NaN + 1));
    224 assertFalse(s.has(23));
    225 var m = new Map;
    226 assertFalse(m.has(NaN));
    227 assertFalse(m.has(NaN + 1));
    228 assertFalse(m.has(23));
    229 m.set(NaN, 'a-value');
    230 assertTrue(m.has(NaN));
    231 assertTrue(m.has(NaN + 1));
    232 assertFalse(m.has(23));
    233 
    234 
    235 // Test some common JavaScript idioms for Sets
    236 var s = new Set;
    237 assertTrue(s instanceof Set);
    238 assertTrue(Set.prototype.add instanceof Function)
    239 assertTrue(Set.prototype.has instanceof Function)
    240 assertTrue(Set.prototype.delete instanceof Function)
    241 assertTrue(Set.prototype.clear instanceof Function)
    242 
    243 
    244 // Test some common JavaScript idioms for Maps
    245 var m = new Map;
    246 assertTrue(m instanceof Map);
    247 assertTrue(Map.prototype.set instanceof Function)
    248 assertTrue(Map.prototype.get instanceof Function)
    249 assertTrue(Map.prototype.has instanceof Function)
    250 assertTrue(Map.prototype.delete instanceof Function)
    251 assertTrue(Map.prototype.clear instanceof Function)
    252 
    253 
    254 // Test some common JavaScript idioms for WeakMaps
    255 var m = new WeakMap;
    256 assertTrue(m instanceof WeakMap);
    257 assertTrue(WeakMap.prototype.set instanceof Function)
    258 assertTrue(WeakMap.prototype.get instanceof Function)
    259 assertTrue(WeakMap.prototype.has instanceof Function)
    260 assertTrue(WeakMap.prototype.delete instanceof Function)
    261 assertTrue(WeakMap.prototype.clear instanceof Function)
    262 
    263 
    264 // Test some common JavaScript idioms for WeakSets
    265 var s = new WeakSet;
    266 assertTrue(s instanceof WeakSet);
    267 assertTrue(WeakSet.prototype.add instanceof Function)
    268 assertTrue(WeakSet.prototype.has instanceof Function)
    269 assertTrue(WeakSet.prototype.delete instanceof Function)
    270 assertTrue(WeakSet.prototype.clear instanceof Function)
    271 
    272 
    273 // Test class of instance and prototype.
    274 assertEquals("Set", %_ClassOf(new Set))
    275 assertEquals("Object", %_ClassOf(Set.prototype))
    276 assertEquals("Map", %_ClassOf(new Map))
    277 assertEquals("Object", %_ClassOf(Map.prototype))
    278 assertEquals("WeakMap", %_ClassOf(new WeakMap))
    279 assertEquals("Object", %_ClassOf(WeakMap.prototype))
    280 assertEquals("WeakSet", %_ClassOf(new WeakSet))
    281 assertEquals("Object", %_ClassOf(WeakMap.prototype))
    282 
    283 
    284 // Test name of constructor.
    285 assertEquals("Set", Set.name);
    286 assertEquals("Map", Map.name);
    287 assertEquals("WeakMap", WeakMap.name);
    288 assertEquals("WeakSet", WeakSet.name);
    289 
    290 
    291 // Test prototype property of Set, Map, WeakMap and WeakSet.
    292 function TestPrototype(C) {
    293   assertTrue(C.prototype instanceof Object);
    294   assertEquals({
    295     value: {},
    296     writable: true,  // TODO(2793): This should be non-writable.
    297     enumerable: false,
    298     configurable: false
    299   }, Object.getOwnPropertyDescriptor(C, "prototype"));
    300 }
    301 TestPrototype(Set);
    302 TestPrototype(Map);
    303 TestPrototype(WeakMap);
    304 TestPrototype(WeakSet);
    305 
    306 
    307 // Test constructor property of the Set, Map, WeakMap and WeakSet prototype.
    308 function TestConstructor(C) {
    309   assertFalse(C === Object.prototype.constructor);
    310   assertSame(C, C.prototype.constructor);
    311   assertSame(C, (new C).__proto__.constructor);
    312 }
    313 TestConstructor(Set);
    314 TestConstructor(Map);
    315 TestConstructor(WeakMap);
    316 TestConstructor(WeakSet);
    317 
    318 
    319 // Test the Set, Map, WeakMap and WeakSet global properties themselves.
    320 function TestDescriptor(global, C) {
    321   assertEquals({
    322     value: C,
    323     writable: true,
    324     enumerable: false,
    325     configurable: true
    326   }, Object.getOwnPropertyDescriptor(global, C.name));
    327 }
    328 TestDescriptor(this, Set);
    329 TestDescriptor(this, Map);
    330 TestDescriptor(this, WeakMap);
    331 TestDescriptor(this, WeakSet);
    332 
    333 
    334 // Regression test for WeakMap prototype.
    335 assertTrue(WeakMap.prototype.constructor === WeakMap)
    336 assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype)
    337 
    338 
    339 // Regression test for issue 1617: The prototype of the WeakMap constructor
    340 // needs to be unique (i.e. different from the one of the Object constructor).
    341 assertFalse(WeakMap.prototype === Object.prototype);
    342 var o = Object.create({});
    343 assertFalse("get" in o);
    344 assertFalse("set" in o);
    345 assertEquals(undefined, o.get);
    346 assertEquals(undefined, o.set);
    347 var o = Object.create({}, { myValue: {
    348   value: 10,
    349   enumerable: false,
    350   configurable: true,
    351   writable: true
    352 }});
    353 assertEquals(10, o.myValue);
    354 
    355 
    356 // Regression test for issue 1884: Invoking any of the methods for Harmony
    357 // maps, sets, or weak maps, with a wrong type of receiver should be throwing
    358 // a proper TypeError.
    359 var alwaysBogus = [ undefined, null, true, "x", 23, {} ];
    360 var bogusReceiversTestSet = [
    361   { proto: Set.prototype,
    362     funcs: [ 'add', 'has', 'delete' ],
    363     receivers: alwaysBogus.concat([ new Map, new WeakMap, new WeakSet ]),
    364   },
    365   { proto: Map.prototype,
    366     funcs: [ 'get', 'set', 'has', 'delete' ],
    367     receivers: alwaysBogus.concat([ new Set, new WeakMap, new WeakSet ]),
    368   },
    369   { proto: WeakMap.prototype,
    370     funcs: [ 'get', 'set', 'has', 'delete' ],
    371     receivers: alwaysBogus.concat([ new Set, new Map, new WeakSet ]),
    372   },
    373   { proto: WeakSet.prototype,
    374     funcs: [ 'add', 'has', 'delete' ],
    375     receivers: alwaysBogus.concat([ new Set, new Map, new WeakMap ]),
    376   },
    377 ];
    378 function TestBogusReceivers(testSet) {
    379   for (var i = 0; i < testSet.length; i++) {
    380     var proto = testSet[i].proto;
    381     var funcs = testSet[i].funcs;
    382     var receivers = testSet[i].receivers;
    383     for (var j = 0; j < funcs.length; j++) {
    384       var func = proto[funcs[j]];
    385       for (var k = 0; k < receivers.length; k++) {
    386         assertThrows(function () { func.call(receivers[k], {}) }, TypeError);
    387       }
    388     }
    389   }
    390 }
    391 TestBogusReceivers(bogusReceiversTestSet);
    392 
    393 
    394 // Stress Test
    395 // There is a proposed stress-test available at the es-discuss mailing list
    396 // which cannot be reasonably automated.  Check it out by hand if you like:
    397 // https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html
    398 
    399 
    400 // Set and Map size getters
    401 var setSizeDescriptor = Object.getOwnPropertyDescriptor(Set.prototype, 'size');
    402 assertEquals(undefined, setSizeDescriptor.value);
    403 assertEquals(undefined, setSizeDescriptor.set);
    404 assertTrue(setSizeDescriptor.get instanceof Function);
    405 assertEquals(undefined, setSizeDescriptor.get.prototype);
    406 assertFalse(setSizeDescriptor.enumerable);
    407 assertTrue(setSizeDescriptor.configurable);
    408 
    409 var s = new Set();
    410 assertFalse(s.hasOwnProperty('size'));
    411 for (var i = 0; i < 10; i++) {
    412   assertEquals(i, s.size);
    413   s.add(i);
    414 }
    415 for (var i = 9; i >= 0; i--) {
    416   s.delete(i);
    417   assertEquals(i, s.size);
    418 }
    419 
    420 
    421 var mapSizeDescriptor = Object.getOwnPropertyDescriptor(Map.prototype, 'size');
    422 assertEquals(undefined, mapSizeDescriptor.value);
    423 assertEquals(undefined, mapSizeDescriptor.set);
    424 assertTrue(mapSizeDescriptor.get instanceof Function);
    425 assertEquals(undefined, mapSizeDescriptor.get.prototype);
    426 assertFalse(mapSizeDescriptor.enumerable);
    427 assertTrue(mapSizeDescriptor.configurable);
    428 
    429 var m = new Map();
    430 assertFalse(m.hasOwnProperty('size'));
    431 for (var i = 0; i < 10; i++) {
    432   assertEquals(i, m.size);
    433   m.set(i, i);
    434 }
    435 for (var i = 9; i >= 0; i--) {
    436   m.delete(i);
    437   assertEquals(i, m.size);
    438 }
    439 
    440 
    441 // Test Set clear
    442 (function() {
    443   var s = new Set();
    444   s.add(42);
    445   assertTrue(s.has(42));
    446   assertEquals(1, s.size);
    447   s.clear();
    448   assertFalse(s.has(42));
    449   assertEquals(0, s.size);
    450 })();
    451 
    452 
    453 // Test Map clear
    454 (function() {
    455   var m = new Map();
    456   m.set(42, true);
    457   assertTrue(m.has(42));
    458   assertEquals(1, m.size);
    459   m.clear();
    460   assertFalse(m.has(42));
    461   assertEquals(0, m.size);
    462 })();
    463 
    464 
    465 // Test WeakMap clear
    466 (function() {
    467   var k = new Object();
    468   var w = new WeakMap();
    469   w.set(k, 23);
    470   assertTrue(w.has(k));
    471   assertEquals(23, w.get(k));
    472   w.clear();
    473   assertFalse(w.has(k));
    474   assertEquals(undefined, w.get(k));
    475 })();
    476 
    477 
    478 // Test WeakSet clear
    479 (function() {
    480   var k = new Object();
    481   var w = new WeakSet();
    482   w.add(k);
    483   assertTrue(w.has(k));
    484   w.clear();
    485   assertFalse(w.has(k));
    486 })();