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