Ctrl K
ComunidadGuías…

packages/codemode/test/stdlib.test.ts

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/*
 * 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 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"
import { Effect, Schema } from "effect"
import { CodeMode, Tool } from "./lib/index.js"

// Standard-library value types: Date, RegExp, Map, Set. Programs use them as ordinary JS;
// intra-CodeMode checkpoints (Object.* helpers, spread, coercion inputs) preserve the live
// values. JSON.stringify keeps Date -> ISO string (invalid -> null), URL -> href, and
// RegExp/Map/Set/URLSearchParams -> {}. The host boundary matches that except URLSearchParams,
// which cross as their query string, and Set, which crosses as an array.
const run = (code: string) => Effect.runPromise(CodeMode.execute({ code, tools: {} }))
const value = async (code: string) => {
  const result = await run(code)
  if (!result.ok) throw new Error(`expected success, got ${result.error.kind}: ${result.error.message}`)
  return result.value
}
const error = async (code: string) => {
  const result = await run(code)
  if (result.ok) throw new Error(`expected failure, got value ${JSON.stringify(result.value)}`)
  return result.error
}

describe("Number and Math", () => {
  test("Number.toString truncates the radix before checking its range", async () => {
    expect(
      await value(`return [36.1, 36.9, "36.9", { valueOf() { return 36.9 } }].map(radix => (35).toString(radix))`),
    ).toEqual(["z", "z", "z", "z"])
  })

  test("Number.toString keeps invalid radixes catchable as RangeError", async () => {
    expect(
      await value(`return [0, 1.9, 37, NaN, Infinity, -Infinity].map(radix => {
        try { return (35).toString(radix) }
        catch (error) { return error instanceof RangeError }
      })`),
    ).toEqual([true, true, true, true, true, true])
    expect(await value(`return [(35).toString(), (35).toString(undefined), (35).toString(2.9)]`)).toEqual([
      "35",
      "35",
      "100011",
    ])
  })

  test("Math.random returns a number in [0, 1)", async () => {
    expect(await value(`const n = Math.random(); return typeof n === "number" && n >= 0 && n < 1`)).toBe(true)
  })

  test("Number exposes native non-finite constants", async () => {
    expect(
      await value(
        `return [Number.isNaN(Number.NaN), Number.POSITIVE_INFINITY === Infinity, Number.NEGATIVE_INFINITY === -Infinity]`,
      ),
    ).toEqual([true, true, true])
  })

  test("Number valueOf returns its primitive receiver", async () => {
    expect(await value(`return (42).valueOf()`)).toBe(42)
  })

  test("Number valueOf does not enable boxed numbers", async () => {
    const failure = await error(`return new Number(42)`)
    expect(failure.kind).toBe("ExecutionFailure")
    expect(failure.message).toContain("new Number(...) is not supported; call Number(...) without new instead.")
  })
})

describe("Date", () => {
  test("Date.now() returns a number", async () => {
    expect(await value(`return typeof Date.now()`)).toBe("number")
  })

  test("epoch construction and ISO rendering", async () => {
    expect(await value(`return new Date(0).toISOString()`)).toBe("1970-01-01T00:00:00.000Z")
  })

  test("string parsing round-trips", async () => {
    expect(await value(`return new Date("2024-01-02T03:04:05.000Z").getTime()`)).toBe(1704164645000)
    expect(await value(`return Date.parse("2024-01-02T03:04:05.000Z")`)).toBe(1704164645000)
  })

  test("one-argument construction coerces supported values like JavaScript", async () => {
    expect(
      await value(`return [new Date(true).getTime(), new Date(false).getTime(), new Date(null).getTime()]`),
    ).toEqual([1, 0, 0])
    expect(await value(`return Number.isNaN(new Date(undefined).getTime())`)).toBe(true)
    expect(await value(`return Number.isNaN(new Date([]).getTime())`)).toBe(true)
    expect(await value(`return new Date(["1970-01-01T00:00:00.000Z"]).getTime()`)).toBe(0)
    expect(await value(`return Number.isNaN(new Date({}).getTime())`)).toBe(true)
  })

  test("one-argument construction uses valueOf then toString for objects", async () => {
    expect(
      await value(`
        const calls = []
        const number = { valueOf: () => 8 }
        const text = {
          valueOf: () => { calls.push("valueOf"); return {} },
          toString: () => { calls.push("toString"); return "2016-06-05T18:40:00.000Z" },
        }
        return [new Date(number).getTime(), new Date(text).getTime(), calls]
      `),
    ).toEqual([8, 1465152000000, ["valueOf", "toString"]])

    expect(
      await value(`
        const values = [
          { valueOf: () => undefined },
          { valueOf: () => true },
          { valueOf: () => false },
          { valueOf: () => null },
        ]
        return values.map((item) => new Date(item).getTime())
      `),
    ).toEqual([null, 1, 0, 0])

    expect(
      await value(`
        try {
          new Date({ valueOf: () => ({}), toString: () => ({}) })
        } catch (error) {
          return error.name
        }
      `),
    ).toBe("TypeError")
  })

  test("date arithmetic and comparison use the time value", async () => {
    expect(await value(`const a = new Date(1000); const b = new Date(3000); return b - a`)).toBe(2000)
    expect(await value(`const a = new Date(1000); const b = new Date(3000); return a < b`)).toBe(true)
    expect(await value(`return +new Date(42)`)).toBe(42)
  })

  test("UTC getters read calendar components", async () => {
    expect(
      await value(
        `const d = new Date("2024-03-05T06:07:08.009Z"); return [d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()]`,
      ),
    ).toEqual([2024, 2, 5, 6, 7, 8, 9])
  })

  test("invalid dates yield NaN times, guardable in-CodeMode", async () => {
    expect(await value(`return Number.isNaN(new Date("garbage").getTime())`)).toBe(true)
    expect(await value(`return new Date("garbage").toJSON()`)).toBeNull()
  })

  test("toISOString on an invalid date throws RangeError", async () => {
    expect(await value(`try { new Date("garbage").toISOString() } catch (error) { return error.name }`)).toBe(
      "RangeError",
    )
  })

  test("template interpolation renders the ISO form", async () => {
    expect(await value("return `at ${new Date(0)}`")).toBe("at 1970-01-01T00:00:00.000Z")
  })

  test("dates serialize to ISO strings at the boundary, direct and nested", async () => {
    expect(await value(`return new Date(0)`)).toBe("1970-01-01T00:00:00.000Z")
    expect(await value(`return { when: new Date(0), tags: [new Date(1000)] }`)).toEqual({
      when: "1970-01-01T00:00:00.000Z",
      tags: ["1970-01-01T00:00:01.000Z"],
    })
    expect(await value(`return JSON.stringify({ d: new Date(0) })`)).toBe('{"d":"1970-01-01T00:00:00.000Z"}')
  })

  test("coercions: Number is the time, String is ISO, Boolean is true", async () => {
    expect(await value(`return Number(new Date(5))`)).toBe(5)
    expect(await value(`return String(new Date(0))`)).toBe("1970-01-01T00:00:00.000Z")
    expect(await value(`return Boolean(new Date(0))`)).toBe(true)
  })

  test("sorting dates with a numeric comparator", async () => {
    expect(
      await value(`
      const dates = [new Date(3000), new Date(1000), new Date(2000)]
      return dates.sort((a, b) => a - b).map((d) => d.getTime())
    `),
    ).toEqual([1000, 2000, 3000])
  })

  test("new Date(year, month, day) accepts component form", async () => {
    expect(await value(`const d = new Date(2024, 0, 2); return [d.getFullYear(), d.getMonth(), d.getDate()]`)).toEqual([
      2024, 0, 2,
    ])
  })

  test("typeof and unknown properties are forgiving", async () => {
    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", () => {
  test("literal test", async () => {
    expect(await value(`return /ab+c/.test("xabbbc")`)).toBe(true)
    expect(await value(`return /ab+c/.test("nope")`)).toBe(false)
  })

  test("exec exposes captures and index", async () => {
    expect(await value(`const m = /a(b+)/.exec("xxabbc"); return { full: m[0], group: m[1], index: m.index }`)).toEqual(
      {
        full: "abb",
        group: "bb",
        index: 2,
      },
    )
    expect(await value(`return /a/.exec("zzz")`)).toBeNull()
  })

  test("named groups read through", async () => {
    expect(
      await value(`const m = /(?<word>[a-z]+)-(?<num>\\d+)/.exec("id ab-42"); return m.groups.word + m.groups.num`),
    ).toBe("ab42")
  })

  test("global exec advances lastIndex across calls", async () => {
    expect(
      await value(`
      const r = /\\d+/g
      const first = r.exec("a1b22c")
      const second = r.exec("a1b22c")
      return [first[0], second[0]]
    `),
    ).toEqual(["1", "22"])
  })

  test("lastIndex is writable and stores a number", 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]
      `),
    ).toEqual([[12, "number"], "ab4", 17, 0])
    // lastIndex is a prototype accessor, so delete is a no-op rather than a TypeError.
    expect(await value(`const re = /a/; return [delete re.lastIndex, re.lastIndex]`)).toEqual([true, 0])
  })

  test("a non-numeric lastIndex runs from 0; non-global exec and test leave it alone", async () => {
    expect(
      await value(`
        const pattern = /a/g
        pattern.lastIndex = {}
        const match = pattern.exec("ba")
        pattern.lastIndex = 10
        const missed = pattern.exec("a")
        const plain = /a/
        plain.lastIndex = 5
        return [match.index, pattern.lastIndex, missed, plain.exec("ba").index, plain.test("ba"), plain.lastIndex]
      `),
    ).toEqual([1, 0, null, 1, true, 5])
  })

  test("String methods read and update lastIndex like exec", async () => {
    expect(
      await value(`
        const re = /a/y
        re.exec("aa")
        re.lastIndex = 0
        return ["aa".replace(re, "b"), re.lastIndex]
      `),
    ).toEqual(["ba", 1])
    expect(
      await value(`
        const re = /a/g
        re.exec("aaa")
        return ["aaa".match(re), re.lastIndex]
      `),
    ).toEqual([["a", "a", "a"], 0])
    expect(
      await value(`
        const re = /a/g
        re.lastIndex = 2
        return ["aaa".replace(re, () => "b"), re.lastIndex]
      `),
    ).toEqual(["bbb", 0])
    expect(
      await value(`
        const re = /a/g
        re.lastIndex = 2
        return ["aaa".replaceAll(re, "b"), re.lastIndex]
      `),
    ).toEqual(["bbb", 0])
    expect(
      await value(`
        const re = /a/y
        re.lastIndex = 1
        const m = "baa".match(re)
        return [m.index, re.lastIndex]
      `),
    ).toEqual([1, 2])
  })

  test("split, search, and matchAll leave lastIndex unchanged like JS", async () => {
    expect(
      await value(`
        const re = /a/y
        re.lastIndex = 2
        return ["banana".split(re), re.lastIndex]
      `),
    ).toEqual([["b", "n", "n", ""], 2])
    expect(
      await value(`
        const re = /a/g
        re.lastIndex = 2
        return ["banana".search(re), re.lastIndex]
      `),
    ).toEqual([1, 2])
    expect(
      await value(`
        const re = /a/y
        re.lastIndex = 2
        return ["banana".search(re), re.lastIndex]
      `),
    ).toEqual([-1, 2])
    expect(
      await value(`
        const re = /a/g
        re.lastIndex = 2
        return ["banana".matchAll(re).map((m) => m.index), re.lastIndex]
      `),
    ).toEqual([[3, 5], 2])
    expect(
      await value(`
        const re = /a/gy
        re.lastIndex = 1
        return ["banana".matchAll(re).map((m) => m.index), re.lastIndex]
      `),
    ).toEqual([[1], 1])
  })

  test("String methods leave lastIndex untouched without g or y", async () => {
    expect(
      await value(`
        const re = /a/
        re.lastIndex = 5
        return ["aaa".replace(re, "b"), "aaa".match(re).index, "aaa".split(re), "aaa".search(re), re.lastIndex]
      `),
    ).toEqual(["baa", 0, ["", "", "", ""], 0, 5])
  })

  test("an unmatched string pattern returns null", async () => {
    expect(await value(`return "abc".match(/\\d/)`)).toBeNull()
  })

  test("matchAll materializes match arrays with captures", async () => {
    expect(await value(`return "a1b22".matchAll(/(\\d+)/g).map((m) => m[1])`)).toEqual(["1", "22"])
  })

  test("function replacers receive captures, offsets, input, and named groups", async () => {
    expect(
      await value(`
        const seen = []
        const output = "a1b22".replace(/(\\d)(\\d)?/g, (match, first, second, offset, input) => {
          seen.push([match, first, second === undefined, offset, input])
          return Number(match) * 2
        })
        return { output, seen }
      `),
    ).toEqual({
      output: "a2b44",
      seen: [
        ["1", "1", true, 1, "a1b22"],
        ["22", "2", false, 3, "a1b22"],
      ],
    })
    expect(
      await value(`
        return "red-blue".replace(
          /(?<left>[a-z]+)-(?<right>[a-z]+)/,
          (match, left, right, offset, input, groups) => groups.right + ":" + groups.left,
        )
      `),
    ).toBe("blue:red")
  })

  test("function replacers support string searches, zero-length matches, and result coercion", async () => {
    expect(await value(`return "banana".replace("na", (match, offset, input) => "[" + offset + "]")`)).toBe("ba[2]na")
    expect(await value(`return "ab".replaceAll("", (match, offset) => offset)`)).toBe("0a1b2")
    expect(await value(`return "😀".replaceAll(/(?:)/gu, (match, offset) => "[" + offset + "]")`)).toBe("[0]😀[2]")
    expect(
      await value(`return "123".replace(/\\d/g, (match) => match === "1" ? 7 : match === "2" ? null : { n: 3 })`),
    ).toBe("7null[object Object]")
  })

  test("promise-returning string replacers are coerced synchronously", async () => {
    const decorate = Tool.make({
      description: "Decorate a string",
      input: Schema.String,
      output: Schema.String,
      execute: (input) => Effect.succeed(`[${input}]`),
    })
    const result = await Effect.runPromise(
      CodeMode.execute({
        tools: { host: { decorate } },
        code: `return "a1b22".replace(/\\d+/g, async (match) => await tools.host.decorate(match))`,
      }),
    )
    expect(result.ok && result.value).toBe("a[object Promise]b[object Promise]")

    const missingAwait = await Effect.runPromise(
      CodeMode.execute({
        tools: { host: { decorate } },
        code: `return "a1".replace(/\\d/, (match) => tools.host.decorate(match))`,
      }),
    )
    expect(missingAwait.ok && missingAwait.value).toBe("a[object Promise]")
  })

  test("replaceAll without the g flag is a catchable error", async () => {
    expect(await value(`try { "a".replaceAll(/a/, "b"); return "no" } catch { return "caught" }`)).toBe("caught")
  })

  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")
    expect(await value(`return [/a/ instanceof RegExp, /a/.source]`)).toEqual([true, "a"])
  })

  test("invalid patterns fail with actionable messages", async () => {
    const fromString = await error(`return "abc".match("(")`)
    expect(fromString.message).toContain('String.match received the string "("')
    expect(fromString.message).toContain("escape them with a backslash")

    const fromConstructor = await error(`return new RegExp("(")`)
    expect(fromConstructor.message).toContain('new RegExp(...) received "("')
    expect(fromConstructor.message).toContain("escape them with a backslash")

    const fromFlags = await error(`return new RegExp("a", "xz")`)
    expect(fromFlags.message).toContain('invalid flags "xz"')
    expect(fromFlags.message).toContain("Valid flags are")
  })

  test("missing g-flag errors say how to fix the call", async () => {
    expect((await error(`return "aa".replaceAll(/a/, "b")`)).message).toContain("write /a/g, or use String.replace")
    expect((await error(`return "aa".matchAll(/a/)`)).message).toContain("write /a/g, or use String.match")
  })

  test("any argument is a pattern string, as new RegExp(arg) reads it", async () => {
    expect(
      await value(
        `return ["a42b".match(42)[0], "xnullx".search(null), "abc".match(undefined), [..."1a1".matchAll(1)].length]`,
      ),
    ).toEqual(["42", 1, [""], 2])
  })

  test("source and flags properties read through", async () => {
    expect(await value(`const r = /ab/gi; return { source: r.source, flags: r.flags, global: r.global }`)).toEqual({
      source: "ab",
      flags: "gi",
      global: true,
    })
  })

  test("regexes serialize as {} like JSON.stringify, at the boundary and inside the program", async () => {
    expect(await value(`return [/a/, { r: /b/gi }]`)).toEqual([{}, { r: {} }])
    expect(await value(`return JSON.stringify({ r: /a/g })`)).toBe('{"r":{}}')
  })

  test("template interpolation renders the literal form", async () => {
    expect(await value("return `${/ab/g}`")).toBe("/ab/g")
  })
})

describe("URL and URI helpers", () => {
  test("encodes and decodes complete URIs and URI components", async () => {
    expect(
      await value(`
        return [
          encodeURI("https://example.test/a b?q=a/b"),
          encodeURIComponent("a b/c?"),
          decodeURI("https://example.test/a%20b?q=a/b"),
          decodeURIComponent("a%20b%2Fc%3F"),
          ["a b", "c/d"].map(encodeURIComponent),
        ]
      `),
    ).toEqual([
      "https://example.test/a%20b?q=a/b",
      "a%20b%2Fc%3F",
      "https://example.test/a b?q=a/b",
      "a b/c?",
      ["a%20b", "c%2Fd"],
    ])
    expect(
      await value(`try { decodeURIComponent("%zz"); return false } catch (error) { return error instanceof URIError }`),
    ).toBe(true)
  })

  test("resolves and mutates URLs with linked search parameters", async () => {
    expect(
      await value(`
        const url = new URL("../users?id=old#top", "https://user:pass@example.com:8443/api/v1/")
        url.pathname = "/items/a b"
        url.searchParams.set("id", "a b")
        url.searchParams.append("tag", "x/y")
        url.hash = "part 1"
        return {
          href: url.href,
          origin: url.origin,
          host: url.host,
          pathname: url.pathname,
          search: url.search,
          id: url.searchParams.get("id"),
          string: String(url),
          json: url.toJSON(),
          instances: [
            url instanceof URL,
            url.searchParams instanceof URLSearchParams,
            url.searchParams === url.searchParams,
          ],
        }
      `),
    ).toEqual({
      href: "https://user:pass@example.com:8443/items/a%20b?id=a+b&tag=x%2Fy#part%201",
      origin: "https://example.com:8443",
      host: "example.com:8443",
      pathname: "/items/a%20b",
      search: "?id=a+b&tag=x%2Fy",
      id: "a b",
      string: "https://user:pass@example.com:8443/items/a%20b?id=a+b&tag=x%2Fy#part%201",
      json: "https://user:pass@example.com:8443/items/a%20b?id=a+b&tag=x%2Fy#part%201",
      instances: [true, true, true],
    })
  })

  test("URLSearchParams supports records, pairs, mutation, callbacks, and materialization", async () => {
    expect(
      await value(`
        const params = new URLSearchParams([["tag", "b"], ["tag", "a"], ["q", "a b"]])
        const seen = []
        params.forEach((value, key) => seen.push(key + "=" + value))
        params.delete("tag", "b")
        params.append("tag", "c")
        params.sort()
        return {
          text: params.toString(),
          size: params.size,
          tags: params.getAll("tag"),
          has: params.has("tag", "c"),
          entries: Array.from(params),
          object: Object.fromEntries(params),
          record: new URLSearchParams({ page: 2, filter: "open" }).toString(),
          seen,
        }
      `),
    ).toEqual({
      text: "q=a+b&tag=a&tag=c",
      size: 3,
      tags: ["a", "c"],
      has: true,
      entries: [
        ["q", "a b"],
        ["tag", "a"],
        ["tag", "c"],
      ],
      object: { q: "a b", tag: "c" },
      record: "page=2&filter=open",
      seen: ["tag=b", "tag=a", "q=a b"],
    })
  })

  test("URL parsing failures are catchable and values use native JSON forms", async () => {
    expect(
      await value(`
        const parsed = URL.parse("/users", "https://example.test/api/")
        let invalidIsTypeError = false
        try { new URL("not relative without a base") } catch (error) { invalidIsTypeError = error instanceof TypeError }
        return {
          canParse: URL.canParse("/users", "https://example.test/api/"),
          cannotParse: URL.canParse("not relative without a base"),
          parsed: parsed.href,
          invalidIsTypeError,
          boundary: [new URL("https://example.test/a"), new URLSearchParams("q=one")],
          json: JSON.stringify({ url: new URL("https://example.test/a"), params: new URLSearchParams("q=one") }),
        }
      `),
    ).toEqual({
      canParse: true,
      cannotParse: false,
      parsed: "https://example.test/users",
      invalidIsTypeError: true,
      boundary: ["https://example.test/a", "q=one"],
      json: '{"url":"https://example.test/a","params":{}}',
    })
  })

  test("distinguishes omitted URL arguments from explicit undefined", async () => {
    expect(
      await value(`
        function throwsTypeError(run) {
          try { run(); return false } catch (error) { return error instanceof TypeError }
        }
        const params = new URLSearchParams()
        const required = [
          () => params.append(),
          () => params.delete(),
          () => params.get(),
          () => params.getAll(),
          () => params.has(),
          () => params.set(),
          () => params.forEach(),
        ].map(throwsTypeError)
        params.append(undefined, undefined)
        return {
          construct: throwsTypeError(() => new URL()),
          canParse: throwsTypeError(() => URL.canParse()),
          parse: throwsTypeError(() => URL.parse()),
          explicitUndefined: new URL(undefined, "https://example.test/base/").href,
          params: params.toString(),
          required,
        }
      `),
    ).toEqual({
      construct: true,
      canParse: true,
      parse: true,
      explicitUndefined: "https://example.test/base/undefined",
      params: "undefined=undefined",
      required: [true, true, true, true, true, true, true],
    })
  })
})

describe("Headers", () => {
  test("constructs from records, pairs, Maps, and Headers; names fold to lowercase and values combine", async () => {
    expect(
      await value(`
        const headers = new Headers({ "Content-Type": "text/plain", "X-Count": 1, "X-Null": null })
        headers.append("Accept", "text/html")
        headers.append("accept", "application/json")
        headers.set("x-count", "2")
        headers.delete("x-null")
        const copy = new Headers(headers)
        copy.set("content-type", "text/html")
        return {
          get: headers.get("content-type"),
          missing: headers.get("x-missing"),
          combined: headers.get("ACCEPT"),
          has: [headers.has("Accept"), headers.has("x-null")],
          count: headers.get("x-count"),
          copied: [headers.get("content-type"), copy.get("content-type")],
          pairs: [...new Headers([["b", "2"], ["A", "1"]])],
          map: [...new Headers(new Map([["k", "v"]]))],
          keys: [...headers.keys()],
          values: [...headers.values()],
          entries: [...headers.entries()],
        }
      `),
    ).toEqual({
      get: "text/plain",
      missing: null,
      combined: "text/html, application/json",
      has: [true, false],
      count: "2",
      copied: ["text/plain", "text/html"],
      pairs: [
        ["a", "1"],
        ["b", "2"],
      ],
      map: [["k", "v"]],
      keys: ["accept", "content-type", "x-count"],
      values: ["text/html, application/json", "text/plain", "2"],
      entries: [
        ["accept", "text/html, application/json"],
        ["content-type", "text/plain"],
        ["x-count", "2"],
      ],
    })
  })

  test("iterates in sorted order everywhere iteration is allowed, and getSetCookie keeps cookies apart", async () => {
    expect(
      await value(`
        const headers = new Headers({ b: "2", a: "1" })
        headers.append("Set-Cookie", "x=1")
        headers.append("set-cookie", "y=2")
        const seen = []
        headers.forEach((value, name, self) => seen.push(name + "=" + value + ":" + (self === headers)))
        const [first] = headers
        function* pairs() { yield* headers }
        return {
          seen,
          first,
          spread: [...headers],
          from: Array.from(headers).length,
          generator: [...pairs()].length,
          object: Object.fromEntries(headers),
          cookies: headers.getSetCookie(),
        }
      `),
    ).toEqual({
      seen: ["a=1:true", "b=2:true", "set-cookie=x=1:true", "set-cookie=y=2:true"],
      first: ["a", "1"],
      spread: [
        ["a", "1"],
        ["b", "2"],
        ["set-cookie", "x=1"],
        ["set-cookie", "y=2"],
      ],
      from: 4,
      generator: 4,
      object: { a: "1", b: "2", "set-cookie": "y=2" },
      cookies: ["x=1", "y=2"],
    })
  })

  test("serializes as a name-to-value object at the boundary and in JSON; prints for console", async () => {
    const result = await run(`
      const headers = new Headers({ "X-A": "1", b: "2" })
      console.log(headers)
      return { headers, json: JSON.stringify({ headers }), text: String(headers), type: typeof headers, is: headers instanceof Headers }
    `)
    expect(result.ok && result.value).toEqual({
      headers: { b: "2", "x-a": "1" },
      json: '{"headers":{"b":"2","x-a":"1"}}',
      text: "[object Headers]",
      type: "object",
      is: true,
    })
    expect(result.ok && result.logs?.[0]).toBe('Headers {"b":"2","x-a":"1"}')
  })

  test("rejects what it cannot build from, and invalid names and values, with TypeErrors the program can catch", async () => {
    expect(
      await value(`
        function message(run) {
          try { run(); return null } catch (error) { return error instanceof TypeError ? error.message : error }
        }
        const headers = new Headers()
        return [
          message(() => Headers()),
          message(() => new Headers(null)),
          message(() => new Headers(1)),
          message(() => new Headers("a=1")),
          message(() => new Headers(new Date())),
          message(() => new Headers(() => 1)),
          message(() => new Headers([["name"]])),
          message(() => new Headers([["a", "b", "c"]])),
          message(() => new Headers({ "bad name": "x" })),
          message(() => new Headers({ name: "bad\u0000value" })),
          message(() => headers.get("invalid\u0100")),
          message(() => headers.has({})),
          message(() => headers.set("a", "invalid\u0100")),
          message(() => headers.append("a")),
          message(() => headers.forEach()),
          message(() => headers.forEach(1)),
          message(() => { const get = headers.get; return get("a") }),
        ]
      `),
    ).toEqual([
      "Constructor Headers requires 'new'.",
      "new Headers(...) expects a record of names to values, iterable [name, value] pairs, or Headers.",
      "new Headers(...) expects a record of names to values, iterable [name, value] pairs, or Headers.",
      "new Headers(...) expects a record of names to values, iterable [name, value] pairs, or Headers.",
      "new Headers(...) expects a record of names to values, iterable [name, value] pairs, or Headers.",
      "new Headers(...) expects a record of names to values, iterable [name, value] pairs, or Headers.",
      "new Headers(...) expects iterable [name, value] pairs.",
      "new Headers(...) expects iterable [name, value] pairs.",
      expect.stringContaining("bad name"),
      expect.stringContaining("invalid value"),
      expect.stringContaining("Invalid header name"),
      expect.stringContaining("[object Object]"),
      expect.stringContaining("invalid value"),
      "Headers.append requires 2 arguments.",
      "Headers.forEach requires 1 argument.",
      "Headers.forEach expects a function callback.",
      "Headers.prototype.get called on incompatible receiver undefined.",
    ])
  })
})

describe("Map", () => {
  test("get/set/has/size with chaining", async () => {
    expect(
      await value(`
      const m = new Map()
      m.set("a", 1).set("b", 2)
      return { a: m.get("a"), b: m.get("b"), has: m.has("a"), miss: m.get("zz") === undefined, size: m.size }
    `),
    ).toEqual({ a: 1, b: 2, has: true, miss: true, size: 5 - 3 })
  })

  test("object keys use identity", async () => {
    expect(
      await value(`
      const key = { id: 1 }
      const m = new Map()
      m.set(key, "hit")
      return [m.get(key), m.get({ id: 1 }) === undefined]
    `),
    ).toEqual(["hit", true])
  })

  test("construction from entry pairs and another Map", async () => {
    expect(await value(`const m = new Map([["a", 1], ["b", 2]]); return m.get("b")`)).toBe(2)
    expect(
      await value(
        `const m = new Map([["a", 1]]); const n = new Map(m); n.set("b", 2); return [n.get("a"), n.get("b"), m.has("b")]`,
      ),
    ).toEqual([1, 2, false])
    expect((await error(`return new Map("nope")`)).message).toMatch(/\[key, value\] pairs/)
    expect((await error(`return new Map(["flat"])`)).message).toMatch(/\[key, value\] pairs/)
  })

  test("keys/values/entries return live iterators", async () => {
    expect(
      await value(`
      const m = new Map([["a", 1], ["b", 2]])
      const keys = m.keys()
      const first = keys.next()
      m.set("c", 3)
      return { first, rest: [...keys], values: [...m.values()], entries: [...m.entries()], same: [...m[Symbol.iterator]()] }
    `),
    ).toEqual({
      first: { value: "a", done: false },
      rest: ["b", "c"],
      values: [1, 2, 3],
      entries: [
        ["a", 1],
        ["b", 2],
        ["c", 3],
      ],
      same: [
        ["a", 1],
        ["b", 2],
        ["c", 3],
      ],
    })
  })

  test("Object.fromEntries(map) and Array.from(map)", async () => {
    expect(await value(`return Object.fromEntries(new Map([["a", 1], ["b", 2]]))`)).toEqual({ a: 1, b: 2 })
    expect(await value(`return Array.from(new Map([["a", 1]]))`)).toEqual([["a", 1]])
  })

  test("for...of iterates [key, value] pairs with destructuring", async () => {
    expect(
      await value(`
      const m = new Map([["a", 1], ["b", 2]])
      let total = 0
      let names = ""
      for (const [key, count] of m) { names += key; total += count }
      return names + total
    `),
    ).toBe("ab3")
  })

  test("spread produces entry pairs", async () => {
    expect(await value(`return [...new Map([["a", 1]])]`)).toEqual([["a", 1]])
  })

  test("forEach passes (value, key)", async () => {
    expect(
      await value(`
      const m = new Map([["a", 1], ["b", 2]])
      const seen = []
      m.forEach((count, key) => seen.push(key + count))
      return seen
    `),
    ).toEqual(["a1", "b2"])
  })

  test("delete and clear", async () => {
    expect(
      await value(`
      const m = new Map([["a", 1], ["b", 2]])
      const removed = m.delete("a")
      const missed = m.delete("zz")
      const sizeAfterDelete = m.size
      m.clear()
      return [removed, missed, sizeAfterDelete, m.size]
    `),
    ).toEqual([true, false, 1, 0])
  })

  test("counting idiom: grouped tallies", async () => {
    expect(
      await value(`
      const words = ["a", "b", "a", "c", "a"]
      const counts = new Map()
      for (const word of words) counts.set(word, (counts.get(word) ?? 0) + 1)
      return Object.fromEntries(counts)
    `),
    ).toEqual({ a: 3, b: 1, c: 1 })
  })

  test("getOrInsert and getOrInsertComputed insert only when the key is missing", async () => {
    expect(
      await value(`
      const groups = new Map()
      groups.getOrInsert("a", []).push(1)
      groups.getOrInsert("a", []).push(2)
      let calls = 0
      const computed = (key) => { calls++; return key + "!" }
      const first = groups.getOrInsertComputed("b", computed)
      const second = groups.getOrInsertComputed("b", computed)
      const zero = groups.getOrInsertComputed(-0, (key) => 1 / key === Infinity)
      return [[...groups], first, second, calls, zero]
    `),
    ).toEqual([
      [
        ["a", [1, 2]],
        ["b", "b!"],
        [0, true],
      ],
      "b!",
      "b!",
      1,
      true,
    ])
    expect(
      await value(`
      const m = new Map()
      const outer = m.getOrInsertComputed("k", () => { m.set("k", "inner"); return "outer" })
      let thrown
      try { m.getOrInsertComputed("j", () => { throw new Error("boom") }) } catch (error) { thrown = error.message }
      return [outer, m.get("k"), thrown, m.has("j")]
    `),
    ).toEqual(["outer", "outer", "boom", false])
    expect((await error(`new Map().getOrInsertComputed("k", 5)`)).message).toContain("expects a function callback")
  })

  test("maps serialize to {} at the boundary, like JSON", async () => {
    expect(await value(`return new Map([["a", 1]])`)).toEqual({})
    expect(await value(`return JSON.stringify(new Map([["a", 1]]))`)).toBe("{}")
  })

  test("console.log renders map contents for debugging", async () => {
    const result = await run(`console.log(new Map([["a", 1]])); return null`)
    expect(result.ok).toBe(true)
    expect(result.logs?.[0]).toBe(`Map(1) [["a",1]]`)
  })
})

describe("Set", () => {
  test("forEach is live on Map and Set: deleted entries are skipped and added ones visited", async () => {
    expect(
      await value(`
        const m = new Map([[1, "a"], [2, "b"]])
        const s = new Set([1, 2])
        const seen = []
        m.forEach((v, k) => { seen.push(k); if (k === 1) { m.delete(2); m.set(3, "c") } })
        s.forEach((v) => { seen.push(v); if (v === 1) { s.delete(2); s.add(3) } })
        return seen
      `),
    ).toEqual([1, 3, 1, 3])
  })

  test("add/has/delete/size with chaining", async () => {
    expect(
      await value(`
      const s = new Set()
      s.add(1).add(2).add(1)
      const removed = s.delete(2)
      return [s.size, s.has(1), s.has(2), removed]
    `),
    ).toEqual([1, true, false, true])
  })

  test("dedupe idiom: [...new Set(items)]", async () => {
    expect(await value(`return [...new Set([1, 2, 2, 3, 1])]`)).toEqual([1, 2, 3])
  })

  test("construction from strings and other Sets", async () => {
    expect(await value(`return [...new Set("aba")]`)).toEqual(["a", "b"])
    expect(await value(`return Array.from(new Set(new Set([1, 2])))`)).toEqual([1, 2])
  })

  test("SameValueZero: NaN is findable", async () => {
    expect(await value(`const s = new Set([NaN]); return s.has(NaN)`)).toBe(true)
  })

  test("for...of iterates values", async () => {
    expect(
      await value(`
      let total = 0
      for (const n of new Set([1, 2, 3])) total += n
      return total
    `),
    ).toBe(6)
  })

  test("sets cross the boundary as arrays; JSON.stringify keeps {} like JS", async () => {
    expect(await value(`return { s: new Set([1, "a", { n: 1 }, undefined]) }`)).toEqual({ s: [1, "a", { n: 1 }, null] })
    expect(await value(`return JSON.stringify(new Set([1]))`)).toBe("{}")
  })
})

describe("Uint8Array", () => {
  test("from maps the original values with thisArg, after consuming the source", async () => {
    expect(
      await value(`
        const events = []
        function* source() {
          events.push("start")
          yield 300
          events.push("end")
        }
        return [
          [...Uint8Array.from([300, 2], (value, index) => value / 2 + index)],
          [...Uint8Array.from(new Uint8Array([2, 3]), (value, index) => value + 255 + index)],
          [...Uint8Array.from([1, 2], function (value, index) { return value + index + this.offset }, { offset: 5 })],
          [...Uint8Array.from(atob("aGk="), (c) => c.charCodeAt(0))],
          [...Uint8Array.from([300, 2], undefined)],
          [...Uint8Array.from(source(), (value) => { events.push("map"); return value })],
          events,
        ]
      `),
    ).toEqual([[150, 2], [1, 3], [6, 8], [104, 105], [44, 2], [44], ["start", "end", "map"]])
  })

  test("from rejects a non-callable mapper even for an empty source", async () => {
    for (const mapper of ["42", "null", "{}"]) {
      expect((await error(`return Uint8Array.from([], ${mapper}).length`)).message).toContain(
        "TypeError: Uint8Array.from expects a function callback",
      )
    }
  })

  test("constructs from a length, an array, an iterable, or another Uint8Array", async () => {
    expect(
      await value(`
      const a = new Uint8Array(2)
      const b = new Uint8Array([1, 2, 300])
      const c = Uint8Array.from(new Set([7, 8]))
      const d = new Uint8Array(b)
      d[0] = 9
      return [[...a], [...b], [...c], [...d], [...b], new Uint8Array("3").length, [...Uint8Array.of(1, "2")]]
    `),
    ).toEqual([[0, 0], [1, 2, 44], [7, 8], [9, 2, 44], [1, 2, 44], 3, [1, 2]])
    expect((await error(`new Uint8Array(-1)`)).message).toContain("Invalid typed array length: -1")
    expect((await error(`new Uint8Array(1.5)`)).message).toContain("Invalid typed array length")
    expect((await error(`new Uint8Array(20_000_000)`)).message).toContain("Invalid array length")
    expect((await error(`Uint8Array.from(/x/)`)).message).toContain("received a RegExp")
  })

  test("index reads and writes clamp to a byte and ignore out-of-range writes, like JS", async () => {
    expect(
      await value(`
      const b = new Uint8Array(3)
      b[0] = 300
      b[1] = -1
      b["2"] = "7"
      b[5] = 9
      b.tag = "x"
      return [b[0], b[1], b[2], b[5], b.length, Object.keys(b), 1 in b, 5 in b, b.tag]
    `),
    ).toEqual([44, 255, 7, null, 3, ["0", "1", "2", "tag"], true, false, "x"])
    expect((await error(`delete new Uint8Array(1)[0]`)).message).toContain("Cannot delete property '0'")
    expect((await error(`Uint8Array.prototype.length`)).message).toContain("incompatible receiver")
  })

  test("iteration, spread, destructuring, and Array.from", async () => {
    expect(
      await value(`
      const b = new Uint8Array([1, 2, 3])
      const [x, ...rest] = b
      const seen = []
      for (const byte of b) seen.push(byte)
      function* g() { yield* b }
      return [x, rest, seen, [...g()], Array.from(b, (n) => n * 2), new Set(b).size, Array.isArray(b)]
    `),
    ).toEqual([1, [2, 3], [1, 2, 3], [1, 2, 3], [2, 4, 6], 3, false])
  })

  test("methods", async () => {
    expect(
      await value(`
      const b = Uint8Array.from([1, 2, 3, 2])
      const view = b.subarray(1, 3)
      view.fill(9)
      const copy = b.slice(0, 2)
      copy[0] = 5
      const target = new Uint8Array(4)
      target.set([1, 2], 2)
      target.set(b.subarray(0, 1))
      return [
        b.at(-1), [...b], [...copy], [...target], b.indexOf(9), b.lastIndexOf(9), b.includes(3), b.includes(2, 1),
        b.join("-"), b.toString(), [...b.keys()], [...b.values()], [...b.entries()], [...Uint8Array.from([1, 2]).reverse()],
      ]
    `),
    ).toEqual([
      2,
      [1, 9, 9, 2],
      [5, 9],
      [1, 0, 1, 2],
      1,
      2,
      false,
      true,
      "1-9-9-2",
      "1,9,9,2",
      [0, 1, 2, 3],
      [1, 9, 9, 2],
      [
        [0, 1],
        [1, 9],
        [2, 9],
        [3, 2],
      ],
      [2, 1],
    ])
    expect((await error(`new Uint8Array(2).set([1, 2, 3])`)).message).toContain("does not fit")
    expect((await error(`new Uint8Array(2).set([1], 2)`)).message).toContain("does not fit")
  })

  test("base64 and hex", async () => {
    expect(
      await value(`
      return [
        new Uint8Array([104, 105]).toBase64(), new Uint8Array([255, 0]).toHex(),
        [...Uint8Array.fromBase64("aGk=")], [...Uint8Array.fromHex("ff00")],
      ]
    `),
    ).toEqual(["aGk=", "ff00", [104, 105], [255, 0]])
    expect(await error(`Uint8Array.fromBase64("!!!")`)).toMatchObject({
      message: expect.stringContaining("SyntaxError"),
    })
    expect(await error(`Uint8Array.fromHex("zz")`)).toMatchObject({ message: expect.stringContaining("SyntaxError") })
  })

  test("coercion, console, JSON, and Object.prototype.toString", async () => {
    expect(
      await value(`
      const b = new Uint8Array([1, 2])
      console.log(b, new Uint8Array())
      return [String(b), b + "", +new Uint8Array([5]), Number.isNaN(Number(b)), b == "1,2", JSON.stringify(b), b.toLocaleString(), typeof b, b instanceof Uint8Array]
    `),
    ).toEqual(["1,2", "1,2", 5, true, true, '{"0":1,"1":2}', "1,2", "object", true])
    expect((await run(`console.log(new Uint8Array([1, 2]), new Uint8Array())`)).logs).toEqual([
      "Uint8Array(2) [1,2] Uint8Array(0) []",
    ])
  })

  test("cannot cross the tool boundary; the error says how to encode it", async () => {
    expect((await error(`return new Uint8Array(1)`)).message).toContain("pass text instead")
    expect((await error(`return { deep: [new Uint8Array(1)] }`)).message).toContain("bytes.toBase64()")
    expect(await value(`return new Uint8Array([7, 8]).toBase64()`)).toBe("Bwg=")
  })
})

describe("TextEncoder and TextDecoder", () => {
  test("encodes null as text while omitted and undefined inputs stay empty", async () => {
    expect(
      await value(`
        const encoder = new TextEncoder()
        return [[...encoder.encode(null)], [...encoder.encode()], [...encoder.encode(undefined)]]
      `),
    ).toEqual([[110, 117, 108, 108], [], []])
  })

  test("round-trips UTF-8 and exposes the standard fields", async () => {
    expect(
      await value(`
      const encoder = new TextEncoder()
      const bytes = encoder.encode("héllo ✓")
      const decoder = new TextDecoder()
      return [
        [...bytes], decoder.decode(bytes), decoder.decode(), [...encoder.encode()], encoder.encoding,
        decoder.encoding, decoder.fatal, decoder.ignoreBOM, new TextDecoder("UTF8", { fatal: true }).fatal,
        new TextDecoder().decode(new Uint8Array([0xef, 0xbb, 0xbf, 0x41])),
        new TextDecoder("utf-8", { ignoreBOM: true }).decode(new Uint8Array([0xef, 0xbb, 0xbf, 0x41])),
        new TextDecoder().decode(new Uint8Array([0xff])),
        encoder instanceof TextEncoder, decoder instanceof TextDecoder,
      ]
    `),
    ).toEqual([
      [104, 195, 169, 108, 108, 111, 32, 226, 156, 147],
      "héllo ✓",
      "",
      [],
      "utf-8",
      "utf-8",
      false,
      false,
      true,
      "A",
      "\ufeffA",
      "\ufffd",
      true,
      true,
    ])
  })

  test("only UTF-8 is supported; fatal decoding rejects malformed input", async () => {
    expect((await error(`new TextDecoder("latin1")`)).message).toContain('The "latin1" encoding is not supported')
    expect((await error(`new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array([0xff]))`)).message).toContain(
      "not valid utf-8",
    )
    expect((await error(`new TextDecoder().decode("text")`)).message).toContain(
      "expects a Uint8Array, received a string",
    )
    expect((await error(`TextDecoder()`)).message).toContain("requires 'new'")
  })

  test("crypto.getRandomValues fills the given bytes in place", async () => {
    expect(
      await value(
        `const b = new Uint8Array(16); const same = crypto.getRandomValues(b) === b; return [same, b.length, b.some((n) => n !== 0)]`,
      ),
    ).toEqual([true, 16, true])
    expect((await error(`crypto.getRandomValues([1])`)).message).toContain("expects a Uint8Array, received an array")
  })
})

describe("Iterator helpers", () => {
  test("lazy helpers chain over collection iterators and generators, one source step per result", async () => {
    expect(
      await value(`
        const pulled = []
        function* naturals() { let n = 0; while (true) { pulled.push(n); yield n++ } }
        const squares = naturals().map((n) => n * n).filter((n) => n % 2 === 0).drop(1).take(3)
        const first = squares.next()
        return {
          first,
          rest: squares.toArray(),
          after: squares.next(),
          pulled,
          values: new Map([["a", 1], ["b", 2]]).values().map((v, i) => v * 10 + i).toArray(),
          flat: [1, 2].values().flatMap((n) => [n, [n]]).toArray(),
          entries: [...new Map([[1, 2]]).entries().map(([k, v]) => k + v)],
        }
      `),
    ).toEqual({
      first: { value: 4, done: false },
      rest: [16, 36],
      after: { done: true },
      pulled: [0, 1, 2, 3, 4, 5, 6],
      values: [10, 21],
      flat: [1, [1], 2, [2]],
      entries: [3],
    })
  })

  test("eager helpers consume the source and close it on early exit", async () => {
    expect(
      await value(`
        const log = []
        function* g() { try { yield 1; yield 2; yield 3 } finally { log.push("closed") } }
        const seen = []
        g().forEach((v, i) => seen.push([v, i]))
        return {
          seen,
          sum: g().reduce((a, b) => a + b),
          sumFrom: g().reduce((a, b) => a + b, 10),
          some: g().some((v) => v === 2),
          every: g().every((v) => v < 2),
          find: g().find((v) => v > 1),
          missing: g().find((v) => v > 5),
          log,
        }
      `),
    ).toEqual({
      seen: [
        [1, 0],
        [2, 1],
        [3, 2],
      ],
      sum: 6,
      sumFrom: 16,
      some: true,
      every: false,
      find: 2,
      log: ["closed", "closed", "closed", "closed", "closed", "closed", "closed"],
    })
  })

  test("a helper closes its source when a callback throws, on return(), and on early for...of exit", async () => {
    expect(
      await value(`
        const log = []
        function* g(name) { try { yield 1; yield 2 } finally { log.push(name) } }
        const throwing = g("throw").map((v) => { if (v === 2) throw new Error("boom"); return v })
        throwing.next()
        let message
        try { throwing.next() } catch (error) { message = error.message }
        const returned = g("return").map((v) => v)
        returned.next()
        const closed = returned.return()
        for (const v of g("loop").filter((v) => true)) break
        return { message, afterThrow: throwing.next(), closed, afterReturn: returned.next(), log }
      `),
    ).toEqual({
      message: "boom",
      afterThrow: { done: true },
      closed: { done: true },
      afterReturn: { done: true },
      log: ["throw", "return", "loop"],
    })
  })

  test("collection iterators have no return() and continue after an early exit, as in JS", async () => {
    expect(
      await value(`
        const it = [1, 2, 3].values()
        const found = it.some((v) => v === 2)
        return [typeof it.return, found, it.next().value, typeof it.map(x => x).return]
      `),
    ).toEqual(["undefined", true, 3, "function"])
  })

  test("Iterator.from and the abstract Iterator constructor", async () => {
    expect(
      await value(`
        const it = [1].values()
        let n = 0
        const errors = []
        for (const attempt of [() => Iterator(), () => new Iterator(), () => Iterator.from(5)]) {
          try { attempt() } catch (error) { errors.push(error.name) }
        }
        return [
          Iterator.from(it) === it,
          Iterator.from("ab").toArray(),
          Iterator.from([1, 2]).map((v) => v * 2).toArray(),
          Iterator.from({ next: () => ({ done: n > 1, value: n++ }) }).toArray(),
          it instanceof Iterator,
          errors,
        ]
      `),
    ).toEqual([true, ["a", "b"], [2, 4], [0, 1], true, ["TypeError", "TypeError", "TypeError"]])
  })

  test("argument validation", async () => {
    const cases: Array<[string, string]> = [
      ["[1].values().map(1)", "Iterator.prototype.map expects a function callback."],
      ["[1].values().take(-1)", "Iterator.prototype.take expects a non-negative count, received -1."],
      ["[1].values().drop()", "Iterator.prototype.drop expects a non-negative count, received NaN."],
      [
        "[1].values().flatMap((v) => 'ab').toArray()",
        "Iterator.prototype.flatMap expects an iterable or iterator, received a string.",
      ],
      ["[].values().reduce((a, b) => a)", "Iterator.prototype.reduce of an empty iterator with no initial value."],
    ]
    for (const [code, message] of cases) {
      expect((await error(`return ${code}`)).message).toContain(message)
    }
    expect(
      await error(`
        function* g() { while (true) yield 1 }
        const it = g().map(() => it.next())
        return it.next()
      `),
    ).toMatchObject({ message: expect.stringContaining("Iterator helper is already running.") })
  })
})

describe("built-in iterators", () => {
  test("keys/values/entries and [Symbol.iterator] step with next() and stay live", async () => {
    expect(
      await value(`
        const items = ["a"]
        const it = items.entries()
        items.push("b")
        const steps = [it.next(), it.next(), it.next()]
        items.push("c")
        return { steps, after: it.next(), same: items[Symbol.iterator] === items.values }
      `),
    ).toEqual({
      steps: [{ value: [0, "a"], done: false }, { value: [1, "b"], done: false }, { done: true }],
      after: { done: true },
      same: true,
    })
    expect(
      await value(`
        const s = new Set([1, 2])
        const u = new URLSearchParams("a=1&b=2")
        const h = new Headers({ b: "2", a: "1" })
        const bytes = new Uint8Array([7, 8])
        return [
          [...s.entries()], [...s[Symbol.iterator]()], s[Symbol.iterator] === s.values,
          [...u.keys()], [...u[Symbol.iterator]()], u[Symbol.iterator] === u.entries,
          [...h.values()], [...h[Symbol.iterator]()], h[Symbol.iterator] === h.entries,
          [...bytes.entries()], [...bytes[Symbol.iterator]()], bytes[Symbol.iterator] === bytes.values,
          [..."ab"[Symbol.iterator]()],
        ]
      `),
    ).toEqual([
      [
        [1, 1],
        [2, 2],
      ],
      [1, 2],
      true,
      ["a", "b"],
      [
        ["a", "1"],
        ["b", "2"],
      ],
      true,
      ["1", "2"],
      [
        ["a", "1"],
        ["b", "2"],
      ],
      true,
      [
        [0, 7],
        [1, 8],
      ],
      [7, 8],
      true,
      ["a", "b"],
    ])
  })

  test("iterators are consumed once by every iteration site", async () => {
    expect(
      await value(`
        const it = [1, 2, 3, 4].values()
        const picked = []
        for (const item of it) { picked.push(item); if (item === 2) break }
        const [third] = it
        return { picked, third, rest: [...it], spent: Array.from(it), again: it[Symbol.iterator]() === it }
      `),
    ).toEqual({ picked: [1, 2], third: 3, rest: [4], spent: [], again: true })
    expect(
      await value(`
        const m = new Map([["a", 1], ["b", 2]])
        return [
          Object.fromEntries(m.entries()), Array.from(m.keys(), (k) => k + "!"), new Set(m.values()).size,
          await Promise.all([Promise.resolve(1), 2].values()),
        ]
      `),
    ).toEqual([{ a: 1, b: 2 }, ["a!", "b!"], 2, [1, 2]])
    expect(await value(`let s = 0; for await (const v of [Promise.resolve(1), 2].values()) s += v; return s`)).toBe(3)
    expect(
      await value(`return new Set([1, 2]).union({ size: 1, has: () => false, keys: () => new Set([3]).keys() })`),
    ).toEqual([1, 2, 3])
  })

  test("iterators are opaque references", async () => {
    expect(await value(`return [1].keys()`)).toEqual({})
    expect(await value(`return JSON.stringify({ it: [1].keys() })`)).toBe('{"it":{}}')
    expect(await value(`return [typeof [1].keys(), Array.isArray([1].keys()), Object.keys([1].keys())]`)).toEqual([
      "object",
      false,
      [],
    ])
    const logged = await run(`console.log([1].keys()); return null`)
    expect(logged.logs?.[0]).toBe("[opaque reference]")
    expect((await error(`return [1].keys() + ""`)).message).toContain("Binary operators require data values")
    expect((await error(`return [1].keys().next.call({})`)).message).toContain(
      "Iterator.prototype.next called on incompatible receiver a data object",
    )
    expect((await error(`const it = [1].keys(); const next = it.next; return next()`)).message).toContain(
      "Iterator.prototype.next called on incompatible receiver undefined",
    )
  })
})

describe("Object.prototype.toString", () => {
  test("reports the built-in kind it is inherited by, as JS does through Symbol.toStringTag", async () => {
    expect(
      await value(`
      return [
        new Map().toString(), new Set().toString(), new Headers().toString(), Promise.resolve(1).toString(),
        [1].values().toString(), ({}).toString(), String(new Map()), String(Promise.resolve(1)),
        \`\${new Set([1])}\`, [new Map()] + "", new Map() == "[object Map]",
      ]
    `),
    ).toEqual([
      "[object Map]",
      "[object Set]",
      "[object Headers]",
      "[object Promise]",
      "[object Iterator]",
      "[object Object]",
      "[object Map]",
      "[object Promise]",
      "[object Set]",
      "[object Map]",
      true,
    ])
  })
})

describe("console.log of errors", () => {
  test("prints name and message, nested too", async () => {
    const result = await run(`console.log(new Error("boom"), { e: new RangeError("r") })`)
    expect(result.logs).toEqual(['Error: boom {"e":RangeError: r}'])
  })
})

describe("toLocaleString", () => {
  test("numbers and dates format as en-US in UTC; everything else falls back to toString", async () => {
    expect(
      await value(`
      return [
        (1234567.891).toLocaleString(), new Date(0).toLocaleString(), new Date(0).toLocaleDateString(),
        new Date(0).toLocaleTimeString(), "a".toLocaleString(), true.toLocaleString(), ({}).toLocaleString(),
        ({ toString: () => "custom" }).toLocaleString(), new Uint8Array([1, 2]).toLocaleString(),
      ]
    `),
    ).toEqual([
      "1,234,567.891",
      "1/1/1970, 12:00:00 AM",
      "1/1/1970",
      "12:00:00 AM",
      "a",
      "true",
      "[object Object]",
      "custom",
      "1,2",
    ])
  })

  test("arrays join each element's toLocaleString, skipping holes and nullish elements", async () => {
    expect(
      await value(`
      let calls = 0
      const item = { toLocaleString() { calls++; return "o" } }
      return [[1234.5, "x", null, undefined, item, new Date(0)].toLocaleString(), [, item, , item].toLocaleString(), calls]
    `),
    ).toEqual(["1,234.5,x,,,o,1/1/1970, 12:00:00 AM", ",o,,o", 3])
    expect((await error(`const f = ({}).toLocaleString; f()`)).message).toContain(
      "Object.prototype.toLocaleString called on null or undefined",
    )
  })

  test("toLocaleLowerCase and toLocaleUpperCase ignore the locale argument", async () => {
    expect(
      await value(`return ["ABC".toLocaleLowerCase("tr"), "abc".toLocaleUpperCase(), "İ".toLocaleLowerCase()]`),
    ).toEqual(["abc", "ABC", "i̇"])
  })
})

describe("stdlib integration", () => {
  test("constructor follows own keys, shadowing, writes, and new", async () => {
    expect(
      await value(`return [JSON.parse('{"constructor":"Foo"}').constructor, ({ constructor: 1 }).constructor]`),
    ).toEqual(["Foo", 1])
    expect(await value(`const Array = 5; return [].constructor.isArray([])`)).toBe(true)
    expect(await value(`const o = {}; o.constructor = 7; return o.constructor`)).toBe(7)
    expect(await value(`return new ([].constructor)(3).length`)).toBe(3)
    expect(await value(`return typeof ({}).constructor`)).toBe("function")
    expect(await value(`return ({}).constructor.constructor === Function`)).toBe(true)
  })

  test("new dispatches on the constructor value, not its name", async () => {
    expect(await value(`const D = Date; return new D(0) instanceof Date`)).toBe(true)
    expect(await value(`const make = (C) => new C([["a", 1]]); return make(Map).get("a")`)).toBe(1)
    expect(await value(`const t = { M: Map }; return new t.M() instanceof Map`)).toBe(true)
    const shadowed = await error(`const Date = 5; return new Date()`)
    expect(shadowed.message).toStartWith("TypeError: Date is not a constructor.")
    const fn = await error(`const f = () => 1; return new f()`)
    expect(fn.message).toStartWith("TypeError: f cannot be constructed")
  })

  test("Object.is uses SameValue semantics", async () => {
    expect(
      await value(`
        const object = {}
        return [
          Object.is(NaN, NaN),
          Object.is(0, -0),
          Object.is(object, object),
          Object.is({}, {}),
        ]
      `),
    ).toEqual([true, false, true, false])
  })

  test("Object.is compares opaque runtime references by identity", async () => {
    expect(await value(`return [Object.is(Math.max, Math.max), Object.is(Math.max, Math.min)]`)).toEqual([true, false])
  })

  test("Object values and entries accept arrays", async () => {
    expect(await value(`return [Object.values(["a", "b"]), Object.entries(["a", "b"])]`)).toEqual([
      ["a", "b"],
      [
        ["0", "a"],
        ["1", "b"],
      ],
    ])
    expect(await value(`const match = /a/.exec("ba"); return [Object.values(match), Object.entries(match)]`)).toEqual([
      ["a", 1, "ba"],
      [
        ["0", "a"],
        ["index", 1],
        ["input", "ba"],
      ],
    ])
    expect(await value(`return Object.keys(Object.values({ match: /a/.exec("ba") })[0])`)).toEqual([
      "0",
      "index",
      "input",
    ])
  })

  test("Object.fromEntries accepts every supported entry collection", async () => {
    expect(
      await value(`
        return [
          Object.fromEntries([["a", 1]]),
          Object.fromEntries(new Map([["b", 2]])),
          Object.fromEntries(new Set([["c", 3]])),
          Object.fromEntries(new URLSearchParams("d=4")),
          Object.fromEntries([{ 0: "e", 1: 5 }]),
          Object.fromEntries(new Set([[{}, 6], [new Date(0), 7], [null, 8], [undefined, 9]])),
        ]
      `),
    ).toEqual([
      { a: 1 },
      { b: 2 },
      { c: 3 },
      { d: "4" },
      { e: 5 },
      { "[object Object]": 6, "1970-01-01T00:00:00.000Z": 7, null: 8, undefined: 9 },
    ])
    expect(await value(`try { Object.fromEntries(new Set([Math.max])); return false } catch { return true }`)).toBe(
      true,
    )
    expect(
      await value(`try { Object.fromEntries(new Map([["fn", Math.max]])); return false } catch { return true }`),
    ).toBe(true)
  })

  test("deterministic Math methods match the host runtime", async () => {
    const result = await value(`
      return [
        Math.acos(0.5), Math.acosh(2), Math.asin(0.5), Math.asinh(2), Math.atan(1), Math.atan2(1, 2), Math.atanh(0.5),
        Math.cos(0.5), Math.cosh(0.5), Math.sin(0.5), Math.sinh(0.5), Math.tan(0.5), Math.tanh(0.5),
        Math.log1p(0.5), Math.expm1(0.5), Math.f16round(1.337), Math.fround(1.337), Math.clz32(1), Math.imul(2, 3),
      ]
    `)
    expect(result).toEqual([
      Math.acos(0.5),
      Math.acosh(2),
      Math.asin(0.5),
      Math.asinh(2),
      Math.atan(1),
      Math.atan2(1, 2),
      Math.atanh(0.5),
      Math.cos(0.5),
      Math.cosh(0.5),
      Math.sin(0.5),
      Math.sinh(0.5),
      Math.tan(0.5),
      Math.tanh(0.5),
      Math.log1p(0.5),
      Math.expm1(0.5),
      Math.f16round(1.337),
      Math.fround(1.337),
      Math.clz32(1),
      Math.imul(2, 3),
    ])
  })

  test("Object.assign mutates and returns its target", async () => {
    expect(
      await value(`
        const target = { a: 1 }
        const result = Object.assign(target, { b: 2 })
        return { target, result, same: target === result }
      `),
    ).toEqual({ target: { a: 1, b: 2 }, result: { a: 1, b: 2 }, same: true })
    expect(await value(`try { Object.assign(null, { a: 1 }); return false } catch { return true }`)).toBe(true)
  })

  test("Object.assign rejects direct and nested cycles", async () => {
    expect(
      await value(`
        const target = { kept: true }
        try { Object.assign(target, { self: target }) } catch { return target }
        return null
      `),
    ).toEqual({ kept: true })
    expect(
      await value(`
        const target = { kept: true }
        const nested = { target }
        try { Object.assign(target, { nested }) } catch { return target }
        return null
      `),
    ).toEqual({ kept: true })
    expect(
      await value(`
        const target = {}
        const source = {}
        source[Symbol.iterator] = target
        try { Object.assign(target, source) } catch { return Object.hasOwn(target, Symbol.iterator) }
        return true
      `),
    ).toBe(false)
    expect(
      await value(`
        const target = {}
        const nested = {}
        nested[Symbol.iterator] = target
        try { Object.assign(target, { nested }) } catch { return Object.hasOwn(target, "nested") }
        return true
      `),
    ).toBe(false)
  })

  test("Object.assign preserves mutations before a circular field", async () => {
    expect(
      await value(`
        const target = {}
        try { Object.assign(target, { before: 1, cycle: { target }, after: 2 }) } catch { return target }
        return null
      `),
    ).toEqual({ before: 1 })
    expect(
      await value(`
        const target = {}
        const marker = {}
        const source = {}
        source[Symbol.iterator] = marker
        source[Symbol.asyncIterator] = target
        try { Object.assign(target, source) } catch {
          return [target[Symbol.iterator] === marker, Object.hasOwn(target, Symbol.asyncIterator)]
        }
        return null
      `),
    ).toEqual([true, false])
  })

  test("Object.assign preserves target identity and acyclic shared aliases", async () => {
    expect(
      await value(`
        const shared = { count: 1 }
        const target = {}
        const result = Object.assign(target, { left: shared, right: shared })
        result.left.count = 2
        return [result === target, result.left === shared, result.left === result.right, shared.count]
      `),
    ).toEqual([true, true, true, 2])
  })

  test("assignment resolves and reads its left side before evaluating the right side", async () => {
    expect(await value(`let x = 1; x += (x = 5); return x`)).toBe(6)
    expect(await value(`let i = 0; const values = [9]; values[i++] = i; return [values, i]`)).toEqual([[1], 1])
    expect(await value(`let i = 0; const values = [10, 20]; values[i++] += i; return [values, i]`)).toEqual([
      [11, 20],
      1,
    ])
  })

  test("typeof reports constructors as functions and never throws", async () => {
    expect(await value(`return typeof Map`)).toBe("function")
    expect(await value(`return typeof ((x) => x)`)).toBe("function")
    expect(await value(`return typeof Math`)).toBe("object")
    expect(await value(`return typeof tools`)).toBe("object")
  })

  test("negation works on any value", async () => {
    expect(await value(`return !new Map()`)).toBe(false)
    expect(await value(`const fn = () => 1; return !fn`)).toBe(false)
  })

  test("object spread of CodeMode values is a no-op, like JS", async () => {
    expect(await value(`return { ...new Map([["a", 1]]), kept: true }`)).toEqual({ kept: true })
  })

  test("dates inside Map values survive in-CodeMode reads", async () => {
    expect(
      await value(`
      const m = new Map([["start", new Date(1000)]])
      return m.get("start").getTime()
    `),
    ).toBe(1000)
  })

  test("instanceof recognizes the stdlib value types", async () => {
    expect(
      await value(
        `return [new Date(0) instanceof Date, /a/ instanceof RegExp, new Map() instanceof Map, new Set() instanceof Set]`,
      ),
    ).toEqual([true, true, true, true])
    expect(
      await value(`return [[1] instanceof Array, [1] instanceof Object, ({}) instanceof Object, 5 instanceof Object]`),
    ).toEqual([true, true, true, false])
    expect(await value(`return [new Map() instanceof Set, "s" instanceof Date]`)).toEqual([false, false])
    expect(
      await value(`const p = Promise.resolve(1); const isPromise = p instanceof Promise; await p; return isPromise`),
    ).toBe(true)
  })

  test("realistic pipeline: parse, extract with regex, dedupe, count by day", async () => {
    expect(
      await value(`
      const raw = '[{"at":"2024-01-01T05:00:00Z","tag":"a b"},{"at":"2024-01-01T09:00:00Z","tag":"b c"},{"at":"2024-01-02T01:00:00Z","tag":"a"}]'
      const rows = JSON.parse(raw)
      const tags = new Set()
      const byDay = new Map()
      for (const row of rows) {
        for (const m of row.tag.matchAll(/[a-z]+/g)) tags.add(m[0])
        const day = new Date(row.at).toISOString().slice(0, 10)
        byDay.set(day, (byDay.get(day) ?? 0) + 1)
      }
      return { tags: [...tags].sort((a, b) => (a < b ? -1 : 1)), byDay: Object.fromEntries(byDay) }
    `),
    ).toEqual({ tags: ["a", "b", "c"], byDay: { "2024-01-01": 2, "2024-01-02": 1 } })
  })
})

describe("CodeMode values at intra-CodeMode checkpoints", () => {
  test("Object.values/entries keep Dates usable", async () => {
    expect(await value(`return Object.values({ d: new Date(0) })[0].getTime()`)).toBe(0)
    expect(await value(`const [key, d] = Object.entries({ d: new Date(0) })[0]; return key + ":" + d.getTime()`)).toBe(
      "d:0",
    )
  })

  test("Object.values/entries preserve nested object identity", async () => {
    expect(
      await value(`
      const child = { selected: false }
      const rows = { a: child }
      Object.values(rows)[0].selected = true
      return child.selected
    `),
    ).toBe(true)
    expect(
      await value(`
      const child = { selected: false }
      const rows = { a: child }
      Object.entries(rows)[0][1].selected = true
      return child.selected
    `),
    ).toBe(true)
  })

  test("Object enumeration preserves promises and callable references", async () => {
    expect(
      await value(`
      const pending = Promise.resolve(1)
      const source = { pending }
      return [Object.keys(source), Object.hasOwn(source, "pending"), await Object.values(source)[0], await Object.entries(source)[0][1]]
    `),
    ).toEqual([["pending"], true, 1, 1])
    expect(await value(`return Object.values({ max: Math.max })[0](1, 2)`)).toBe(2)
  })

  test("Object enumeration rejects invalid receivers and gives promises an await hint", async () => {
    const diagnostic = await error(`return Object.keys(Promise.resolve({ a: 1 }))`)
    expect(diagnostic.kind).toBe("InvalidDataValue")
    expect(diagnostic.message).toContain("await")
    expect(await value(`return Object.keys(Math)`)).toEqual([])
  })

  test("Object.assign keeps Maps usable", async () => {
    expect(await value(`const merged = Object.assign({}, { m: new Map([["a", 1]]) }); return merged.m.get("a")`)).toBe(
      1,
    )
  })

  test("object and array spread keep CodeMode values usable", async () => {
    expect(
      await value(`
      const src = { m: new Map([["a", 1]]) }
      const copy = { ...src }
      copy.m.set("b", 2)
      return [copy.m.get("a"), src.m.get("b")]
    `),
    ).toEqual([1, 2])
    expect(await value(`const list = [new Date(1000)]; const copy = [...list]; return copy[0].getTime()`)).toBe(1000)
  })

  test("Array.from over arrays keeps nested CodeMode values usable", async () => {
    expect(await value(`return Array.from([new Date(5)])[0].getTime()`)).toBe(5)
  })

  test("Array.from and Array.of preserve nested object identity", async () => {
    expect(
      await value(`
      const child = { selected: false }
      Array.from([child])[0].selected = true
      return child.selected
    `),
    ).toBe(true)
    expect(
      await value(`
      const child = { selected: false }
      Array.of(child)[0].selected = true
      return child.selected
    `),
    ).toBe(true)
  })

  test("Array.from and Array.of preserve promises and callable references", async () => {
    expect(
      await value(`
      const pending = Promise.resolve(1)
      return [await Array.from([pending])[0], await Array.of(pending)[0]]
    `),
    ).toEqual([1, 1])
    expect(await value(`return [Array.from([Math.max])[0](1, 2), Array.of(Math.max)[0](3, 4)]`)).toEqual([2, 4])
  })

  test("Array.from preserves identity across supported collection shapes", async () => {
    expect(
      await value(`
      const child = { selected: false }
      const fromArrayLike = Array.from({ 0: child, length: 1 })
      const fromMap = Array.from(new Map([["child", child]]))
      const fromSet = Array.from(new Set([child]))
      fromArrayLike[0].selected = true
      return [fromMap[0][1] === child, fromSet[0] === child, child.selected]
    `),
    ).toEqual([true, true, true])
  })

  test("Array.from rejects invalid receivers and gives promises an await hint", async () => {
    const diagnostic = await error(`return Array.from(Promise.resolve([1]))`)
    expect(diagnostic.kind).toBe("InvalidDataValue")
    expect(diagnostic.message).toContain("await")
    expect(await value(`return Array.from((a, b) => 1)`)).toEqual([null, null])
  })

  test("regexes stay callable through Object.values", async () => {
    expect(await value(`return Object.values({ r: /ab+/ })[0].test("abb")`)).toBe(true)
  })

  test("Object.* helpers see CodeMode values as empty objects, never internals", async () => {
    expect(await value(`return Object.keys(new Map([["a", 1]]))`)).toEqual([])
    expect(await value(`return Object.values(new Date(0))`)).toEqual([])
    expect(await value(`return Object.entries(new Set([1]))`)).toEqual([])
    expect(await value(`return Object.assign({}, new Map([["a", 1]]))`)).toEqual({})
    expect(await value(`return Object.hasOwn(new Date(0), "time")`)).toBe(false)
  })

  test("the host boundary still serializes JSON forms: results, JSON.stringify, and tool arguments", async () => {
    expect(await value(`return { d: new Date(0), m: new Map([["a", 1]]) }`)).toEqual({
      d: "1970-01-01T00:00:00.000Z",
      m: {},
    })
    expect(await value(`return JSON.stringify({ d: new Date(0) })`)).toBe('{"d":"1970-01-01T00:00:00.000Z"}')

    const observed: Array<unknown> = []
    const capture = Tool.make({
      description: "Capture the exact input the host receives",
      input: { type: "object" },
      execute: (input) =>
        Effect.sync(() => {
          observed.push(input)
          return "ok"
        }),
    })
    const result = await Effect.runPromise(
      CodeMode.execute({
        tools: { host: { capture } },
        code: `return await tools.host.capture({ when: new Date(0), tags: new Map([["a", 1]]) })`,
      }),
    )
    expect(result.ok).toBe(true)
    expect(observed).toStrictEqual([{ when: "1970-01-01T00:00:00.000Z", tags: {} }])
  })
})

describe("Uint8Array callback methods", () => {
  test.each(["'1'", "true", "false", "null", "{}", "undefined", "NaN"])(
    "typed-array searches do not coerce %s into a byte",
    async (search) => {
      expect(
        await value(`
          const bytes = new Uint8Array([0, 1, 2, 1])
          return [bytes.indexOf(${search}), bytes.lastIndexOf(${search}), bytes.includes(${search})]
        `),
      ).toEqual([-1, -1, false])
    },
  )

  test("typed-array searches keep numeric matching and start-index coercion", async () => {
    expect(
      await value(`
        const bytes = new Uint8Array([0, 1, 2, 1])
        return [
          bytes.indexOf(1, "2"), bytes.lastIndexOf(1, "2"), bytes.includes(2, "3"),
          bytes.indexOf(-0), bytes.includes(257), bytes.indexOf(1, -1)
        ]
      `),
    ).toEqual([3, 1, false, 0, false, 3])
  })

  test("map and filter return new Uint8Arrays with clamped bytes", async () => {
    expect(
      await value(`
      const b = new Uint8Array([1, 2, 3])
      const mapped = b.map((byte) => byte * 100)
      const filtered = b.filter((byte) => byte > 1)
      mapped[0] = 9
      return [
        [...mapped], mapped instanceof Uint8Array, Array.isArray(mapped), [...b], [...filtered],
        [...b.map(() => "7")], b.map((byte) => byte, {}).length, [...new Uint8Array().map((byte) => byte)],
      ]
    `),
    ).toEqual([[9, 200, 44], true, false, [1, 2, 3], [2, 3], [7, 7, 7], 3, []])
  })

  test("find, findIndex, findLast, findLastIndex, some, every, and forEach", async () => {
    expect(
      await value(`
      const b = new Uint8Array([1, 2, 3])
      const seen = []
      b.forEach((byte, index, array) => seen.push([byte, index, array === b]))
      return [
        b.find((byte) => byte > 1), b.find((byte) => byte > 5) === undefined, b.findIndex((byte) => byte > 1),
        b.findIndex((byte) => byte > 5), b.findLast((byte) => byte < 3), b.findLastIndex((byte) => byte < 3),
        b.findLastIndex((byte) => byte > 9), b.some((byte) => byte > 2), b.every((byte) => byte > 2),
        new Uint8Array().some(() => true), new Uint8Array().every(() => false),
        b.every((byte, index, array) => array === b), seen,
      ]
    `),
    ).toEqual([
      2,
      true,
      1,
      -1,
      2,
      1,
      -1,
      true,
      false,
      false,
      true,
      true,
      [
        [1, 0, true],
        [2, 1, true],
        [3, 2, true],
      ],
    ])
  })

  test("reduce and reduceRight", async () => {
    expect(
      await value(`
      const b = new Uint8Array([1, 2, 3])
      return [
        b.reduce((sum, byte) => sum + byte), b.reduce((sum, byte) => sum + byte, 10),
        b.reduceRight((text, byte) => text + byte, ""), new Uint8Array().reduce((sum, byte) => sum + byte, 5),
        b.reduce((_, byte, index, array) => array === b && index, 0),
      ]
    `),
    ).toEqual([6, 16, "321", 5, 2])
    expect((await error(`new Uint8Array().reduce((sum, byte) => sum + byte)`)).message).toContain(
      "Uint8Array.reduce of an empty array with no initial value",
    )
    expect((await error(`new Uint8Array().reduceRight((sum, byte) => sum + byte)`)).message).toContain(
      "Uint8Array.reduceRight of an empty array with no initial value",
    )
    expect((await error(`new Uint8Array([1]).map(null)`)).message).toContain("Uint8Array.map expects a function")
  })

  test("sort is numeric by default and in place, with an optional comparator", async () => {
    expect(
      await value(`
      const b = new Uint8Array([10, 9, 1])
      const same = b.sort() === b
      const desc = new Uint8Array([3, 1, 2]).sort((x, y) => y - x)
      return [same, [...b], [...desc], desc instanceof Uint8Array, [...new Uint8Array([2, 1]).sort(() => NaN)]]
    `),
    ).toEqual([true, [1, 9, 10], [3, 2, 1], true, [2, 1]])
    expect((await error(`new Uint8Array([2, 1]).sort(null)`)).message).toContain("Uint8Array.sort expects a function")
  })

  test("lastIndexOf treats an explicit undefined fromIndex as 0", async () => {
    expect(
      await value(`
      const a = [1, 2, 1]
      const b = new Uint8Array([1, 2, 1])
      return [a.lastIndexOf(1, undefined), a.lastIndexOf(1), a.lastIndexOf(2, undefined), b.lastIndexOf(1, undefined), b.lastIndexOf(1)]
    `),
    ).toEqual([0, 2, -1, 0, 2])
  })
})