blob: 3981797a7c91a0b2456ab8d185778939a7df0a65 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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})();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100676
677
678(function testUnscopable() {
679 assertTrue(Array.prototype[Symbol.unscopables].includes);
680})();