mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
af0f2af93f
follow on from https://github.com/oxc-project/oxc/pull/16796
755 lines
29 KiB
TypeScript
755 lines
29 KiB
TypeScript
// Tests for lazy deserialization.
|
|
|
|
// oxlint-disable-next-line typescript-eslint/ban-ts-comment
|
|
// @ts-nocheck
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { parseSync } from "../src-js/index.js";
|
|
|
|
function parseSyncLazy(filename, code, options = null) {
|
|
return parseSync(filename, code, { ...options, experimentalLazy: true });
|
|
}
|
|
|
|
// Get `NodeArray` constructor
|
|
const NodeArray = Object.getPrototypeOf(parseSyncLazy("test.js", "").program.body).constructor;
|
|
// oxlint-disable eslint-plugin-jest/no-standalone-expect
|
|
expect(NodeArray).not.toBe(Array);
|
|
expect(NodeArray.toString().startsWith("class NodeArray extends Array {")).toBe(true);
|
|
// oxlint-enable eslint-plugin-jest/no-standalone-expect
|
|
|
|
it("parses", () => {
|
|
const { program } = parseSyncLazy("test.js", "let x = y + z;");
|
|
expect(program.type).toBe("Program");
|
|
expect(Array.isArray(program.body)).toBe(true);
|
|
expect(program.body.length).toBe(1);
|
|
|
|
const declaration = program.body[0];
|
|
expect(declaration.type).toBe("VariableDeclaration");
|
|
expect(declaration.kind).toBe("let");
|
|
expect(Array.isArray(declaration.declarations)).toBe(true);
|
|
expect(declaration.declarations.length).toBe(1);
|
|
|
|
const declarator = declaration.declarations[0];
|
|
expect(declarator.type).toBe("VariableDeclarator");
|
|
});
|
|
|
|
it("returns same node objects and node arrays on each access", () => {
|
|
const data = parseSyncLazy("test.js", "let x = y + z;");
|
|
const { program } = data;
|
|
expect(data.program).toBe(program);
|
|
const { body } = program;
|
|
expect(program.body).toBe(body);
|
|
const stmt = body[0];
|
|
expect(body[0]).toBe(stmt);
|
|
const { declarations } = stmt;
|
|
expect(stmt.declarations).toBe(declarations);
|
|
const declaration = declarations[0];
|
|
expect(declarations[0]).toBe(declaration);
|
|
const { id } = declaration;
|
|
expect(declaration.id).toBe(id);
|
|
|
|
expect(program.body[0].declarations[0].id).toBe(id);
|
|
});
|
|
|
|
describe("NodeArray", () => {
|
|
describe("methods", () => {
|
|
it("at", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.at(0)).toBe(body[0]);
|
|
expect(body.at(1)).toBe(body[1]);
|
|
expect(body.at(2)).toBeUndefined();
|
|
});
|
|
|
|
it("concat", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const concat = body.concat(body);
|
|
expect(Array.isArray(concat)).toBe(true);
|
|
expect(Object.getPrototypeOf(concat)).toBe(Array.prototype);
|
|
expect(concat).toHaveLength(4);
|
|
expect(concat[0]).toBe(body[0]);
|
|
expect(concat[1]).toBe(body[1]);
|
|
expect(concat[2]).toBe(body[0]);
|
|
expect(concat[3]).toBe(body[1]);
|
|
});
|
|
|
|
it("copyWithin (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.copyWithin(0, 1, 2)).toThrow(new TypeError("Cannot redefine property: 0"));
|
|
});
|
|
|
|
it("entries", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const entries = [...body.entries()];
|
|
expect(entries).toStrictEqual([
|
|
[0, body[0]],
|
|
[1, body[1]],
|
|
]);
|
|
expect(entries[0][1]).toBe(body[0]);
|
|
expect(entries[1][1]).toBe(body[1]);
|
|
});
|
|
|
|
it("every", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.every((stmt) => typeof stmt.type === "string")).toBe(true);
|
|
expect(body.every((stmt) => stmt.type === "VariableDeclaration")).toBe(false);
|
|
});
|
|
|
|
it("fill (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.fill(0)).toThrow(new TypeError("Cannot redefine property: 0"));
|
|
});
|
|
|
|
it("filter", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const filter = body.filter((stmt) => stmt.type === "VariableDeclaration");
|
|
expect(Array.isArray(filter)).toBe(true);
|
|
expect(Object.getPrototypeOf(filter)).toBe(Array.prototype);
|
|
expect(filter).toHaveLength(1);
|
|
expect(filter[0]).toBe(body[0]);
|
|
});
|
|
|
|
it("find", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.find((stmt) => stmt.type === "VariableDeclaration")).toBe(body[0]);
|
|
expect(body.find((stmt) => stmt.type === "ExpressionStatement")).toBe(body[1]);
|
|
});
|
|
|
|
it("findIndex", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.findIndex((stmt) => stmt.type === "VariableDeclaration")).toBe(0);
|
|
expect(body.findIndex((stmt) => stmt.type === "ExpressionStatement")).toBe(1);
|
|
});
|
|
|
|
it("findLast", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.findLast(() => true)).toBe(body[1]);
|
|
expect(body.findLast((stmt) => stmt.type === "VariableDeclaration")).toBe(body[0]);
|
|
});
|
|
|
|
it("findLastIndex", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.findLastIndex(() => true)).toBe(1);
|
|
expect(body.findLastIndex((stmt) => stmt.type === "VariableDeclaration")).toBe(0);
|
|
});
|
|
|
|
it("flat", () => {
|
|
// Can't test flattening of nested arrays, as we don't have `Vec<Vec>` in AST
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const flat = body.flat();
|
|
expect(Array.isArray(flat)).toBe(true);
|
|
expect(Object.getPrototypeOf(flat)).toBe(Array.prototype);
|
|
expect(flat).toHaveLength(2);
|
|
expect(flat[0]).toBe(body[0]);
|
|
expect(flat[1]).toBe(body[1]);
|
|
});
|
|
|
|
it("flatMap", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const flat = body.flatMap((stmt) => [stmt, stmt]);
|
|
expect(Array.isArray(flat)).toBe(true);
|
|
expect(Object.getPrototypeOf(flat)).toBe(Array.prototype);
|
|
expect(flat).toHaveLength(4);
|
|
expect(flat[0]).toBe(body[0]);
|
|
expect(flat[1]).toBe(body[0]);
|
|
expect(flat[2]).toBe(body[1]);
|
|
expect(flat[3]).toBe(body[1]);
|
|
});
|
|
|
|
it("forEach", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const stmts = [];
|
|
body.forEach((stmt) => stmts.push(stmt));
|
|
expect(stmts).toHaveLength(2);
|
|
expect(stmts[0]).toBe(body[0]);
|
|
expect(stmts[1]).toBe(body[1]);
|
|
});
|
|
|
|
it("includes", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.includes(body[0])).toBe(true);
|
|
expect(body.includes(body[1])).toBe(true);
|
|
expect(body.includes(undefined)).toBe(false);
|
|
expect(body.includes({ ...body[0] })).toBe(false);
|
|
});
|
|
|
|
it("indexOf", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.indexOf(body[0])).toBe(0);
|
|
expect(body.indexOf(body[1])).toBe(1);
|
|
expect(body.indexOf(undefined)).toBe(-1);
|
|
expect(body.indexOf({ ...body[0] })).toBe(-1);
|
|
});
|
|
|
|
it("join", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
// oxlint-disable-next-line typescript-eslint/no-base-to-string
|
|
expect(body.join()).toBe("[object Object],[object Object]");
|
|
// oxlint-disable-next-line typescript-eslint/no-base-to-string
|
|
expect(body.join(" x ")).toBe("[object Object] x [object Object]");
|
|
});
|
|
|
|
it("keys", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const keys = [...body.keys()];
|
|
expect(keys).toStrictEqual([0, 1]);
|
|
});
|
|
|
|
it("lastIndexOf", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.lastIndexOf(body[0])).toBe(0);
|
|
expect(body.lastIndexOf(body[1])).toBe(1);
|
|
expect(body.lastIndexOf(undefined)).toBe(-1);
|
|
expect(body.lastIndexOf({ ...body[0] })).toBe(-1);
|
|
});
|
|
|
|
it("map", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const map = body.map((stmt) => stmt.type === "VariableDeclaration");
|
|
expect(Array.isArray(map)).toBe(true);
|
|
expect(Object.getPrototypeOf(map)).toBe(Array.prototype);
|
|
expect(map).toStrictEqual([true, false]);
|
|
});
|
|
|
|
it("pop (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.pop()).toThrow(
|
|
new TypeError("'deleteProperty' on proxy: trap returned falsish for property '1'"),
|
|
);
|
|
});
|
|
|
|
it("push (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.push()).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
expect(() => body.push({})).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '2'"),
|
|
);
|
|
expect(() => body.push({}, {})).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '2'"),
|
|
);
|
|
});
|
|
|
|
it("reduce", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const stmts = body.reduce((stmts, stmt) => {
|
|
stmts.push(stmt);
|
|
return stmts;
|
|
}, []);
|
|
expect(stmts).toHaveLength(2);
|
|
expect(stmts[0]).toBe(body[0]);
|
|
expect(stmts[1]).toBe(body[1]);
|
|
});
|
|
|
|
it("reduceRight", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const stmts = body.reduceRight((stmts, stmt) => {
|
|
stmts.push(stmt);
|
|
return stmts;
|
|
}, []);
|
|
expect(stmts).toHaveLength(2);
|
|
expect(stmts[0]).toBe(body[1]);
|
|
expect(stmts[1]).toBe(body[0]);
|
|
});
|
|
|
|
it("reverse (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.reverse()).toThrow(new TypeError("Cannot redefine property: 0"));
|
|
});
|
|
|
|
it("shift (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.shift()).toThrow(new TypeError("Cannot redefine property: 0"));
|
|
});
|
|
|
|
describe("slice", () => {
|
|
class Case {
|
|
constructor(args, expected) {
|
|
this.args = args;
|
|
this.expected = expected;
|
|
}
|
|
|
|
toString() {
|
|
return `(${this.args.map((arg) => JSON.stringify(arg) || "undefined").join(", ")})`;
|
|
}
|
|
}
|
|
|
|
it.each([
|
|
// No args
|
|
new Case([], { start: 0, length: 3 }),
|
|
// 1 arg integer
|
|
new Case([1], { start: 1, length: 2 }),
|
|
new Case([2], { start: 2, length: 1 }),
|
|
new Case([3], { start: 0, length: 0 }),
|
|
new Case([4], { start: 0, length: 0 }),
|
|
// 1 arg negative integer
|
|
new Case([-0], { start: 0, length: 3 }),
|
|
new Case([-1], { start: 2, length: 1 }),
|
|
new Case([-2], { start: 1, length: 2 }),
|
|
new Case([-3], { start: 0, length: 3 }),
|
|
new Case([-4], { start: 0, length: 3 }),
|
|
// 1 arg undefined/null
|
|
new Case([undefined], { start: 0, length: 3 }),
|
|
new Case([null], { start: 0, length: 3 }),
|
|
// 1 arg non-integer
|
|
new Case(["0"], { start: 0, length: 3 }),
|
|
new Case(["2"], { start: 2, length: 1 }),
|
|
new Case(["-2"], { start: 1, length: 2 }),
|
|
new Case(["0x2"], { start: 2, length: 1 }),
|
|
new Case(["oops"], { start: 0, length: 3 }),
|
|
new Case([false], { start: 0, length: 3 }),
|
|
new Case([true], { start: 1, length: 2 }),
|
|
new Case([{ valueOf: () => 1 }], { start: 1, length: 2 }),
|
|
// 2 args integers
|
|
new Case([0, 0], { start: 0, length: 0 }),
|
|
new Case([0, 1], { start: 0, length: 1 }),
|
|
new Case([0, 2], { start: 0, length: 2 }),
|
|
new Case([0, 3], { start: 0, length: 3 }),
|
|
new Case([0, 4], { start: 0, length: 3 }),
|
|
new Case([1, 2], { start: 1, length: 1 }),
|
|
new Case([1, 3], { start: 1, length: 2 }),
|
|
new Case([1, 4], { start: 1, length: 2 }),
|
|
new Case([3, 3], { start: 0, length: 0 }),
|
|
new Case([3, 5], { start: 0, length: 0 }),
|
|
new Case([3, 0], { start: 0, length: 0 }),
|
|
// 2 args negative integers
|
|
new Case([-1, 3], { start: 2, length: 1 }),
|
|
new Case([-2, 3], { start: 1, length: 2 }),
|
|
new Case([-3, 3], { start: 0, length: 3 }),
|
|
new Case([-4, 3], { start: 0, length: 3 }),
|
|
new Case([-2, 5], { start: 1, length: 2 }),
|
|
new Case([0, -1], { start: 0, length: 2 }),
|
|
new Case([1, -1], { start: 1, length: 1 }),
|
|
new Case([2, -1], { start: 0, length: 0 }),
|
|
new Case([3, -1], { start: 0, length: 0 }),
|
|
new Case([0, -0], { start: 0, length: 0 }),
|
|
new Case([-2, -1], { start: 1, length: 1 }),
|
|
new Case([-3, -1], { start: 0, length: 2 }),
|
|
new Case([-3, -4], { start: 0, length: 0 }),
|
|
// 2 args undefined/null
|
|
new Case([undefined, undefined], { start: 0, length: 3 }),
|
|
new Case([null, null], { start: 0, length: 0 }),
|
|
new Case([null, undefined], { start: 0, length: 3 }),
|
|
new Case([undefined, null], { start: 0, length: 0 }),
|
|
new Case([undefined, 1], { start: 0, length: 1 }),
|
|
new Case([undefined, 3], { start: 0, length: 3 }),
|
|
new Case([undefined, 4], { start: 0, length: 3 }),
|
|
new Case([undefined, -1], { start: 0, length: 2 }),
|
|
new Case([undefined, 0], { start: 0, length: 0 }),
|
|
new Case([null, 1], { start: 0, length: 1 }),
|
|
new Case([null, 3], { start: 0, length: 3 }),
|
|
new Case([null, 4], { start: 0, length: 3 }),
|
|
new Case([null, -1], { start: 0, length: 2 }),
|
|
new Case([null, 0], { start: 0, length: 0 }),
|
|
new Case([0, undefined], { start: 0, length: 3 }),
|
|
new Case([1, undefined], { start: 1, length: 2 }),
|
|
new Case([2, undefined], { start: 2, length: 1 }),
|
|
new Case([3, undefined], { start: 0, length: 0 }),
|
|
new Case([4, undefined], { start: 0, length: 0 }),
|
|
new Case([-2, undefined], { start: 1, length: 2 }),
|
|
new Case([-3, undefined], { start: 0, length: 3 }),
|
|
new Case([-5, undefined], { start: 0, length: 3 }),
|
|
new Case([0, null], { start: 0, length: 0 }),
|
|
new Case([1, null], { start: 0, length: 0 }),
|
|
new Case([3, null], { start: 0, length: 0 }),
|
|
new Case([-2, null], { start: 0, length: 0 }),
|
|
new Case([-3, null], { start: 0, length: 0 }),
|
|
new Case([-5, null], { start: 0, length: 0 }),
|
|
// 2 args non-integers
|
|
new Case(["0", "2"], { start: 0, length: 2 }),
|
|
new Case(["0", "-2"], { start: 0, length: 1 }),
|
|
new Case(["1", "-1"], { start: 1, length: 1 }),
|
|
new Case(["0x1", "0x2"], { start: 1, length: 1 }),
|
|
new Case([0, "oops"], { start: 0, length: 0 }),
|
|
new Case([false, true], { start: 0, length: 1 }),
|
|
new Case([true, true], { start: 0, length: 0 }),
|
|
new Case([1, { valueOf: () => 2 }], { start: 1, length: 1 }),
|
|
])("%s", ({ args, expected }) => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2; x = 3;").program;
|
|
const slice = body.slice(...args);
|
|
expect(Array.isArray(slice)).toBe(true);
|
|
expect(Object.getPrototypeOf(slice)).toBe(NodeArray.prototype);
|
|
expect(slice.length).toBe(expected.length);
|
|
|
|
for (let i = 0; i < expected.length; i++) {
|
|
expect(slice[i]).toBe(body[i + expected.start]);
|
|
}
|
|
|
|
// Check `Array.prototype.slice` behaves the same
|
|
const arr = [11, 22, 33];
|
|
const arrSlice = arr.slice(...args);
|
|
expect(arrSlice.length).toBe(expected.length);
|
|
|
|
for (let i = 0; i < expected.length; i++) {
|
|
expect(arrSlice[i]).toBe(arr[i + expected.start]);
|
|
}
|
|
});
|
|
});
|
|
|
|
it("some", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(body.some((stmt) => stmt.type === "VariableDeclaration")).toBe(true);
|
|
expect(body.some((stmt) => stmt.type === "ExpressionStatement")).toBe(true);
|
|
expect(body.some((stmt) => stmt.type === "Donkey")).toBe(false);
|
|
});
|
|
|
|
it("sort (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
// oxlint-disable-next-line typescript-eslint/require-array-sort-compare
|
|
expect(() => body.sort()).toThrow(new TypeError("Cannot redefine property: 0"));
|
|
});
|
|
|
|
it("splice (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.splice(0, 0)).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
expect(() => body.splice(0, 1)).toThrow(new TypeError("Cannot redefine property: 0"));
|
|
expect(() => body.splice(0, 0, {})).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '2'"),
|
|
);
|
|
});
|
|
|
|
it("toLocaleString", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
// oxlint-disable-next-line typescript-eslint/no-base-to-string
|
|
expect(body.toLocaleString()).toBe("[object Object],[object Object]");
|
|
});
|
|
|
|
it("toReversed", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const reversed = body.toReversed();
|
|
expect(Array.isArray(reversed)).toBe(true);
|
|
expect(Object.getPrototypeOf(reversed)).toBe(Array.prototype);
|
|
expect(reversed).toHaveLength(2);
|
|
expect(reversed[0]).toBe(body[1]);
|
|
expect(reversed[1]).toBe(body[0]);
|
|
});
|
|
|
|
it("toSorted", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const sorted = body.toSorted((a, b) => {
|
|
if (a.type === b.type) return 0;
|
|
return a.type > b.type ? 1 : -1;
|
|
});
|
|
expect(Array.isArray(sorted)).toBe(true);
|
|
expect(Object.getPrototypeOf(sorted)).toBe(Array.prototype);
|
|
expect(sorted).toHaveLength(2);
|
|
expect(sorted[0]).toBe(body[1]);
|
|
expect(sorted[1]).toBe(body[0]);
|
|
});
|
|
|
|
it("toSpliced", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const spliced = body.toSpliced(1, 0, { x: 1 }, { y: 2 });
|
|
expect(Array.isArray(spliced)).toBe(true);
|
|
expect(Object.getPrototypeOf(spliced)).toBe(Array.prototype);
|
|
expect(spliced).toStrictEqual([body[0], { x: 1 }, { y: 2 }, body[1]]);
|
|
expect(spliced[0]).toBe(body[0]);
|
|
expect(spliced[3]).toBe(body[1]);
|
|
});
|
|
|
|
it("toString", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
// oxlint-disable-next-line typescript-eslint/no-base-to-string
|
|
expect(body.toString()).toBe("[object Object],[object Object]");
|
|
});
|
|
|
|
it("unshift (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => body.unshift({})).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '2'"),
|
|
);
|
|
});
|
|
|
|
it("values", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const values = [...body.values()];
|
|
expect(values).toHaveLength(2);
|
|
expect(values[0]).toBe(body[0]);
|
|
expect(values[1]).toBe(body[1]);
|
|
});
|
|
|
|
it("with", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const withed = body.with(0, { x: 1 });
|
|
expect(Array.isArray(withed)).toBe(true);
|
|
expect(Object.getPrototypeOf(withed)).toBe(Array.prototype);
|
|
expect(withed).toStrictEqual([{ x: 1 }, body[1]]);
|
|
expect(withed[1]).toBe(body[1]);
|
|
});
|
|
});
|
|
|
|
it("iteration", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const stmts = [];
|
|
for (const stmt of body) {
|
|
stmts.push(stmt);
|
|
}
|
|
expect(stmts).toHaveLength(2);
|
|
expect(stmts[0]).toBe(body[0]);
|
|
expect(stmts[1]).toBe(body[1]);
|
|
});
|
|
|
|
it("spread", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const stmts = [...body];
|
|
expect(stmts).toHaveLength(2);
|
|
expect(stmts[0]).toBe(body[0]);
|
|
expect(stmts[1]).toBe(body[1]);
|
|
|
|
const stmtsTwice = [...body, ...body];
|
|
expect(stmtsTwice).toHaveLength(4);
|
|
expect(stmtsTwice[0]).toBe(body[0]);
|
|
expect(stmtsTwice[1]).toBe(body[1]);
|
|
expect(stmtsTwice[2]).toBe(body[0]);
|
|
expect(stmtsTwice[3]).toBe(body[1]);
|
|
});
|
|
|
|
it("get length", () => {
|
|
const body0 = parseSyncLazy("test.js", "").program.body;
|
|
expect(body0.length).toBe(0);
|
|
const body2 = parseSyncLazy("test.js", "let x = 1; x = 2;").program.body;
|
|
expect(body2.length).toBe(2);
|
|
const body4 = parseSyncLazy("test.js", "x; y; z; 123;").program.body;
|
|
expect(body4.length).toBe(4);
|
|
});
|
|
|
|
it("set length (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => (body.length = 0)).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
expect(() => (body.length = 2)).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
expect(() => (body.length = 3)).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
});
|
|
|
|
it("set length via `defineProperty` (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => Object.defineProperty(body, "length", { value: 0 })).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
expect(() => Object.defineProperty(body, "length", { value: 2 })).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
expect(() => Object.defineProperty(body, "length", { value: 3 })).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property 'length'"),
|
|
);
|
|
});
|
|
|
|
it("set element (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => (body[0] = {})).toThrow(new TypeError("Cannot redefine property: 0"));
|
|
expect(() => (body[1] = {})).toThrow(new TypeError("Cannot redefine property: 1"));
|
|
expect(() => (body[2] = {})).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '2'"),
|
|
);
|
|
expect(() => (body[4294967294] = {})).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '4294967294'"),
|
|
);
|
|
});
|
|
|
|
it("set element via `defineProperty` (throws)", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(() => Object.defineProperty(body, 0, { value: {} })).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '0'"),
|
|
);
|
|
expect(() => Object.defineProperty(body, 1, { value: {} })).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '1'"),
|
|
);
|
|
expect(() => Object.defineProperty(body, 2, { value: {} })).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '2'"),
|
|
);
|
|
expect(() => Object.defineProperty(body, 4294967294, { value: {} })).toThrow(
|
|
new TypeError("'defineProperty' on proxy: trap returned falsish for property '4294967294'"),
|
|
);
|
|
});
|
|
|
|
const propertyKeys = [
|
|
"foo",
|
|
"bar",
|
|
Symbol("yeah"),
|
|
-1,
|
|
"01",
|
|
"0x1",
|
|
"1 ",
|
|
" 1",
|
|
"1e1",
|
|
"4294967295",
|
|
"4294967296",
|
|
"10000000000000",
|
|
];
|
|
|
|
it("set properties", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
|
|
for (const [i, key] of propertyKeys.entries()) {
|
|
body[key] = i + 100;
|
|
}
|
|
|
|
for (const [i, key] of propertyKeys.entries()) {
|
|
expect(body[key]).toBe(i + 100);
|
|
}
|
|
});
|
|
|
|
it("set properties via `defineProperty`", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
|
|
for (const [i, key] of propertyKeys.entries()) {
|
|
Object.defineProperty(body, key, { value: i + 100 });
|
|
}
|
|
|
|
for (const [i, key] of propertyKeys.entries()) {
|
|
expect(body[key]).toBe(i + 100);
|
|
}
|
|
});
|
|
|
|
describe("reflection", () => {
|
|
it("Object.keys", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const keys = Object.keys(body);
|
|
expect(keys).toStrictEqual(["0", "1"]);
|
|
// Check same as array
|
|
expect(Object.keys([...body])).toStrictEqual(keys);
|
|
});
|
|
|
|
it("Object.values", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const values = Object.values(body);
|
|
expect(values).toStrictEqual([body[0], body[1]]);
|
|
expect(values[0]).toBe(body[0]);
|
|
expect(values[1]).toBe(body[1]);
|
|
// Check same as array
|
|
expect(Object.values([...body])).toStrictEqual(values);
|
|
});
|
|
|
|
it("Object.entries", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const entries = Object.entries(body);
|
|
expect(entries).toStrictEqual([
|
|
["0", body[0]],
|
|
["1", body[1]],
|
|
]);
|
|
expect(entries[0][1]).toBe(body[0]);
|
|
expect(entries[1][1]).toBe(body[1]);
|
|
// Check same as array
|
|
expect(Object.entries([...body])).toStrictEqual(entries);
|
|
});
|
|
|
|
it("Object.getOwnPropertyNames", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const propNames = Object.getOwnPropertyNames(body);
|
|
expect(propNames).toStrictEqual(["0", "1", "length"]);
|
|
// Check same as array
|
|
expect(Object.getOwnPropertyNames([...body])).toStrictEqual(propNames);
|
|
});
|
|
|
|
it("Object.getOwnPropertySymbols", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const symbols = Object.getOwnPropertySymbols(body);
|
|
expect(symbols).toStrictEqual([]);
|
|
// Check same as array
|
|
expect(Object.getOwnPropertySymbols([...body])).toStrictEqual(symbols);
|
|
});
|
|
|
|
it("Object.getOwnPropertyDescriptor", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
|
|
const descriptor0 = Object.getOwnPropertyDescriptor(body, 0);
|
|
expect(descriptor0).toStrictEqual({
|
|
value: body[0],
|
|
writable: false,
|
|
enumerable: true,
|
|
configurable: true,
|
|
});
|
|
expect(descriptor0.value).toBe(body[0]);
|
|
// Check same as array, except for `writable`
|
|
expect(Object.getOwnPropertyDescriptor([...body], 0)).toStrictEqual({
|
|
...descriptor0,
|
|
writable: true,
|
|
});
|
|
|
|
const descriptor1 = Object.getOwnPropertyDescriptor(body, 1);
|
|
expect(descriptor1).toStrictEqual({
|
|
value: body[1],
|
|
writable: false,
|
|
enumerable: true,
|
|
configurable: true,
|
|
});
|
|
expect(descriptor1.value).toBe(body[1]);
|
|
// Check same as array, except for `writable`
|
|
expect(Object.getOwnPropertyDescriptor([...body], 1)).toStrictEqual({
|
|
...descriptor1,
|
|
writable: true,
|
|
});
|
|
|
|
const descriptorLength = Object.getOwnPropertyDescriptor(body, "length");
|
|
expect(descriptorLength).toStrictEqual({
|
|
value: 2,
|
|
writable: true,
|
|
enumerable: false,
|
|
configurable: false,
|
|
});
|
|
// Check same as array
|
|
expect(Object.getOwnPropertyDescriptor([...body], "length")).toStrictEqual(descriptorLength);
|
|
});
|
|
|
|
it("Object.getOwnPropertyDescriptors", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
const descriptors = Object.getOwnPropertyDescriptors(body);
|
|
expect(descriptors).toStrictEqual({
|
|
0: {
|
|
value: body[0],
|
|
writable: false,
|
|
enumerable: true,
|
|
configurable: true,
|
|
},
|
|
1: {
|
|
value: body[1],
|
|
writable: false,
|
|
enumerable: true,
|
|
configurable: true,
|
|
},
|
|
length: {
|
|
value: 2,
|
|
writable: true,
|
|
enumerable: false,
|
|
configurable: false,
|
|
},
|
|
});
|
|
expect(descriptors[0].value).toBe(body[0]);
|
|
expect(descriptors[1].value).toBe(body[1]);
|
|
// Check same as array, except for `writable` on elements
|
|
descriptors[0].writable = true;
|
|
descriptors[1].writable = true;
|
|
expect(Object.getOwnPropertyDescriptors([...body])).toStrictEqual(descriptors);
|
|
});
|
|
|
|
it("Object.isExtensible", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(Object.isExtensible(body)).toBe(true);
|
|
// Check same as array
|
|
expect(Object.isExtensible([...body])).toBe(true);
|
|
});
|
|
|
|
it("Object.isFrozen", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(Object.isFrozen(body)).toBe(false);
|
|
// Check same as array
|
|
expect(Object.isFrozen([...body])).toBe(false);
|
|
});
|
|
|
|
it("Object.isSealed", () => {
|
|
const { body } = parseSyncLazy("test.js", "let x = 1; x = 2;").program;
|
|
expect(Object.isSealed(body)).toBe(false);
|
|
// Check same as array
|
|
expect(Object.isSealed([...body])).toBe(false);
|
|
});
|
|
});
|
|
});
|