mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-15 23:08:29 +00:00
test(codemode): add Test262 array coverage (#35965)
This commit is contained in:
parent
b44a981eef
commit
ec8eea7cbe
5 changed files with 736 additions and 106 deletions
325
packages/codemode/test/array-callbacks-test262.test.ts
Normal file
325
packages/codemode/test/array-callbacks-test262.test.ts
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Portions adapted from Test262 at revision 250f204f23a9249ff204be2baec29600faae7b75:
|
||||
* - test/built-ins/Array/prototype/map/15.4.4.19-8-1.js
|
||||
* - test/built-ins/Array/prototype/map/15.4.4.19-8-2.js
|
||||
* - test/built-ins/Array/prototype/map/15.4.4.19-8-b-1.js
|
||||
* - test/built-ins/Array/prototype/filter/15.4.4.20-9-1.js
|
||||
* - test/built-ins/Array/prototype/filter/15.4.4.20-9-2.js
|
||||
* - test/built-ins/Array/prototype/filter/15.4.4.20-9-b-1.js
|
||||
* - test/built-ins/Array/prototype/find/predicate-call-parameters.js
|
||||
* - test/built-ins/Array/prototype/find/predicate-not-called-on-empty-array.js
|
||||
* - test/built-ins/Array/prototype/find/return-found-value-predicate-result-is-true.js
|
||||
* - test/built-ins/Array/prototype/find/return-undefined-if-predicate-returns-false-value.js
|
||||
* - test/built-ins/Array/prototype/findIndex/predicate-call-parameters.js
|
||||
* - test/built-ins/Array/prototype/findIndex/return-index-predicate-result-is-true.js
|
||||
* - test/built-ins/Array/prototype/findIndex/return-negative-one-if-predicate-returns-false-value.js
|
||||
* - test/built-ins/Array/prototype/findLast/predicate-call-parameters.js
|
||||
* - test/built-ins/Array/prototype/findLast/return-found-value-predicate-result-is-true.js
|
||||
* - test/built-ins/Array/prototype/findLast/return-undefined-if-predicate-returns-false-value.js
|
||||
* - test/built-ins/Array/prototype/findLastIndex/predicate-call-parameters.js
|
||||
* - test/built-ins/Array/prototype/findLastIndex/return-index-predicate-result-is-true.js
|
||||
* - test/built-ins/Array/prototype/findLastIndex/return-negative-one-if-predicate-returns-false-value.js
|
||||
* - test/built-ins/Array/prototype/some/15.4.4.17-7-1.js
|
||||
* - test/built-ins/Array/prototype/some/15.4.4.17-8-1.js
|
||||
* - test/built-ins/Array/prototype/every/15.4.4.16-7-1.js
|
||||
* - test/built-ins/Array/prototype/every/15.4.4.16-8-1.js
|
||||
* - test/built-ins/Array/prototype/forEach/15.4.4.18-7-1.js
|
||||
* - test/built-ins/Array/prototype/forEach/15.4.4.18-7-2.js
|
||||
* - test/built-ins/Array/prototype/reduce/15.4.4.21-9-5.js
|
||||
* - test/built-ins/Array/prototype/reduce/15.4.4.21-9-1.js
|
||||
* - test/built-ins/Array/prototype/reduce/15.4.4.21-10-1.js
|
||||
* - test/built-ins/Array/prototype/reduceRight/15.4.4.22-9-5.js
|
||||
* - test/built-ins/Array/prototype/reduceRight/15.4.4.22-9-1.js
|
||||
* - test/built-ins/Array/prototype/reduceRight/15.4.4.22-10-1.js
|
||||
* - test/built-ins/Array/prototype/flatMap/depth-always-one.js
|
||||
* - test/built-ins/Array/prototype/flatMap/mapperfunction-throws.js
|
||||
* - test/built-ins/Array/prototype/sort/S15.4.4.11_A1.1_T1.js
|
||||
* - test/built-ins/Array/prototype/sort/S15.4.4.11_A2.1_T1.js
|
||||
* - test/built-ins/Array/prototype/sort/stability-5-elements.js
|
||||
* - test/built-ins/Array/prototype/toSorted/comparefn-controls-sort.js
|
||||
* - test/built-ins/Array/prototype/toSorted/comparefn-default.js
|
||||
* - test/built-ins/Array/prototype/toSorted/immutable.js
|
||||
* - test/built-ins/Array/prototype/toSorted/zero-or-one-element.js
|
||||
*
|
||||
* Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
* Copyright (C) 2018 Mathias Bynens. All rights reserved.
|
||||
* Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
* Copyright (C) 2021 Igalia, S.L. All rights reserved.
|
||||
* Copyright (C) 2021 Microsoft. All rights reserved.
|
||||
* Copyright (C) 2025 Google. All rights reserved.
|
||||
* Copyright (C) 2026 Garham Lee. All rights reserved.
|
||||
* Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
* Copyright 2009 the Sputnik authors. All rights reserved.
|
||||
* Test262 portions are governed by the BSD license in LICENSE.test262.
|
||||
*/
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { CodeMode } from "../src/index.js"
|
||||
|
||||
const value = async (code: string) => {
|
||||
const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} }))
|
||||
if (!result.ok) throw new Error(`expected success, got ${result.error.kind}: ${result.error.message}`)
|
||||
return result.value
|
||||
}
|
||||
|
||||
const cases = [
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/map/15.4.4.19-8-1.js",
|
||||
code: `const input = [1, 2]; input[3] = 4; input[4] = 5; const result = input.map((value) => { input[2] = 3; input[5] = 6; return 1 }); return [result.length, result[5] === undefined]`,
|
||||
expected: [5, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/map/15.4.4.19-8-2.js",
|
||||
code: `const input = [1, 2, 3, 4, 5]; const result = input.map((value) => { input[4] = -1; return value > 0 ? 1 : 0 }); return [result.length, result[4]]`,
|
||||
expected: [5, 0],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/map/15.4.4.19-8-b-1.js",
|
||||
code: `const input = []; input[10] = 0; input.pop(); input[1] = undefined; let calls = 0; const result = input.map(() => { calls += 1; return 1 }); return [result.length, calls, 0 in result, 1 in result]`,
|
||||
expected: [10, 1, false, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/filter/15.4.4.20-9-1.js",
|
||||
code: `const input = [1, 2]; input[3] = 4; input[4] = 5; const result = input.filter(() => { input[2] = 3; input[5] = 6; return true }); return result`,
|
||||
expected: [1, 2, 3, 4, 5],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/filter/15.4.4.20-9-2.js",
|
||||
code: `const input = [1, 2, 3, 4, 5]; return input.filter((value) => { input[2] = -1; input[4] = -1; return value > 0 })`,
|
||||
expected: [1, 2, 4],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/filter/15.4.4.20-9-b-1.js",
|
||||
code: `const input = []; input[9] = 0; input.pop(); input[1] = undefined; let calls = 0; const result = input.filter(() => { calls += 1; return false }); return [result, calls]`,
|
||||
expected: [[], 1],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/find/predicate-call-parameters.js",
|
||||
code: `const input = [10, 20]; const seen = []; input.find((value, index, receiver) => { seen.push([value, index, receiver === input]); return false }); return seen`,
|
||||
expected: [
|
||||
[10, 0, true],
|
||||
[20, 1, true],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/find/return-found-value-predicate-result-is-true.js",
|
||||
code: `return [1, 2, 3].find((value) => value > 1)`,
|
||||
expected: 2,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/find/return-undefined-if-predicate-returns-false-value.js",
|
||||
code: `return [1, 2, 3].find((value) => value > 4) === undefined`,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/find/predicate-not-called-on-empty-array.js",
|
||||
code: `let calls = 0; const result = [].find(() => { calls += 1; return true }); return [result === undefined, calls]`,
|
||||
expected: [true, 0],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findIndex/predicate-call-parameters.js",
|
||||
code: `const input = [10, 20]; const seen = []; input.findIndex((value, index, receiver) => { seen.push([value, index, receiver === input]); return false }); return seen`,
|
||||
expected: [
|
||||
[10, 0, true],
|
||||
[20, 1, true],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findIndex/return-index-predicate-result-is-true.js",
|
||||
code: `return [1, 2, 3].findIndex((value) => value > 1)`,
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findIndex/return-negative-one-if-predicate-returns-false-value.js",
|
||||
code: `return [1, 2, 3].findIndex((value) => value > 4)`,
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findLast/predicate-call-parameters.js",
|
||||
code: `const input = [10, 20]; const seen = []; input.findLast((value, index, receiver) => { seen.push([value, index, receiver === input]); return false }); return seen`,
|
||||
expected: [
|
||||
[20, 1, true],
|
||||
[10, 0, true],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findLast/return-found-value-predicate-result-is-true.js",
|
||||
code: `return [1, 2, 3].findLast((value) => value < 3)`,
|
||||
expected: 2,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findLast/return-undefined-if-predicate-returns-false-value.js",
|
||||
code: `return [1, 2, 3].findLast((value) => value > 4) === undefined`,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findLastIndex/predicate-call-parameters.js",
|
||||
code: `const input = [10, 20]; const seen = []; input.findLastIndex((value, index, receiver) => { seen.push([value, index, receiver === input]); return false }); return seen`,
|
||||
expected: [
|
||||
[20, 1, true],
|
||||
[10, 0, true],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findLastIndex/return-index-predicate-result-is-true.js",
|
||||
code: `return [1, 2, 3].findLastIndex((value) => value < 3)`,
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/findLastIndex/return-negative-one-if-predicate-returns-false-value.js",
|
||||
code: `return [1, 2, 3].findLastIndex((value) => value > 4)`,
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/some/15.4.4.17-7-1.js",
|
||||
code: `const input = [1, 2]; input[3] = 4; input[4] = 5; const seen = []; const result = input.some((value) => { input[2] = 3; seen.push(value); return false }); return [result, seen.includes(3)]`,
|
||||
expected: [false, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/some/15.4.4.17-8-1.js",
|
||||
code: `return [].some(() => true)`,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/every/15.4.4.16-7-1.js",
|
||||
code: `const input = [1, 2]; input[3] = 4; input[4] = 5; const seen = []; const result = input.every((value) => { input[2] = 3; seen.push(value); return true }); return [result, seen.includes(3)]`,
|
||||
expected: [true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/every/15.4.4.16-8-1.js",
|
||||
code: `return [].every(() => false)`,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/forEach/15.4.4.18-7-1.js",
|
||||
code: `const input = [1, 2]; input[3] = 4; input[4] = 5; let calls = 0; input.forEach(() => { calls += 1; input[2] = 3; input[5] = 6 }); return calls`,
|
||||
expected: 5,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/forEach/15.4.4.18-7-2.js",
|
||||
code: `const input = [1, 2, 3]; const seen = []; input.forEach((value, index) => { seen.push(value); if (index === 0) input.pop() }); return seen`,
|
||||
expected: [1, 2],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/reduce/15.4.4.21-9-1.js",
|
||||
code: `const input = [1, 2]; input[3] = 4; input[4] = "5"; return input.reduce((accumulator, value) => { input[2] = 3; input[5] = 6; return accumulator + value })`,
|
||||
expected: "105",
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/reduce/15.4.4.21-9-5.js",
|
||||
code: `let calls = 0; const result = [1].reduce(() => { calls += 1; return 2 }); return [result, calls]`,
|
||||
expected: [1, 0],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/reduce/15.4.4.21-10-1.js",
|
||||
code: `const input = [1, 2, 3, 4, 5]; input.reduce(() => 1); return input`,
|
||||
expected: [1, 2, 3, 4, 5],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/reduceRight/15.4.4.22-9-1.js",
|
||||
code: `const input = ["1", 2]; input[3] = 4; input[4] = "5"; return input.reduceRight((accumulator, value) => { input[2] = 3; input[5] = 6; return accumulator + value })`,
|
||||
expected: "54321",
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/reduceRight/15.4.4.22-9-5.js",
|
||||
code: `let calls = 0; const result = [1].reduceRight(() => { calls += 1; return 2 }); return [result, calls]`,
|
||||
expected: [1, 0],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/reduceRight/15.4.4.22-10-1.js",
|
||||
code: `const input = [1, 2, 3, 4, 5]; input.reduceRight(() => 1); return input`,
|
||||
expected: [1, 2, 3, 4, 5],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/flatMap/depth-always-one.js",
|
||||
code: `return [1, 2, 3].flatMap((value) => [[value * 2]])`,
|
||||
expected: [[2], [4], [6]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/flatMap/mapperfunction-throws.js",
|
||||
code: `try { [1, 2].flatMap(() => { throw "stop" }) } catch (error) { return error === "stop" } return false`,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/sort/S15.4.4.11_A1.1_T1.js",
|
||||
code: `const input = []; input[2] = 0; input.pop(); input.sort(); return [input.length, input[0] === undefined, input[1] === undefined]`,
|
||||
expected: [2, true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/sort/S15.4.4.11_A2.1_T1.js",
|
||||
code: `return ["z", "y", "x", "w", "v", "u", "t", "s", "r", "q", "p", "o", "n", "M", "L", "K", "J", "I", "H", "G", "F", "E", "D", "C", "B", "A"].sort()`,
|
||||
expected: [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/sort/stability-5-elements.js",
|
||||
code: `const input = [{ n: "A", r: 2 }, { n: "B", r: 3 }, { n: "C", r: 2 }, { n: "D", r: 3 }, { n: "E", r: 3 }]; return input.sort((left, right) => right.r - left.r).map((item) => item.n).join("")`,
|
||||
expected: "BDEAC",
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/toSorted/comparefn-controls-sort.js",
|
||||
code: `const mixed = [333, 33, 3, 222, 22, 2, 111, 11, 1]; return [[1, 2, 3, 4].toSorted((a, b) => a - b), [4, 3, 2, 1].toSorted((a, b) => a - b), mixed.toSorted((a, b) => a - b), [1, 2, 3, 4].toSorted((a, b) => b - a), [4, 3, 2, 1].toSorted((a, b) => b - a), mixed.toSorted((a, b) => b - a)]`,
|
||||
expected: [
|
||||
[1, 2, 3, 4],
|
||||
[1, 2, 3, 4],
|
||||
[1, 2, 3, 11, 22, 33, 111, 222, 333],
|
||||
[4, 3, 2, 1],
|
||||
[4, 3, 2, 1],
|
||||
[333, 222, 111, 33, 22, 11, 3, 2, 1],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/toSorted/comparefn-default.js",
|
||||
code: `return [[1, 2, 3, 4].toSorted(), [4, 3, 2, 1].toSorted(), ["a", 2, 1, "z"].toSorted(), [333, 33, 3, 222, 22, 2, 111, 11, 1].toSorted()]`,
|
||||
expected: [
|
||||
[1, 2, 3, 4],
|
||||
[1, 2, 3, 4],
|
||||
[1, 2, "a", "z"],
|
||||
[1, 11, 111, 2, 22, 222, 3, 33, 333],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/toSorted/immutable.js",
|
||||
code: `const input = [2, 0, 1]; const result = input.toSorted(); return [input, result !== input]`,
|
||||
expected: [[2, 0, 1], true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/toSorted/zero-or-one-element.js",
|
||||
code: `const zero = []; const one = [1]; const zeroResult = zero.toSorted(); const oneResult = one.toSorted(); return [zeroResult, oneResult, zeroResult !== zero, oneResult !== one]`,
|
||||
expected: [[], [1], true, true],
|
||||
},
|
||||
] as const
|
||||
|
||||
describe("Test262 Array callback adaptations", () => {
|
||||
for (const item of cases) {
|
||||
test(item.path, async () => {
|
||||
expect(await value(item.code)).toEqual(item.expected)
|
||||
})
|
||||
}
|
||||
})
|
||||
323
packages/codemode/test/array-core-test262.test.ts
Normal file
323
packages/codemode/test/array-core-test262.test.ts
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* Portions adapted from Test262 at revision 250f204f23a9249ff204be2baec29600faae7b75:
|
||||
* - test/built-ins/Array/prototype/includes/samevaluezero.js
|
||||
* - test/built-ins/Array/prototype/includes/using-fromindex.js
|
||||
* - test/built-ins/Array/prototype/join/S15.4.4.5_A3.1_T1.js
|
||||
* - test/built-ins/Array/prototype/join/S15.4.4.5_A3.2_T1.js
|
||||
* - test/built-ins/Array/prototype/slice/S15.4.4.10_A1.2_T2.js
|
||||
* - test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T1.js
|
||||
* - test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T2.js
|
||||
* - test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T3.js
|
||||
* - test/built-ins/Array/prototype/indexOf/fromindex-zero-conversion.js
|
||||
* - test/built-ins/Array/prototype/indexOf/length-zero-returns-minus-one.js
|
||||
* - test/built-ins/Array/prototype/lastIndexOf/fromindex-zero-conversion.js
|
||||
* - test/built-ins/Array/prototype/lastIndexOf/length-zero-returns-minus-one.js
|
||||
* - test/built-ins/Array/prototype/at/returns-item.js
|
||||
* - test/built-ins/Array/prototype/at/returns-item-relative-index.js
|
||||
* - test/built-ins/Array/prototype/at/returns-undefined-for-out-of-range-index.js
|
||||
* - test/built-ins/Array/prototype/flat/null-undefined-elements.js
|
||||
* - test/built-ins/Array/prototype/flat/positive-infinity.js
|
||||
* - test/built-ins/Array/prototype/reverse/S15.4.4.8_A1_T1.js
|
||||
* - test/built-ins/Array/prototype/toReversed/immutable.js
|
||||
* - test/built-ins/Array/prototype/toReversed/zero-or-one-element.js
|
||||
* - test/built-ins/Array/prototype/with/immutable.js
|
||||
* - test/built-ins/Array/prototype/with/index-negative.js
|
||||
* - test/built-ins/Array/prototype/push/S15.4.4.7_A1_T1.js
|
||||
* - test/built-ins/Array/prototype/pop/S15.4.4.6_A1.1_T1.js
|
||||
* - test/built-ins/Array/prototype/shift/S15.4.4.9_A1.1_T1.js
|
||||
* - test/built-ins/Array/prototype/unshift/S15.4.4.13_A1_T1.js
|
||||
* - test/built-ins/Array/prototype/splice/S15.4.4.12_A1.1_T1.js
|
||||
* - test/built-ins/Array/prototype/splice/S15.4.4.12_A1.2_T1.js
|
||||
* - test/built-ins/Array/prototype/splice/called_with_one_argument.js
|
||||
* - test/built-ins/Array/prototype/fill/fill-values.js
|
||||
* - test/built-ins/Array/prototype/fill/fill-values-custom-start-and-end.js
|
||||
* - test/built-ins/Array/prototype/fill/return-this.js
|
||||
* - test/built-ins/Array/prototype/copyWithin/non-negative-target-start-and-end.js
|
||||
* - test/built-ins/Array/prototype/copyWithin/return-this.js
|
||||
* - test/built-ins/Array/prototype/keys/iteration.js
|
||||
* - test/built-ins/Array/prototype/values/iteration.js
|
||||
* - test/built-ins/Array/prototype/entries/iteration.js
|
||||
* - test/built-ins/Array/isArray/15.4.3.2-0-3.js
|
||||
* - test/built-ins/Array/isArray/15.4.3.2-0-4.js
|
||||
* - test/built-ins/Array/from/from-array.js
|
||||
* - test/built-ins/Array/from/from-string.js
|
||||
* - test/built-ins/Array/from/array-like-has-length-but-no-indexes-with-values.js
|
||||
* - test/built-ins/Array/of/creates-a-new-array-from-arguments.js
|
||||
*
|
||||
* Copyright (C) 2015 André Bargull. All rights reserved.
|
||||
* Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
* Copyright (C) 2016 the V8 project authors. All rights reserved.
|
||||
* Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
* Copyright (C) 2020 Alexey Shvayka. All rights reserved.
|
||||
* Copyright (C) 2020 Rick Waldron. All rights reserved.
|
||||
* Copyright (C) 2021 Igalia, S.L. All rights reserved.
|
||||
* Copyright (c) 2012 Ecma International. All rights reserved.
|
||||
* Copyright (c) 2014 Hank Yates. All rights reserved.
|
||||
* Copyright (c) 2015 the V8 project authors. All rights reserved.
|
||||
* Copyright (c) 2021 Rick Waldron. All rights reserved.
|
||||
* Copyright 2009 the Sputnik authors. All rights reserved.
|
||||
* Copyright 2015 Microsoft Corporation. All rights reserved.
|
||||
* Copyright 2016 The V8 project authors. All rights reserved.
|
||||
* Test262 portions are governed by the BSD license in LICENSE.test262.
|
||||
*/
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { CodeMode } from "../src/index.js"
|
||||
|
||||
const value = async (code: string) => {
|
||||
const result = await Effect.runPromise(CodeMode.execute({ code, tools: {} }))
|
||||
if (!result.ok) throw new Error(`expected success, got ${result.error.kind}: ${result.error.message}`)
|
||||
return result.value
|
||||
}
|
||||
|
||||
const cases = [
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/includes/samevaluezero.js",
|
||||
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("")]`,
|
||||
expected: [true, false, false, false, true, true, true, false, false],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/includes/using-fromindex.js",
|
||||
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)]`,
|
||||
expected: [true, false, true, true, false, true, true, false, true, true, false, true, true, false, true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/join/S15.4.4.5_A3.1_T1.js",
|
||||
code: `return [[0, 1, 2, 3].join("&"), [0, 1, 2, 3].join("")]`,
|
||||
expected: ["0&1&2&3", "0123"],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/join/S15.4.4.5_A3.2_T1.js",
|
||||
code: `return [
|
||||
["", "", ""].join(""),
|
||||
["&", "&", "&"].join("&"),
|
||||
[true, true, true].join(),
|
||||
[null, null, null].join(),
|
||||
[undefined, undefined, undefined].join(),
|
||||
[Infinity, Infinity, Infinity].join(),
|
||||
[NaN, NaN, NaN].join(),
|
||||
]`,
|
||||
expected: ["", "&&&&&", "true,true,true", ",,", ",,", "Infinity,Infinity,Infinity", "NaN,NaN,NaN"],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/slice/S15.4.4.10_A1.2_T2.js",
|
||||
code: `return [0, 1, 2, 3, 4].slice(-1, 5)`,
|
||||
expected: [4],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T1.js",
|
||||
code: `return [].concat([0, 1], [2, 3, 4])`,
|
||||
expected: [0, 1, 2, 3, 4],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T2.js",
|
||||
code: `const object = { value: 1 }; const result = [0].concat(object, [1, 2], -1, true, "NaN"); return [result, result[1] === object]`,
|
||||
expected: [[0, { value: 1 }, 1, 2, -1, true, "NaN"], true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/concat/S15.4.4.4_A1_T3.js",
|
||||
code: `const input = [0, 1]; const result = input.concat(); return [result, result !== input]`,
|
||||
expected: [[0, 1], true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/indexOf/fromindex-zero-conversion.js",
|
||||
code: `const result = [true].indexOf(true, -0); return [result, 1 / result === Infinity]`,
|
||||
expected: [0, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/indexOf/length-zero-returns-minus-one.js",
|
||||
code: `return [].indexOf(1)`,
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/lastIndexOf/fromindex-zero-conversion.js",
|
||||
code: `const result = [true].lastIndexOf(true, -0); return [result, 1 / result === Infinity]`,
|
||||
expected: [0, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/lastIndexOf/length-zero-returns-minus-one.js",
|
||||
code: `return [].lastIndexOf(1)`,
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/at/returns-item.js",
|
||||
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)]`,
|
||||
expected: [1, 2, 3, 4, true, 5],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/at/returns-item-relative-index.js",
|
||||
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)]`,
|
||||
expected: [1, 5, true, 4, 3],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/at/returns-undefined-for-out-of-range-index.js",
|
||||
code: `const input = []; return [input.at(-2) === undefined, input.at(0) === undefined, input.at(1) === undefined]`,
|
||||
expected: [true, true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/flat/null-undefined-elements.js",
|
||||
code: `const result = [1, [null, [undefined]]].flat(2); return [result.length, result[0], result[1] === null, result[2] === undefined]`,
|
||||
expected: [3, 1, true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/flat/positive-infinity.js",
|
||||
code: `return [1, [2, [3, [4]]]].flat(Infinity)`,
|
||||
expected: [1, 2, 3, 4],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/reverse/S15.4.4.8_A1_T1.js",
|
||||
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]`,
|
||||
expected: [true, true, true, [2, 1]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/toReversed/immutable.js",
|
||||
code: `const input = [0, 1, 2]; const result = input.toReversed(); return [input, result !== input]`,
|
||||
expected: [[0, 1, 2], true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/toReversed/zero-or-one-element.js",
|
||||
code: `const zero = []; const one = [1]; const zeroResult = zero.toReversed(); const oneResult = one.toReversed(); return [zeroResult, oneResult, zeroResult !== zero, oneResult !== one]`,
|
||||
expected: [[], [1], true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/with/immutable.js",
|
||||
code: `const input = [0, 1, 2]; const result = input.with(1, 3); return [input, result !== input, input.with(1, 1) !== input]`,
|
||||
expected: [[0, 1, 2], true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/with/index-negative.js",
|
||||
code: `const input = [0, 1, 2]; return [input.with(-1, 4), input.with(-3, 4)]`,
|
||||
expected: [
|
||||
[0, 1, 4],
|
||||
[4, 1, 2],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/push/S15.4.4.7_A1_T1.js",
|
||||
code: `const input = []; return [input.push(1), input.push(), input.push(-1), input]`,
|
||||
expected: [1, 1, 2, [1, -1]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/pop/S15.4.4.6_A1.1_T1.js",
|
||||
code: `const input = []; return [input.pop() === undefined, input.length]`,
|
||||
expected: [true, 0],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/shift/S15.4.4.9_A1.1_T1.js",
|
||||
code: `const input = []; return [input.shift() === undefined, input.length]`,
|
||||
expected: [true, 0],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/unshift/S15.4.4.13_A1_T1.js",
|
||||
code: `const input = []; return [input.unshift(1), input[0], input.unshift(), input.unshift(-1), input]`,
|
||||
expected: [1, 1, 1, 2, [-1, 1]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/splice/S15.4.4.12_A1.1_T1.js",
|
||||
code: `const input = [0, 1, 2, 3]; const removed = input.splice(0, 3); return [input, removed]`,
|
||||
expected: [[3], [0, 1, 2]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/splice/S15.4.4.12_A1.2_T1.js",
|
||||
code: `const input = [0, 1]; const removed = input.splice(-2, -1); return [input, removed]`,
|
||||
expected: [[0, 1], []],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/splice/called_with_one_argument.js",
|
||||
code: `const input = ["first", "second", "third"]; const removed = input.splice(1); return [input, removed]`,
|
||||
expected: [["first"], ["second", "third"]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/fill/fill-values-custom-start-and-end.js",
|
||||
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]]]`,
|
||||
expected: [
|
||||
[0, 8, 0],
|
||||
[0, 0, 8, 8, 0],
|
||||
[0, 0, 0, 8, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[false, 8, 8, false, 0],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/fill/return-this.js",
|
||||
code: `const input = []; return input.fill(1) === input`,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/fill/fill-values.js",
|
||||
code: `const omitted = [0, 0].fill(); return [[].fill(8), omitted.map((value) => value === undefined), [0, 0, 0].fill(8)]`,
|
||||
expected: [[], [true, true], [8, 8, 8]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/copyWithin/non-negative-target-start-and-end.js",
|
||||
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)]`,
|
||||
expected: [
|
||||
[0, 1, 2, 3],
|
||||
[0, 1, 2, 3],
|
||||
[1, 1, 2, 3],
|
||||
[0, 0, 1, 3],
|
||||
[0, 3, 4, 3, 4, 5],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/copyWithin/return-this.js",
|
||||
code: `const input = [0, 1, 2, 3]; const result = input.copyWithin(1, 0, 2); return [input, result === input]`,
|
||||
expected: [[0, 0, 1, 3], true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/keys/iteration.js",
|
||||
code: `return ["a", "b", "c"].keys()`,
|
||||
expected: [0, 1, 2],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/values/iteration.js",
|
||||
code: `return ["a", "b", "c"].values()`,
|
||||
expected: ["a", "b", "c"],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/prototype/entries/iteration.js",
|
||||
code: `return ["a", "b"].entries()`,
|
||||
expected: [
|
||||
[0, "a"],
|
||||
[1, "b"],
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/isArray/15.4.3.2-0-3.js",
|
||||
code: `return [Array.isArray([]), Array.isArray([1]), Array.isArray(Array.of(1))]`,
|
||||
expected: [true, true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/isArray/15.4.3.2-0-4.js",
|
||||
code: `return [Array.isArray(42), Array.isArray({}), Array.isArray(null), Array.isArray("array")]`,
|
||||
expected: [false, false, false, false],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/from/from-array.js",
|
||||
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]`,
|
||||
expected: [4, 0, "foo", true, true, true, true],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/from/from-string.js",
|
||||
code: `return Array.from("Test")`,
|
||||
expected: ["T", "e", "s", "t"],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/from/array-like-has-length-but-no-indexes-with-values.js",
|
||||
code: `const result = Array.from({ length: 5 }); const mapped = result.map(() => 1); return [result.length, result.map((value) => value === undefined), mapped.length, mapped]`,
|
||||
expected: [5, [true, true, true, true, true], 5, [1, 1, 1, 1, 1]],
|
||||
},
|
||||
{
|
||||
path: "test/built-ins/Array/of/creates-a-new-array-from-arguments.js",
|
||||
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()]`,
|
||||
expected: [["Mike", "Rick", "Leo"], 4, true, false, null, true, []],
|
||||
},
|
||||
] as const
|
||||
|
||||
describe("Test262 Array core adaptations", () => {
|
||||
for (const item of cases) {
|
||||
test(item.path, async () => {
|
||||
expect(await value(item.code)).toEqual(item.expected)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -42,11 +42,6 @@ describe("H2: string property access reads as undefined (not a throw)", () => {
|
|||
test("unknown property on a number is undefined", async () => {
|
||||
expect(await value(`return (5).foo ?? "n"`)).toBe("n")
|
||||
})
|
||||
|
||||
test("supported string methods still work", async () => {
|
||||
expect(await value(`return "AB".toLowerCase()`)).toBe("ab")
|
||||
expect(await value(`return "hello".length`)).toBe(5)
|
||||
})
|
||||
})
|
||||
|
||||
describe("H3: array property access reads as undefined (not a throw)", () => {
|
||||
|
|
@ -63,8 +58,7 @@ describe("H3: array property access reads as undefined (not a throw)", () => {
|
|||
expect(await value(`return [1,2,3].toSpliced === undefined`)).toBe(true)
|
||||
})
|
||||
|
||||
test("supported array methods and indexing still work", async () => {
|
||||
expect(await value(`return [1,2,3].map(x => x + 1)`)).toEqual([2, 3, 4])
|
||||
test("array indexing still works", async () => {
|
||||
expect(await value(`return [1,2,3][9] === undefined`)).toBe(true)
|
||||
expect(await value(`return [1,2,3][9]`)).toBeNull()
|
||||
})
|
||||
|
|
@ -202,9 +196,6 @@ describe("Error values and instanceof", () => {
|
|||
"TypeError",
|
||||
true,
|
||||
])
|
||||
expect(await value(`try { "a".normalize("NOPE") } catch (e) { return [e.name, e instanceof RangeError] }`)).toEqual(
|
||||
["RangeError", true],
|
||||
)
|
||||
expect(await value(`try { "a".match("(") } catch (e) { return [e.name, e instanceof SyntaxError] }`)).toEqual([
|
||||
"SyntaxError",
|
||||
true,
|
||||
|
|
@ -263,55 +254,18 @@ describe("Error values and instanceof", () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe("array methods: splice, fill, copyWithin, keys/values/entries", () => {
|
||||
test("sort and reverse mutate and return the receiver", async () => {
|
||||
describe("CodeMode-specific array behavior", () => {
|
||||
test("sort with a comparator mutates and returns the receiver", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const sorted = [3, 1, 2]
|
||||
const sortResult = sorted.sort((a, b) => a - b)
|
||||
const reversed = [1, 2, 3]
|
||||
const reverseResult = reversed.reverse()
|
||||
return { sorted, sameSort: sorted === sortResult, reversed, sameReverse: reversed === reverseResult }
|
||||
const input = [3, 1, 2]
|
||||
const result = input.sort((a, b) => a - b)
|
||||
return { input, same: input === result }
|
||||
`),
|
||||
).toEqual({ sorted: [1, 2, 3], sameSort: true, reversed: [3, 2, 1], sameReverse: true })
|
||||
).toEqual({ input: [1, 2, 3], same: true })
|
||||
})
|
||||
|
||||
test("array callbacks receive the receiver and observe later mutations", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const values = [1, 2, 3]
|
||||
const seen = values.map((value, index, receiver) => {
|
||||
if (index === 0) values[1] = 9
|
||||
return [value, receiver === values]
|
||||
})
|
||||
return seen
|
||||
`),
|
||||
).toEqual([
|
||||
[1, true],
|
||||
[9, true],
|
||||
[3, true],
|
||||
])
|
||||
expect(
|
||||
await value(`
|
||||
const values = [1, 2, 3]
|
||||
const seen = []
|
||||
values.forEach((value, index) => {
|
||||
seen.push(value)
|
||||
if (index === 0) values.pop()
|
||||
})
|
||||
return seen
|
||||
`),
|
||||
).toEqual([1, 2])
|
||||
})
|
||||
|
||||
test("splice removes in place and returns the removed elements", async () => {
|
||||
expect(await value(`const a = [1,2,3,4]; const removed = a.splice(1, 2); return { removed, a }`)).toEqual({
|
||||
removed: [2, 3],
|
||||
a: [1, 4],
|
||||
})
|
||||
})
|
||||
|
||||
test("splice inserts new elements at the cut", async () => {
|
||||
test("splice can replace and insert elements", async () => {
|
||||
expect(await value(`const a = ["a","d"]; a.splice(1, 0, "b", "c"); return a`)).toEqual(["a", "b", "c", "d"])
|
||||
expect(await value(`const a = [1,2,3]; const removed = a.splice(1, 1, "x"); return { removed, a }`)).toEqual({
|
||||
removed: [2],
|
||||
|
|
@ -319,32 +273,12 @@ describe("array methods: splice, fill, copyWithin, keys/values/entries", () => {
|
|||
})
|
||||
})
|
||||
|
||||
test("splice with one argument removes to the end; negative start counts back", async () => {
|
||||
expect(await value(`const a = [1,2,3]; const removed = a.splice(1); return { removed, a }`)).toEqual({
|
||||
removed: [2, 3],
|
||||
a: [1],
|
||||
})
|
||||
expect(await value(`const a = [1,2,3]; const removed = a.splice(-1); return { removed, a }`)).toEqual({
|
||||
removed: [3],
|
||||
a: [1, 2],
|
||||
})
|
||||
})
|
||||
|
||||
test("splice rejects inserting a container into itself", async () => {
|
||||
const err = await error(`const a = [1]; a.splice(0, 0, [a]); return a`)
|
||||
expect(err.kind).toBe("InvalidDataValue")
|
||||
expect(err.message).toContain("circular")
|
||||
})
|
||||
|
||||
test("fill overwrites a range and returns the mutated array", async () => {
|
||||
expect(await value(`const a = [1,2,3,4]; return a.fill(0, 1, 3)`)).toEqual([1, 0, 0, 4])
|
||||
expect(await value(`return [1,2,3].fill("z")`)).toEqual(["z", "z", "z"])
|
||||
})
|
||||
|
||||
test("copyWithin copies a range in place", async () => {
|
||||
expect(await value(`return [1,2,3,4,5].copyWithin(0, 3)`)).toEqual([4, 5, 3, 4, 5])
|
||||
})
|
||||
|
||||
test("keys/values/entries return arrays usable with for...of and spread", async () => {
|
||||
expect(await value(`return [...["x","y","z"].keys()]`)).toEqual([0, 1, 2])
|
||||
expect(await value(`return ["x","y"].values()`)).toEqual(["x", "y"])
|
||||
|
|
@ -359,16 +293,9 @@ describe("array methods: splice, fill, copyWithin, keys/values/entries", () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe("string methods: localeCompare, normalize, trim aliases", () => {
|
||||
describe("CodeMode-specific string behavior", () => {
|
||||
test("localeCompare orders strings for sorting", async () => {
|
||||
expect(await value(`return ["b","a","c"].sort((x, y) => x.localeCompare(y))`)).toEqual(["a", "b", "c"])
|
||||
expect(await value(`return "a".localeCompare("a")`)).toBe(0)
|
||||
})
|
||||
|
||||
test("normalize applies unicode normalization forms", async () => {
|
||||
expect(await value(`return "\\u0065\\u0301".normalize("NFC").length`)).toBe(1)
|
||||
expect(await value(`return "\\u00e9".normalize("NFD").length`)).toBe(2)
|
||||
expect(await value(`return "x".normalize() === "x"`)).toBe(true)
|
||||
})
|
||||
|
||||
test("an invalid normalize form is a clear catchable error", async () => {
|
||||
|
|
@ -453,11 +380,6 @@ describe("H5: builtin coercion functions work as array callbacks", () => {
|
|||
expect(await value(`return [1, 2, 3].map(String)`)).toEqual(["1", "2", "3"])
|
||||
})
|
||||
|
||||
test("arrow callbacks still work (no regression)", async () => {
|
||||
expect(await value(`return [1, 2, 3, 4].filter(x => x % 2 === 0)`)).toEqual([2, 4])
|
||||
expect(await value(`return [1, 2, 3].reduce((a, b) => a + b, 0)`)).toBe(6)
|
||||
})
|
||||
|
||||
test("a non-callable callback is still rejected", async () => {
|
||||
const err = await error(`return [1,2,3].map(42)`)
|
||||
expect(err.message).toContain("callback")
|
||||
|
|
|
|||
|
|
@ -154,9 +154,7 @@ describe("RegExp", () => {
|
|||
).toEqual(["1", "22"])
|
||||
})
|
||||
|
||||
test("string match: non-global carries index, global lists all matches", async () => {
|
||||
expect(await value(`const m = "a1b22".match(/\\d+/); return [m[0], m.index]`)).toEqual(["1", 1])
|
||||
expect(await value(`return "a1b22".match(/\\d+/g)`)).toEqual(["1", "22"])
|
||||
test("an unmatched string pattern returns null", async () => {
|
||||
expect(await value(`return "abc".match(/\\d/)`)).toBeNull()
|
||||
})
|
||||
|
||||
|
|
@ -164,13 +162,6 @@ describe("RegExp", () => {
|
|||
expect(await value(`return "a1b22".matchAll(/(\\d+)/g).map((m) => m[1])`)).toEqual(["1", "22"])
|
||||
})
|
||||
|
||||
test("replace and replaceAll with patterns and $1 substitution", async () => {
|
||||
expect(await value(`return "a1b2".replace(/\\d/, "#")`)).toBe("a#b2")
|
||||
expect(await value(`return "a1b2".replace(/\\d/g, "#")`)).toBe("a#b#")
|
||||
expect(await value(`return "a1b2".replaceAll(/\\d/g, "#")`)).toBe("a#b#")
|
||||
expect(await value(`return "hi bob".replace(/b(o)b/, "[$1]")`)).toBe("hi [o]")
|
||||
})
|
||||
|
||||
test("function replacers receive captures, offsets, input, and named groups", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
|
|
@ -236,12 +227,6 @@ describe("RegExp", () => {
|
|||
expect(await value(`try { "a".replaceAll(/a/, "b"); return "no" } catch { return "caught" }`)).toBe("caught")
|
||||
})
|
||||
|
||||
test("split and search accept patterns", async () => {
|
||||
expect(await value(`return "a1b22c".split(/\\d+/)`)).toEqual(["a", "b", "c"])
|
||||
expect(await value(`return "ab42".search(/\\d/)`)).toBe(2)
|
||||
expect(await value(`return "ab".search(/\\d/)`)).toBe(-1)
|
||||
})
|
||||
|
||||
test("new RegExp constructs from strings; invalid patterns are catchable", async () => {
|
||||
expect(await value(`return new RegExp("a+", "i").test("AAA")`)).toBe(true)
|
||||
expect(await value(`try { new RegExp("("); return "no" } catch { return "caught" }`)).toBe("caught")
|
||||
|
|
@ -650,9 +635,7 @@ describe("stdlib integration", () => {
|
|||
true,
|
||||
)
|
||||
expect(
|
||||
await value(
|
||||
`try { Object.fromEntries(new Map([["fn", Math.max]])); return false } catch { return true }`,
|
||||
),
|
||||
await value(`try { Object.fromEntries(new Map([["fn", Math.max]])); return false } catch { return true }`),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
|
|
|
|||
77
packages/codemode/test/test262-array.md
Normal file
77
packages/codemode/test/test262-array.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Test262 Array Coverage
|
||||
|
||||
The Array tests adapt Test262 at revision `250f204f23a9249ff204be2baec29600faae7b75`. They cover CodeMode's 35
|
||||
exposed instance methods and three static methods using actual arrays, accepted argument types, deterministic behavior,
|
||||
and CodeMode's materialized collection conventions. Each executable case names its exact upstream source path.
|
||||
`LICENSE.test262` contains the upstream BSD terms.
|
||||
|
||||
This is coverage of CodeMode's bounded Array surface, not a claim of ECMAScript or Test262 conformance. One upstream
|
||||
file may contain both adapted and inapplicable assertions, so a cited source means only that the represented assertions
|
||||
were adapted.
|
||||
|
||||
## Inventory
|
||||
|
||||
The 38 relevant upstream API directories contain 2,837 files. The executable suite adapts assertions from 83 distinct
|
||||
sources.
|
||||
|
||||
| API | Upstream files | Adapted sources |
|
||||
| ------------------------------- | -------------: | --------------: |
|
||||
| `Array.prototype.map` | 216 | 3 |
|
||||
| `Array.prototype.filter` | 242 | 3 |
|
||||
| `Array.prototype.find` | 23 | 4 |
|
||||
| `Array.prototype.findIndex` | 23 | 3 |
|
||||
| `Array.prototype.findLast` | 24 | 3 |
|
||||
| `Array.prototype.findLastIndex` | 24 | 3 |
|
||||
| `Array.prototype.some` | 219 | 2 |
|
||||
| `Array.prototype.every` | 218 | 2 |
|
||||
| `Array.prototype.includes` | 30 | 2 |
|
||||
| `Array.prototype.join` | 23 | 2 |
|
||||
| `Array.prototype.reduce` | 260 | 3 |
|
||||
| `Array.prototype.reduceRight` | 260 | 3 |
|
||||
| `Array.prototype.flatMap` | 24 | 2 |
|
||||
| `Array.prototype.forEach` | 190 | 2 |
|
||||
| `Array.prototype.sort` | 54 | 3 |
|
||||
| `Array.prototype.toSorted` | 21 | 4 |
|
||||
| `Array.prototype.slice` | 71 | 1 |
|
||||
| `Array.prototype.concat` | 69 | 3 |
|
||||
| `Array.prototype.indexOf` | 201 | 2 |
|
||||
| `Array.prototype.lastIndexOf` | 198 | 2 |
|
||||
| `Array.prototype.at` | 13 | 3 |
|
||||
| `Array.prototype.flat` | 19 | 2 |
|
||||
| `Array.prototype.reverse` | 18 | 1 |
|
||||
| `Array.prototype.toReversed` | 17 | 2 |
|
||||
| `Array.prototype.with` | 21 | 2 |
|
||||
| `Array.prototype.push` | 24 | 1 |
|
||||
| `Array.prototype.pop` | 23 | 1 |
|
||||
| `Array.prototype.shift` | 20 | 1 |
|
||||
| `Array.prototype.unshift` | 22 | 1 |
|
||||
| `Array.prototype.splice` | 81 | 3 |
|
||||
| `Array.prototype.fill` | 22 | 3 |
|
||||
| `Array.prototype.copyWithin` | 39 | 2 |
|
||||
| `Array.prototype.keys` | 12 | 1 |
|
||||
| `Array.prototype.values` | 12 | 1 |
|
||||
| `Array.prototype.entries` | 12 | 1 |
|
||||
| `Array.from` | 47 | 3 |
|
||||
| `Array.isArray` | 29 | 2 |
|
||||
| `Array.of` | 16 | 1 |
|
||||
|
||||
## Exclusions
|
||||
|
||||
Assertions are not adapted when they test behavior outside CodeMode's documented Array surface:
|
||||
|
||||
- Function metadata, property descriptors, constructibility, prototype mutation, species constructors, or cross-realm
|
||||
identity.
|
||||
- Generic receivers, detached methods, `.call`, `.apply`, boxed values, custom coercion objects, Symbols, BigInts,
|
||||
proxies, accessors, frozen arrays, typed arrays, or ArrayBuffers.
|
||||
- `Array.from` mappers, custom iterables, constructor substitution, and iterator-closing behavior.
|
||||
- Native iterator identity, `.next()`, completion records, or live iterator mutation. CodeMode deliberately materializes
|
||||
`keys`, `values`, and `entries` as arrays.
|
||||
- Sparse-array assertions that depend on literal elisions or inherited indexed properties. CodeMode's confined data
|
||||
model does not preserve those prototype and hole semantics at every boundary.
|
||||
- Argument coercions outside the accepted schema-like surface. Numeric positions must be numbers and `join` separators
|
||||
must be strings.
|
||||
- Exact native error brands where CodeMode exposes a safe runtime error instead.
|
||||
- Async/effectful callbacks, circular-data rejection, sandbox-value identity, diagnostics, and host-boundary behavior.
|
||||
Those remain covered by CodeMode-specific tests.
|
||||
|
||||
Handwritten tests remain where they specify CodeMode behavior rather than ordinary ECMAScript Array semantics.
|
||||
Loading…
Add table
Add a link
Reference in a new issue