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