feat(codemode): expand standard library parity (#37943)

This commit is contained in:
Aiden Cline 2026-07-20 09:59:37 -05:00 committed by GitHub
commit 3da0dea8e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 171 additions and 15 deletions

View file

@ -29,6 +29,11 @@
* - 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/toSpliced/holes-not-preserved.js
* - test/built-ins/Array/prototype/toSpliced/immutable.js
* - test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-undefineds.js
* - test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-missing.js
* - test/built-ins/Array/prototype/toSpliced/start-undefined-and-deleteCount-missing.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
@ -59,6 +64,8 @@
* 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.
* The toSpliced hole case omits the source test's inherited Array.prototype element because CodeMode does not expose
* prototype mutation; it retains the source test's hole-densification assertions.
*/
import { describe, expect, test } from "bun:test"
import { Effect } from "effect"
@ -227,6 +234,31 @@ const cases = [
code: `const input = ["first", "second", "third"]; const removed = input.splice(1); return [input, removed]`,
expected: [["first"], ["second", "third"]],
},
{
path: "test/built-ins/Array/prototype/toSpliced/immutable.js",
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]`,
expected: [[2, 0, 1], [-1, 2, 0, 1], [-1, 0, 1], true, true],
},
{
path: "test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-missing.js",
code: `const input = ["first", "second", "third"]; const result = input.toSpliced(); return [result, result !== input]`,
expected: [["first", "second", "third"], true],
},
{
path: "test/built-ins/Array/prototype/toSpliced/start-undefined-and-deleteCount-missing.js",
code: `return ["first", "second", "third"].toSpliced(undefined)`,
expected: [],
},
{
path: "test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-undefineds.js",
code: `const input = ["first", "second", "third"]; const result = input.toSpliced(undefined, undefined); return [result, result !== input]`,
expected: [["first", "second", "third"], true],
},
{
path: "test/built-ins/Array/prototype/toSpliced/holes-not-preserved.js",
code: `const input = [0, , 2, , 4]; const result = input.toSpliced(0, 0, -1); return [result, 2 in result, 4 in result]`,
expected: [[-1, 0, null, 2, null, 4], true, true],
},
{
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]]]`,

View file

@ -64,7 +64,7 @@ describe("H3: array property access reads as undefined (not a throw)", () => {
})
test("unknown property reads stay undefined for methods CodeMode does not implement", async () => {
expect(await value(`return [1,2,3].toSpliced === undefined`)).toBe(true)
expect(await value(`return [1,2,3].unknownMethod === undefined`)).toBe(true)
})
test("array indexing still works", async () => {

View file

@ -2,11 +2,16 @@
* Portions adapted from Test262 at revision 250f204f23a9249ff204be2baec29600faae7b75:
* - test/built-ins/Date/value-to-primitive-result-non-string-prim.js
* - test/built-ins/Date/value-to-primitive-result-string.js
* - test/built-ins/Date/prototype/toUTCString/format.js
* - test/built-ins/Date/prototype/toUTCString/invalid-date.js
* - test/built-ins/RegExp/prototype/exec/S15.10.6.2_A4_T8.js
*
* CodeMode does not support Symbol.toPrimitive, so these cases exercise the same Date-constructor primitive-result
* CodeMode does not support Symbol.toPrimitive, so the Date-constructor cases exercise the same primitive-result
* handling through supported own valueOf and toString functions.
*
* Copyright (C) 2016 the V8 project authors. All rights reserved.
* Copyright (C) 2017 the V8 project authors. 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"
@ -175,6 +180,25 @@ describe("Date", () => {
expect(await value(`return typeof new Date(0)`)).toBe("object")
expect(await value(`return new Date(0).nope === undefined`)).toBe(true)
})
test("toUTCString and toGMTString use the native UTC format", async () => {
expect(
await value(`
const date = new Date(0)
return [
date.toUTCString(),
date.toGMTString(),
new Date(NaN).toUTCString(),
new Date("0020-01-01T00:00:00Z").toUTCString(),
]
`),
).toEqual([
"Thu, 01 Jan 1970 00:00:00 GMT",
"Thu, 01 Jan 1970 00:00:00 GMT",
"Invalid Date",
"Wed, 01 Jan 0020 00:00:00 GMT",
])
})
})
describe("RegExp", () => {
@ -211,6 +235,51 @@ describe("RegExp", () => {
).toEqual(["1", "22"])
})
test("lastIndex is writable and exec coerces its stored value", async () => {
expect(
await value(`
const pattern = /(?:ab|cd)\\d?/g
pattern.lastIndex = "12"
const stored = [pattern.lastIndex, typeof pattern.lastIndex]
const match = pattern.exec("aacd2233ab12nm444ab42")
pattern.lastIndex = 0
return [stored, match[0], match.index, pattern.lastIndex, delete pattern.lastIndex]
`),
).toEqual([["12", "string"], "ab4", 17, 0, false])
})
test("exec coerces CodeMode data objects assigned to lastIndex", async () => {
expect(
await value(`
const pattern = /a/g
pattern.lastIndex = {}
const stored = pattern.lastIndex
const match = pattern.exec("ba")
pattern.lastIndex = 10
const missed = pattern.exec("a")
return [stored, match.index, pattern.lastIndex, missed]
`),
).toEqual([{}, 1, 0, null])
})
test("non-global exec and test coerce and preserve lastIndex", async () => {
expect(
await value(`
const execPattern = /a/
const execIndex = {}
execPattern.lastIndex = execIndex
const match = execPattern.exec("ba")
const testPattern = /a/
const testIndex = {}
testPattern.lastIndex = testIndex
const matched = testPattern.test("ba")
return [match.index, execPattern.lastIndex === execIndex, matched, testPattern.lastIndex === testIndex]
`),
).toEqual([1, true, true, true])
})
test("an unmatched string pattern returns null", async () => {
expect(await value(`return "abc".match(/\\d/)`)).toBeNull()
})