Home | History | Annotate | Download | only in es7
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Largely ported from
      6 // https://github.com/tc39/Array.prototype.includes/tree/master/test
      7 // using https://www.npmjs.org/package/test262-to-mjsunit with further edits
      8 
      9 
     10 // Array.prototype.includes sees a new element added by a getter that is hit
     11 // during iteration
     12 (function() {
     13   var arrayLike = {
     14     length: 5,
     15     0: "a",
     16 
     17     get 1() {
     18       this[2] = "c";
     19       return "b";
     20     }
     21   };
     22 
     23   assertTrue(Array.prototype.includes.call(arrayLike, "c"));
     24 })();
     25 
     26 
     27 // Array.prototype.includes works on array-like objects
     28 (function() {
     29   var arrayLike1 = {
     30     length: 5,
     31     0: "a",
     32     1: "b"
     33   };
     34 
     35   assertTrue(Array.prototype.includes.call(arrayLike1, "a"));
     36   assertFalse(Array.prototype.includes.call(arrayLike1, "c"));
     37 
     38   var arrayLike2 = {
     39     length: 2,
     40     0: "a",
     41     1: "b",
     42     2: "c"
     43   };
     44 
     45   assertTrue(Array.prototype.includes.call(arrayLike2, "b"));
     46   assertFalse(Array.prototype.includes.call(arrayLike2, "c"));
     47 })();
     48 
     49 
     50 // Array.prototype.includes should fail if used on a null or undefined this
     51 (function() {
     52   assertThrows(function() {
     53     Array.prototype.includes.call(null, "a");
     54   }, TypeError);
     55 
     56   assertThrows(function() {
     57     Array.prototype.includes.call(undefined, "a");
     58   }, TypeError);
     59 })();
     60 
     61 
     62 // Array.prototype.includes should terminate if getting an index throws an
     63 // exception
     64 (function() {
     65   function Test262Error() {}
     66 
     67   var trappedZero = {
     68     length: 2,
     69 
     70     get 0() {
     71       throw new Test262Error();
     72     },
     73 
     74     get 1() {
     75       assertUnreachable("Should not try to get the first element");
     76     }
     77   };
     78 
     79   assertThrows(function() {
     80     Array.prototype.includes.call(trappedZero, "a");
     81   }, Test262Error);
     82 })();
     83 
     84 
     85 // Array.prototype.includes should terminate if ToNumber ends up being called on
     86 // a symbol fromIndex
     87 (function() {
     88   var trappedZero = {
     89     length: 1,
     90 
     91     get 0() {
     92       assertUnreachable("Should not try to get the zeroth element");
     93     }
     94   };
     95 
     96   assertThrows(function() {
     97     Array.prototype.includes.call(trappedZero, "a", Symbol());
     98   }, TypeError);
     99 })();
    100 
    101 
    102 // Array.prototype.includes should terminate if an exception occurs converting
    103 // the fromIndex to a number
    104 (function() {
    105   function Test262Error() {}
    106 
    107   var fromIndex = {
    108     valueOf: function() {
    109       throw new Test262Error();
    110     }
    111   };
    112 
    113   var trappedZero = {
    114     length: 1,
    115 
    116     get 0() {
    117       assertUnreachable("Should not try to get the zeroth element");
    118     }
    119   };
    120 
    121   assertThrows(function() {
    122     Array.prototype.includes.call(trappedZero, "a", fromIndex);
    123   }, Test262Error);
    124 })();
    125 
    126 
    127 // Array.prototype.includes should terminate if an exception occurs getting the
    128 // length
    129 (function() {
    130   function Test262Error() {}
    131 
    132   var fromIndexTrap = {
    133     valueOf: function() {
    134       assertUnreachable("Should not try to call ToInteger on valueOf");
    135     }
    136   };
    137 
    138   var throwingLength = {
    139     get length() {
    140       throw new Test262Error();
    141     },
    142 
    143     get 0() {
    144       assertUnreachable("Should not try to get the zeroth element");
    145     }
    146   };
    147 
    148   assertThrows(function() {
    149     Array.prototype.includes.call(throwingLength, "a", fromIndexTrap);
    150   }, Test262Error);
    151 })();
    152 
    153 
    154 // Array.prototype.includes should terminate if ToLength ends up being called on
    155 // a symbol length
    156 (function() {
    157   var fromIndexTrap = {
    158     valueOf: function() {
    159       assertUnreachable("Should not try to call ToInteger on valueOf");
    160     }
    161   };
    162 
    163   var badLength = {
    164     length: Symbol(),
    165 
    166     get 0() {
    167       assertUnreachable("Should not try to get the zeroth element");
    168     }
    169   };
    170 
    171   assertThrows(function() {
    172     Array.prototype.includes.call(badLength, "a", fromIndexTrap);
    173   }, TypeError);
    174 })();
    175 
    176 
    177 // Array.prototype.includes should terminate if an exception occurs converting
    178 // the length to a number
    179 (function() {
    180   function Test262Error() {}
    181 
    182   var fromIndexTrap = {
    183     valueOf: function() {
    184       assertUnreachable("Should not try to call ToInteger on valueOf");
    185     }
    186   };
    187 
    188   var badLength = {
    189     length: {
    190       valueOf: function() {
    191         throw new Test262Error();
    192       }
    193     },
    194 
    195     get 0() {
    196       assertUnreachable("Should not try to get the zeroth element");
    197     }
    198   };
    199 
    200   assertThrows(function() {
    201     Array.prototype.includes.call(badLength, "a", fromIndexTrap);
    202   }, Test262Error);
    203 })();
    204 
    205 
    206 // Array.prototype.includes should search the whole array, as the optional
    207 // second argument fromIndex defaults to 0
    208 (function() {
    209   assertTrue([10, 11].includes(10));
    210   assertTrue([10, 11].includes(11));
    211 
    212   var arrayLike = {
    213     length: 2,
    214 
    215     get 0() {
    216       return "1";
    217     },
    218 
    219     get 1() {
    220       return "2";
    221     }
    222   };
    223 
    224   assertTrue(Array.prototype.includes.call(arrayLike, "1"));
    225   assertTrue(Array.prototype.includes.call(arrayLike, "2"));
    226 })();
    227 
    228 
    229 // Array.prototype.includes returns false if fromIndex is greater or equal to
    230 // the length of the array
    231 (function() {
    232   assertFalse([1, 2].includes(2, 3));
    233   assertFalse([1, 2].includes(2, 2));
    234 
    235   var arrayLikeWithTrap = {
    236     length: 2,
    237 
    238     get 0() {
    239       assertUnreachable("Getter for 0 was called");
    240     },
    241 
    242     get 1() {
    243       assertUnreachable("Getter for 1 was called");
    244     }
    245   };
    246 
    247   assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, "c", 2));
    248   assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, "c", 3));
    249 })();
    250 
    251 
    252 // Array.prototype.includes searches the whole array if the computed index from
    253 // the given negative fromIndex argument is less than 0
    254 (function() {
    255   assertTrue([1, 3].includes(1, -4));
    256   assertTrue([1, 3].includes(3, -4));
    257 
    258   var arrayLike = {
    259     length: 2,
    260     0: "a",
    261 
    262     get 1() {
    263       return "b";
    264     },
    265 
    266     get "-1"() {
    267       assertUnreachable("Should not try to get the element at index -1");
    268     }
    269   };
    270 
    271   assertTrue(Array.prototype.includes.call(arrayLike, "a", -4));
    272   assertTrue(Array.prototype.includes.call(arrayLike, "b", -4));
    273 })();
    274 
    275 
    276 // Array.prototype.includes should use a negative value as the offset from the
    277 // end of the array to compute fromIndex
    278 (function() {
    279   assertTrue([12, 13].includes(13, -1));
    280   assertFalse([12, 13].includes(12, -1));
    281   assertTrue([12, 13].includes(12, -2));
    282 
    283   var arrayLike = {
    284     length: 2,
    285 
    286     get 0() {
    287       return "a";
    288     },
    289 
    290     get 1() {
    291       return "b";
    292     }
    293   };
    294 
    295   assertTrue(Array.prototype.includes.call(arrayLike, "b", -1));
    296   assertFalse(Array.prototype.includes.call(arrayLike, "a", -1));
    297   assertTrue(Array.prototype.includes.call(arrayLike, "a", -2));
    298 })();
    299 
    300 
    301 // Array.prototype.includes converts its fromIndex parameter to an integer
    302 (function() {
    303   assertFalse(["a", "b"].includes("a", 2.3));
    304 
    305   var arrayLikeWithTraps = {
    306     length: 2,
    307 
    308     get 0() {
    309       assertUnreachable("Getter for 0 was called");
    310     },
    311 
    312     get 1() {
    313       assertUnreachable("Getter for 1 was called");
    314     }
    315   };
    316 
    317   assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "c", 2.1));
    318   assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "c", +Infinity));
    319   assertTrue(["a", "b", "c"].includes("a", -Infinity));
    320   assertTrue(["a", "b", "c"].includes("c", 2.9));
    321   assertTrue(["a", "b", "c"].includes("c", NaN));
    322 
    323   var arrayLikeWithTrapAfterZero = {
    324     length: 2,
    325 
    326     get 0() {
    327       return "a";
    328     },
    329 
    330     get 1() {
    331       assertUnreachable("Getter for 1 was called");
    332     }
    333   };
    334 
    335   assertTrue(Array.prototype.includes.call(arrayLikeWithTrapAfterZero, "a", NaN));
    336 
    337   var numberLike = {
    338     valueOf: function() {
    339       return 2;
    340     }
    341   };
    342 
    343   assertFalse(["a", "b", "c"].includes("a", numberLike));
    344   assertFalse(["a", "b", "c"].includes("a", "2"));
    345   assertTrue(["a", "b", "c"].includes("c", numberLike));
    346   assertTrue(["a", "b", "c"].includes("c", "2"));
    347 })();
    348 
    349 
    350 // Array.prototype.includes should have length 1
    351 (function() {
    352   assertEquals(1, Array.prototype.includes.length);
    353 })();
    354 
    355 
    356 // Array.prototype.includes should have name property with value 'includes'
    357 (function() {
    358   assertEquals("includes", Array.prototype.includes.name);
    359 })();
    360 
    361 
    362 // !!! Test failed to convert:
    363 // Cannot convert tests with includes.
    364 // !!!
    365 
    366 
    367 // Array.prototype.includes does not skip holes; if the array has a prototype it
    368 // gets from that
    369 (function() {
    370   var holesEverywhere = [,,,];
    371 
    372   holesEverywhere.__proto__ = {
    373     1: "a"
    374   };
    375 
    376   holesEverywhere.__proto__.__proto__ = Array.prototype;
    377   assertTrue(holesEverywhere.includes("a"));
    378   var oneHole = ["a", "b",, "d"];
    379 
    380   oneHole.__proto__ = {
    381     get 2() {
    382       return "c";
    383     }
    384   };
    385 
    386   assertTrue(Array.prototype.includes.call(oneHole, "c"));
    387 })();
    388 
    389 
    390 // Array.prototype.includes does not skip holes; instead it treates them as
    391 // undefined
    392 (function() {
    393   assertTrue([,,,].includes(undefined));
    394   assertTrue(["a", "b",, "d"].includes(undefined));
    395 })();
    396 
    397 
    398 // Array.prototype.includes gets length property from the prototype if it's
    399 // available
    400 (function() {
    401   var proto = {
    402     length: 1
    403   };
    404 
    405   var arrayLike = Object.create(proto);
    406   arrayLike[0] = "a";
    407 
    408   Object.defineProperty(arrayLike, "1", {
    409     get: function() {
    410       assertUnreachable("Getter for 1 was called");
    411     }
    412   });
    413 
    414   assertTrue(Array.prototype.includes.call(arrayLike, "a"));
    415 })();
    416 
    417 
    418 // Array.prototype.includes treats a missing length property as zero
    419 (function() {
    420   var arrayLikeWithTraps = {
    421     get 0() {
    422       assertUnreachable("Getter for 0 was called");
    423     },
    424 
    425     get 1() {
    426       assertUnreachable("Getter for 1 was called");
    427     }
    428   };
    429 
    430   assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "a"));
    431 })();
    432 
    433 
    434 // Array.prototype.includes should always return false on negative-length
    435 // objects
    436 (function() {
    437   assertFalse(Array.prototype.includes.call({
    438     length: -1
    439   }, 2));
    440 
    441   assertFalse(Array.prototype.includes.call({
    442     length: -2
    443   }));
    444 
    445   assertFalse(Array.prototype.includes.call({
    446     length: -Infinity
    447   }, undefined));
    448 
    449   assertFalse(Array.prototype.includes.call({
    450     length: -Math.pow(2, 53)
    451   }, NaN));
    452 
    453   assertFalse(Array.prototype.includes.call({
    454     length: -1,
    455     "-1": 2
    456   }, 2));
    457 
    458   assertFalse(Array.prototype.includes.call({
    459     length: -3,
    460     "-1": 2
    461   }, 2));
    462 
    463   assertFalse(Array.prototype.includes.call({
    464     length: -Infinity,
    465     "-1": 2
    466   }, 2));
    467 
    468   var arrayLikeWithTrap = {
    469     length: -1,
    470 
    471     get 0() {
    472       assertUnreachable("Getter for 0 was called");
    473     }
    474   };
    475 
    476   assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, 2));
    477 })();
    478 
    479 
    480 // Array.prototype.includes should clamp positive lengths to 2^53 - 1
    481 (function() {
    482   var fromIndexForLargeIndexTests = 9007199254740990;
    483 
    484   assertFalse(Array.prototype.includes.call({
    485     length: 1
    486   }, 2));
    487 
    488   assertTrue(Array.prototype.includes.call({
    489     length: 1,
    490     0: "a"
    491   }, "a"));
    492 
    493   assertTrue(Array.prototype.includes.call({
    494     length: +Infinity,
    495     0: "a"
    496   }, "a"));
    497 
    498   assertFalse(Array.prototype.includes.call({
    499     length: +Infinity
    500   }, "a", fromIndexForLargeIndexTests));
    501 
    502   var arrayLikeWithTrap = {
    503     length: +Infinity,
    504 
    505     get 9007199254740992() {
    506       assertUnreachable("Getter for 9007199254740992 (i.e. 2^53) was called");
    507     },
    508 
    509     "9007199254740993": "a"
    510   };
    511 
    512   assertFalse(
    513     Array.prototype.includes.call(arrayLikeWithTrap, "a", fromIndexForLargeIndexTests)
    514   );
    515 
    516   var arrayLikeWithTooBigLength = {
    517     length: 9007199254740996,
    518     "9007199254740992": "a"
    519   };
    520 
    521   assertFalse(
    522     Array.prototype.includes.call(arrayLikeWithTooBigLength, "a", fromIndexForLargeIndexTests)
    523   );
    524 })();
    525 
    526 
    527 // Array.prototype.includes should always return false on zero-length objects
    528 (function() {
    529   assertFalse([].includes(2));
    530   assertFalse([].includes());
    531   assertFalse([].includes(undefined));
    532   assertFalse([].includes(NaN));
    533 
    534   assertFalse(Array.prototype.includes.call({
    535     length: 0
    536   }, 2));
    537 
    538   assertFalse(Array.prototype.includes.call({
    539     length: 0
    540   }));
    541 
    542   assertFalse(Array.prototype.includes.call({
    543     length: 0
    544   }, undefined));
    545 
    546   assertFalse(Array.prototype.includes.call({
    547     length: 0
    548   }, NaN));
    549 
    550   assertFalse(Array.prototype.includes.call({
    551     length: 0,
    552     0: 2
    553   }, 2));
    554 
    555   assertFalse(Array.prototype.includes.call({
    556     length: 0,
    557     0: undefined
    558   }));
    559 
    560   assertFalse(Array.prototype.includes.call({
    561     length: 0,
    562     0: undefined
    563   }, undefined));
    564 
    565   assertFalse(Array.prototype.includes.call({
    566     length: 0,
    567     0: NaN
    568   }, NaN));
    569 
    570   var arrayLikeWithTrap = {
    571     length: 0,
    572 
    573     get 0() {
    574       assertUnreachable("Getter for 0 was called");
    575     }
    576   };
    577 
    578   Array.prototype.includes.call(arrayLikeWithTrap);
    579 
    580   var trappedFromIndex = {
    581     valueOf: function() {
    582       assertUnreachable("Should not try to convert fromIndex to a number on a zero-length array");
    583     }
    584   };
    585 
    586   [].includes("a", trappedFromIndex);
    587 
    588   Array.prototype.includes.call({
    589     length: 0
    590   }, trappedFromIndex);
    591 })();
    592 
    593 
    594 // Array.prototype.includes works on objects
    595 (function() {
    596   assertFalse(["a", "b", "c"].includes({}));
    597   assertFalse([{}, {}].includes({}));
    598   var obj = {};
    599   assertTrue([obj].includes(obj));
    600   assertFalse([obj].includes(obj, 1));
    601   assertTrue([obj, obj].includes(obj, 1));
    602 
    603   var stringyObject = {
    604     toString: function() {
    605       return "a";
    606     }
    607   };
    608 
    609   assertFalse(["a", "b", obj].includes(stringyObject));
    610 })();
    611 
    612 
    613 // Array.prototype.includes does not see an element removed by a getter that is
    614 // hit during iteration
    615 (function() {
    616   var arrayLike = {
    617     length: 5,
    618     0: "a",
    619 
    620     get 1() {
    621       delete this[2];
    622       return "b";
    623     },
    624 
    625     2: "c"
    626   };
    627 
    628   assertFalse(Array.prototype.includes.call(arrayLike, "c"));
    629 })();
    630 
    631 
    632 // Array.prototype.includes should use the SameValueZero algorithm to compare
    633 (function() {
    634   assertTrue([1, 2, 3].includes(2));
    635   assertFalse([1, 2, 3].includes(4));
    636   assertTrue([1, 2, NaN].includes(NaN));
    637   assertTrue([1, 2, -0].includes(+0));
    638   assertTrue([1, 2, -0].includes(-0));
    639   assertTrue([1, 2, +0].includes(-0));
    640   assertTrue([1, 2, +0].includes(+0));
    641   assertFalse([1, 2, -Infinity].includes(+Infinity));
    642   assertTrue([1, 2, -Infinity].includes(-Infinity));
    643   assertFalse([1, 2, +Infinity].includes(-Infinity));
    644   assertTrue([1, 2, +Infinity].includes(+Infinity));
    645 })();
    646 
    647 
    648 // Array.prototype.includes stops once it hits the length of an array-like, even
    649 // if there are more after
    650 (function() {
    651   var arrayLike = {
    652     length: 2,
    653     0: "a",
    654     1: "b",
    655 
    656     get 2() {
    657       assertUnreachable("Should not try to get the second element");
    658     }
    659   };
    660 
    661   assertFalse(Array.prototype.includes.call(arrayLike, "c"));
    662 })();
    663 
    664 
    665 // Array.prototype.includes works on typed arrays
    666 (function() {
    667   assertTrue(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 2));
    668 
    669   assertTrue(
    670     Array.prototype.includes.call(new Float32Array([2.5, 3.14, Math.PI]), 3.1415927410125732)
    671   );
    672 
    673   assertFalse(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 4));
    674   assertFalse(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 2, 2));
    675 })();
    676