array-core-test262.test.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * Portions adapted from Test262 at revision 250f204f23a9249ff204be2baec29600faae7b75:
  3. * - test/built-ins/Array/prototype/includes/samevaluezero.js
  4. * - test/built-ins/Array/prototype/includes/using-fromindex.js
  5. * - test/built-ins/Array/prototype/join/S15.4.4.5_A3.1_T1.js
  6. * - test/built-ins/Array/prototype/join/S15.4.4.5_A3.2_T1.js
  7. * - test/built-ins/Array/prototype/slice/S15.4.4.10_A1.2_T2.js
  8. * - test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T1.js
  9. * - test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T2.js
  10. * - test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T3.js
  11. * - test/built-ins/Array/prototype/indexOf/fromindex-zero-conversion.js
  12. * - test/built-ins/Array/prototype/indexOf/length-zero-returns-minus-one.js
  13. * - test/built-ins/Array/prototype/lastIndexOf/fromindex-zero-conversion.js
  14. * - test/built-ins/Array/prototype/lastIndexOf/length-zero-returns-minus-one.js
  15. * - test/built-ins/Array/prototype/at/returns-item.js
  16. * - test/built-ins/Array/prototype/at/returns-item-relative-index.js
  17. * - test/built-ins/Array/prototype/at/returns-undefined-for-out-of-range-index.js
  18. * - test/built-ins/Array/prototype/flat/null-undefined-elements.js
  19. * - test/built-ins/Array/prototype/flat/positive-infinity.js
  20. * - test/built-ins/Array/prototype/reverse/S15.4.4.8_A1_T1.js
  21. * - test/built-ins/Array/prototype/toReversed/immutable.js
  22. * - test/built-ins/Array/prototype/toReversed/zero-or-one-element.js
  23. * - test/built-ins/Array/prototype/with/immutable.js
  24. * - test/built-ins/Array/prototype/with/index-negative.js
  25. * - test/built-ins/Array/prototype/push/S15.4.4.7_A1_T1.js
  26. * - test/built-ins/Array/prototype/pop/S15.4.4.6_A1.1_T1.js
  27. * - test/built-ins/Array/prototype/shift/S15.4.4.9_A1.1_T1.js
  28. * - test/built-ins/Array/prototype/unshift/S15.4.4.13_A1_T1.js
  29. * - test/built-ins/Array/prototype/splice/S15.4.4.12_A1.1_T1.js
  30. * - test/built-ins/Array/prototype/splice/S15.4.4.12_A1.2_T1.js
  31. * - test/built-ins/Array/prototype/splice/called_with_one_argument.js
  32. * - test/built-ins/Array/prototype/toSpliced/holes-not-preserved.js
  33. * - test/built-ins/Array/prototype/toSpliced/immutable.js
  34. * - test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-undefineds.js
  35. * - test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-missing.js
  36. * - test/built-ins/Array/prototype/toSpliced/start-undefined-and-deleteCount-missing.js
  37. * - test/built-ins/Array/prototype/fill/fill-values.js
  38. * - test/built-ins/Array/prototype/fill/fill-values-custom-start-and-end.js
  39. * - test/built-ins/Array/prototype/fill/return-this.js
  40. * - test/built-ins/Array/prototype/copyWithin/non-negative-target-start-and-end.js
  41. * - test/built-ins/Array/prototype/copyWithin/return-this.js
  42. * - test/built-ins/Array/prototype/keys/iteration.js
  43. * - test/built-ins/Array/prototype/values/iteration.js
  44. * - test/built-ins/Array/prototype/entries/iteration.js
  45. * - test/built-ins/Array/isArray/15.4.3.2-0-3.js
  46. * - test/built-ins/Array/isArray/15.4.3.2-0-4.js
  47. * - test/built-ins/Array/from/from-array.js
  48. * - test/built-ins/Array/from/from-string.js
  49. * - test/built-ins/Array/from/array-like-has-length-but-no-indexes-with-values.js
  50. * - test/built-ins/Array/of/creates-a-new-array-from-arguments.js
  51. *
  52. * Copyright (C) 2015 André Bargull. All rights reserved.
  53. * Copyright (C) 2015 the V8 project authors. All rights reserved.
  54. * Copyright (C) 2016 the V8 project authors. All rights reserved.
  55. * Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
  56. * Copyright (C) 2020 Alexey Shvayka. All rights reserved.
  57. * Copyright (C) 2020 Rick Waldron. All rights reserved.
  58. * Copyright (C) 2021 Igalia, S.L. All rights reserved.
  59. * Copyright (c) 2012 Ecma International. All rights reserved.
  60. * Copyright (c) 2014 Hank Yates. All rights reserved.
  61. * Copyright (c) 2015 the V8 project authors. All rights reserved.
  62. * Copyright (c) 2021 Rick Waldron. All rights reserved.
  63. * Copyright 2009 the Sputnik authors. All rights reserved.
  64. * Copyright 2015 Microsoft Corporation. All rights reserved.
  65. * Copyright 2016 The V8 project authors. All rights reserved.
  66. * Test262 portions are governed by the BSD license in LICENSE.test262.
  67. * The toSpliced hole case omits the source test's inherited Array.prototype element because CodeMode does not expose
  68. * prototype mutation; it retains the source test's hole-densification assertions.
  69. */
  70. import { describe, expect, test } from "bun:test"
  71. import { Effect } from "effect"
  72. import { CodeMode } from "../src/index.js"
  73. const value = async (code: string) => {
  74. const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} }))
  75. if (!result.ok) throw new Error(`expected success, got ${result.error.kind}: ${result.error.message}`)
  76. return result.value
  77. }
  78. const cases = [
  79. {
  80. path: "test/built-ins/Array/prototype/includes/samevaluezero.js",
  81. code: `const input = [42, 0, 1, NaN]; return [input.includes(42), input.includes("42"), input.includes([42]), input.includes(true), input.includes(NaN), input.includes(0), input.includes(-0), input.includes(null), input.includes("")]`,
  82. expected: [true, false, false, false, true, true, true, false, false],
  83. },
  84. {
  85. path: "test/built-ins/Array/prototype/includes/using-fromindex.js",
  86. code: `const input = ["a", "b", "c"]; return [input.includes("a", 0), input.includes("a", 1), input.includes("a", -4), input.includes("a", -3), input.includes("a", -2), input.includes("b", 0), input.includes("b", 1), input.includes("b", 2), input.includes("b", -3), input.includes("b", -2), input.includes("b", -1), input.includes("c", 0), input.includes("c", 2), input.includes("c", 3), input.includes("c", -3), input.includes("c", -1)]`,
  87. expected: [true, false, true, true, false, true, true, false, true, true, false, true, true, false, true, true],
  88. },
  89. {
  90. path: "test/built-ins/Array/prototype/join/S15.4.4.5_A3.1_T1.js",
  91. code: `return [[0, 1, 2, 3].join("&"), [0, 1, 2, 3].join("")]`,
  92. expected: ["0&1&2&3", "0123"],
  93. },
  94. {
  95. path: "test/built-ins/Array/prototype/join/S15.4.4.5_A3.2_T1.js",
  96. code: `return [
  97. ["", "", ""].join(""),
  98. ["&", "&", "&"].join("&"),
  99. [true, true, true].join(),
  100. [null, null, null].join(),
  101. [undefined, undefined, undefined].join(),
  102. [Infinity, Infinity, Infinity].join(),
  103. [NaN, NaN, NaN].join(),
  104. ]`,
  105. expected: ["", "&&&&&", "true,true,true", ",,", ",,", "Infinity,Infinity,Infinity", "NaN,NaN,NaN"],
  106. },
  107. {
  108. path: "test/built-ins/Array/prototype/slice/S15.4.4.10_A1.2_T2.js",
  109. code: `return [0, 1, 2, 3, 4].slice(-1, 5)`,
  110. expected: [4],
  111. },
  112. {
  113. path: "test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T1.js",
  114. code: `return [].concat([0, 1], [2, 3, 4])`,
  115. expected: [0, 1, 2, 3, 4],
  116. },
  117. {
  118. path: "test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T2.js",
  119. code: `const object = { value: 1 }; const result = [0].concat(object, [1, 2], -1, true, "NaN"); return [result, result[1] === object]`,
  120. expected: [[0, { value: 1 }, 1, 2, -1, true, "NaN"], true],
  121. },
  122. {
  123. path: "test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T3.js",
  124. code: `const input = [0, 1]; const result = input.concat(); return [result, result !== input]`,
  125. expected: [[0, 1], true],
  126. },
  127. {
  128. path: "test/built-ins/Array/prototype/indexOf/fromindex-zero-conversion.js",
  129. code: `const result = [true].indexOf(true, -0); return [result, 1 / result === Infinity]`,
  130. expected: [0, true],
  131. },
  132. {
  133. path: "test/built-ins/Array/prototype/indexOf/length-zero-returns-minus-one.js",
  134. code: `return [].indexOf(1)`,
  135. expected: -1,
  136. },
  137. {
  138. path: "test/built-ins/Array/prototype/lastIndexOf/fromindex-zero-conversion.js",
  139. code: `const result = [true].lastIndexOf(true, -0); return [result, 1 / result === Infinity]`,
  140. expected: [0, true],
  141. },
  142. {
  143. path: "test/built-ins/Array/prototype/lastIndexOf/length-zero-returns-minus-one.js",
  144. code: `return [].lastIndexOf(1)`,
  145. expected: -1,
  146. },
  147. {
  148. path: "test/built-ins/Array/prototype/at/returns-item.js",
  149. code: `const input = [1, 2, 3, 4, undefined, 5]; return [input.at(0), input.at(1), input.at(2), input.at(3), input.at(4) === undefined, input.at(5)]`,
  150. expected: [1, 2, 3, 4, true, 5],
  151. },
  152. {
  153. path: "test/built-ins/Array/prototype/at/returns-item-relative-index.js",
  154. code: `const input = [1, 2, 3, 4, undefined, 5]; return [input.at(0), input.at(-1), input.at(-2) === undefined, input.at(-3), input.at(-4)]`,
  155. expected: [1, 5, true, 4, 3],
  156. },
  157. {
  158. path: "test/built-ins/Array/prototype/at/returns-undefined-for-out-of-range-index.js",
  159. code: `const input = []; return [input.at(-2) === undefined, input.at(0) === undefined, input.at(1) === undefined]`,
  160. expected: [true, true, true],
  161. },
  162. {
  163. path: "test/built-ins/Array/prototype/flat/null-undefined-elements.js",
  164. code: `const result = [1, [null, [undefined]]].flat(2); return [result.length, result[0], result[1] === null, result[2] === undefined]`,
  165. expected: [3, 1, true, true],
  166. },
  167. {
  168. path: "test/built-ins/Array/prototype/flat/positive-infinity.js",
  169. code: `return [1, [2, [3, [4]]]].flat(Infinity)`,
  170. expected: [1, 2, 3, 4],
  171. },
  172. {
  173. path: "test/built-ins/Array/prototype/reverse/S15.4.4.8_A1_T1.js",
  174. code: `const empty = []; const one = [1]; const input = [1, 2]; const emptyResult = empty.reverse(); const oneResult = one.reverse(); const result = input.reverse(); return [emptyResult === empty, oneResult === one, result === input, input]`,
  175. expected: [true, true, true, [2, 1]],
  176. },
  177. {
  178. path: "test/built-ins/Array/prototype/toReversed/immutable.js",
  179. code: `const input = [0, 1, 2]; const result = input.toReversed(); return [input, result !== input]`,
  180. expected: [[0, 1, 2], true],
  181. },
  182. {
  183. path: "test/built-ins/Array/prototype/toReversed/zero-or-one-element.js",
  184. code: `const zero = []; const one = [1]; const zeroResult = zero.toReversed(); const oneResult = one.toReversed(); return [zeroResult, oneResult, zeroResult !== zero, oneResult !== one]`,
  185. expected: [[], [1], true, true],
  186. },
  187. {
  188. path: "test/built-ins/Array/prototype/with/immutable.js",
  189. code: `const input = [0, 1, 2]; const result = input.with(1, 3); return [input, result !== input, input.with(1, 1) !== input]`,
  190. expected: [[0, 1, 2], true, true],
  191. },
  192. {
  193. path: "test/built-ins/Array/prototype/with/index-negative.js",
  194. code: `const input = [0, 1, 2]; return [input.with(-1, 4), input.with(-3, 4)]`,
  195. expected: [
  196. [0, 1, 4],
  197. [4, 1, 2],
  198. ],
  199. },
  200. {
  201. path: "test/built-ins/Array/prototype/push/S15.4.4.7_A1_T1.js",
  202. code: `const input = []; return [input.push(1), input.push(), input.push(-1), input]`,
  203. expected: [1, 1, 2, [1, -1]],
  204. },
  205. {
  206. path: "test/built-ins/Array/prototype/pop/S15.4.4.6_A1.1_T1.js",
  207. code: `const input = []; return [input.pop() === undefined, input.length]`,
  208. expected: [true, 0],
  209. },
  210. {
  211. path: "test/built-ins/Array/prototype/shift/S15.4.4.9_A1.1_T1.js",
  212. code: `const input = []; return [input.shift() === undefined, input.length]`,
  213. expected: [true, 0],
  214. },
  215. {
  216. path: "test/built-ins/Array/prototype/unshift/S15.4.4.13_A1_T1.js",
  217. code: `const input = []; return [input.unshift(1), input[0], input.unshift(), input.unshift(-1), input]`,
  218. expected: [1, 1, 1, 2, [-1, 1]],
  219. },
  220. {
  221. path: "test/built-ins/Array/prototype/splice/S15.4.4.12_A1.1_T1.js",
  222. code: `const input = [0, 1, 2, 3]; const removed = input.splice(0, 3); return [input, removed]`,
  223. expected: [[3], [0, 1, 2]],
  224. },
  225. {
  226. path: "test/built-ins/Array/prototype/splice/S15.4.4.12_A1.2_T1.js",
  227. code: `const input = [0, 1]; const removed = input.splice(-2, -1); return [input, removed]`,
  228. expected: [[0, 1], []],
  229. },
  230. {
  231. path: "test/built-ins/Array/prototype/splice/called_with_one_argument.js",
  232. code: `const input = ["first", "second", "third"]; const removed = input.splice(1); return [input, removed]`,
  233. expected: [["first"], ["second", "third"]],
  234. },
  235. {
  236. path: "test/built-ins/Array/prototype/toSpliced/immutable.js",
  237. code: `const input = [2, 0, 1]; const inserted = input.toSpliced(0, 0, -1); const replaced = input.toSpliced(0, 1, -1); return [input, inserted, replaced, inserted !== input, replaced !== input]`,
  238. expected: [[2, 0, 1], [-1, 2, 0, 1], [-1, 0, 1], true, true],
  239. },
  240. {
  241. path: "test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-missing.js",
  242. code: `const input = ["first", "second", "third"]; const result = input.toSpliced(); return [result, result !== input]`,
  243. expected: [["first", "second", "third"], true],
  244. },
  245. {
  246. path: "test/built-ins/Array/prototype/toSpliced/start-undefined-and-deleteCount-missing.js",
  247. code: `return ["first", "second", "third"].toSpliced(undefined)`,
  248. expected: [],
  249. },
  250. {
  251. path: "test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-undefineds.js",
  252. code: `const input = ["first", "second", "third"]; const result = input.toSpliced(undefined, undefined); return [result, result !== input]`,
  253. expected: [["first", "second", "third"], true],
  254. },
  255. {
  256. path: "test/built-ins/Array/prototype/toSpliced/holes-not-preserved.js",
  257. code: `const input = [0, , 2, , 4]; const result = input.toSpliced(0, 0, -1); return [result, 2 in result, 4 in result]`,
  258. expected: [[-1, 0, null, 2, null, 4], true, true],
  259. },
  260. {
  261. path: "test/built-ins/Array/prototype/fill/fill-values-custom-start-and-end.js",
  262. code: `const input = [0, 0, 0, 0, 0]; input.fill(8, -3, 4); const sparse = []; sparse[4] = 0; sparse.fill(8, 1, 3); return [[0, 0, 0].fill(8, 1, 2), input, [0, 0, 0, 0, 0].fill(8, -2, -1), [0, 0, 0, 0, 0].fill(8, -1, -3), [0 in sparse, sparse[1], sparse[2], 3 in sparse, sparse[4]]]`,
  263. expected: [
  264. [0, 8, 0],
  265. [0, 0, 8, 8, 0],
  266. [0, 0, 0, 8, 0],
  267. [0, 0, 0, 0, 0],
  268. [false, 8, 8, false, 0],
  269. ],
  270. },
  271. {
  272. path: "test/built-ins/Array/prototype/fill/return-this.js",
  273. code: `const input = []; return input.fill(1) === input`,
  274. expected: true,
  275. },
  276. {
  277. path: "test/built-ins/Array/prototype/fill/fill-values.js",
  278. code: `const omitted = [0, 0].fill(); return [[].fill(8), omitted.map((value) => value === undefined), [0, 0, 0].fill(8)]`,
  279. expected: [[], [true, true], [8, 8, 8]],
  280. },
  281. {
  282. path: "test/built-ins/Array/prototype/copyWithin/non-negative-target-start-and-end.js",
  283. code: `return [[0, 1, 2, 3].copyWithin(0, 0, 0), [0, 1, 2, 3].copyWithin(0, 0, 2), [0, 1, 2, 3].copyWithin(0, 1, 2), [0, 1, 2, 3].copyWithin(1, 0, 2), [0, 1, 2, 3, 4, 5].copyWithin(1, 3, 5)]`,
  284. expected: [
  285. [0, 1, 2, 3],
  286. [0, 1, 2, 3],
  287. [1, 1, 2, 3],
  288. [0, 0, 1, 3],
  289. [0, 3, 4, 3, 4, 5],
  290. ],
  291. },
  292. {
  293. path: "test/built-ins/Array/prototype/copyWithin/return-this.js",
  294. code: `const input = [0, 1, 2, 3]; const result = input.copyWithin(1, 0, 2); return [input, result === input]`,
  295. expected: [[0, 0, 1, 3], true],
  296. },
  297. {
  298. path: "test/built-ins/Array/prototype/keys/iteration.js",
  299. code: `return ["a", "b", "c"].keys()`,
  300. expected: [0, 1, 2],
  301. },
  302. {
  303. path: "test/built-ins/Array/prototype/values/iteration.js",
  304. code: `return ["a", "b", "c"].values()`,
  305. expected: ["a", "b", "c"],
  306. },
  307. {
  308. path: "test/built-ins/Array/prototype/entries/iteration.js",
  309. code: `return ["a", "b"].entries()`,
  310. expected: [
  311. [0, "a"],
  312. [1, "b"],
  313. ],
  314. },
  315. {
  316. path: "test/built-ins/Array/isArray/15.4.3.2-0-3.js",
  317. code: `return [Array.isArray([]), Array.isArray([1]), Array.isArray(Array.of(1))]`,
  318. expected: [true, true, true],
  319. },
  320. {
  321. path: "test/built-ins/Array/isArray/15.4.3.2-0-4.js",
  322. code: `return [Array.isArray(42), Array.isArray({}), Array.isArray(null), Array.isArray("array")]`,
  323. expected: [false, false, false, false],
  324. },
  325. {
  326. path: "test/built-ins/Array/from/from-array.js",
  327. code: `const input = [0, "foo", undefined, Infinity]; const result = Array.from(input); return [result.length, result[0], result[1], result[2] === undefined, result[3] === Infinity, result !== input, result instanceof Array]`,
  328. expected: [4, 0, "foo", true, true, true, true],
  329. },
  330. {
  331. path: "test/built-ins/Array/from/from-string.js",
  332. code: `return Array.from("Test")`,
  333. expected: ["T", "e", "s", "t"],
  334. },
  335. {
  336. path: "test/built-ins/Array/from/array-like-has-length-but-no-indexes-with-values.js",
  337. code: `const result = Array.from({ length: 5 }); const mapped = result.map(() => 1); return [result.length, result.map((value) => value === undefined), mapped.length, mapped]`,
  338. expected: [5, [true, true, true, true, true], 5, [1, 1, 1, 1, 1]],
  339. },
  340. {
  341. path: "test/built-ins/Array/of/creates-a-new-array-from-arguments.js",
  342. code: `const mixed = Array.of(undefined, false, null, undefined); return [Array.of("Mike", "Rick", "Leo"), mixed.length, mixed[0] === undefined, mixed[1], mixed[2], mixed[3] === undefined, Array.of()]`,
  343. expected: [["Mike", "Rick", "Leo"], 4, true, false, null, true, []],
  344. },
  345. ] as const
  346. describe("Test262 Array core adaptations", () => {
  347. for (const item of cases) {
  348. test(item.path, async () => {
  349. expect(await value(item.code)).toEqual(item.expected)
  350. })
  351. }
  352. })