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