import { join } from "path";
import { openSync } from "fs";
describe("structured clone", () => {
let primitives_tests = [
{ description: "primitive undefined", value: undefined },
{ description: "primitive null", value: null },
{ description: "primitive true", value: true },
{ description: "primitive false", value: false },
{ description: "primitive string, empty string", value: "" },
{ description: "primitive string, lone high surrogate", value: "\uD800" },
{ description: "primitive string, lone low surrogate", value: "\uDC00" },
{ description: "primitive string, NUL", value: "\u0000" },
{ description: "primitive string, astral character", value: "\uDBFF\uDFFD" },
{ description: "primitive number, 0.2", value: 0.2 },
{ description: "primitive number, 0", value: 0 },
{ description: "primitive number, -0", value: -0 },
{ description: "primitive number, NaN", value: NaN },
{ description: "primitive number, Infinity", value: Infinity },
{ description: "primitive number, -Infinity", value: -Infinity },
{ description: "primitive number, 9007199254740992", value: 9007199254740992 },
{ description: "primitive number, -9007199254740992", value: -9007199254740992 },
{ description: "primitive number, 9007199254740994", value: 9007199254740994 },
{ description: "primitive number, -9007199254740994", value: -9007199254740994 },
{ description: "primitive BigInt, 0n", value: 0n },
{ description: "primitive BigInt, -0n", value: -0n },
{ description: "primitive BigInt, -9007199254740994000n", value: -9007199254740994000n },
{
description: "primitive BigInt, -9007199254740994000900719925474099400090071992547409940009007199254740994000n",
value: -9007199254740994000900719925474099400090071992547409940009007199254740994000n,
},
];
for (let { description, value } of primitives_tests) {
test(description, () => {
var cloned = structuredClone(value);
expect(cloned).toBe(value);
});
}
test("Array with primitives", () => {
var input = [
undefined,
null,
true,
false,
"",
"\uD800",
"\uDC00",
"\u0000",
"\uDBFF\uDFFD",
0.2,
0,
-0,
NaN,
Infinity,
-Infinity,
9007199254740992,
-9007199254740992,
9007199254740994,
-9007199254740994,
-12n,
-0n,
0n,
];
var cloned = structuredClone(input);
expect(cloned).toBeInstanceOf(Array);
expect(cloned).not.toBe(input);
expect(cloned.length).toEqual(input.length);
for (const x in input) {
expect(cloned[x]).toBe(input[x]);
}
});
test("Object with primitives", () => {
var input: any = {
undefined: undefined,
null: null,
true: true,
false: false,
empty: "",
"high surrogate": "\uD800",
"low surrogate": "\uDC00",
nul: "\u0000",
astral: "\uDBFF\uDFFD",
"0.2": 0.2,
"0": 0,
"-0": -0,
NaN: NaN,
Infinity: Infinity,
"-Infinity": -Infinity,
"9007199254740992": 9007199254740992,
"-9007199254740992": -9007199254740992,
"9007199254740994": 9007199254740994,
"-9007199254740994": -9007199254740994,
"-12n": -12n,
"-0n": -0n,
"0n": 0n,
};
var cloned = structuredClone(input);
expect(cloned).toBeInstanceOf(Object);
expect(cloned).not.toBeInstanceOf(Array);
expect(cloned).not.toBe(input);
for (const x in input) {
expect(cloned[x]).toBe(input[x]);
}
});
test("map", () => {
var input = new Map();
input.set("a", 1);
input.set("b", 2);
input.set("c", 3);
var cloned = structuredClone(input);
expect(cloned).toBeInstanceOf(Map);
expect(cloned).not.toBe(input);
expect(cloned.size).toEqual(input.size);
for (const [key, value] of input) {
expect(cloned.get(key)).toBe(value);
}
});
test("set", () => {
var input = new Set();
input.add("a");
input.add("b");
input.add("c");
var cloned = structuredClone(input);
expect(cloned).toBeInstanceOf(Set);
expect(cloned).not.toBe(input);
expect(cloned.size).toEqual(input.size);
for (const value of input) {
expect(cloned.has(value)).toBe(true);
}
});
describe("bun blobs work", () => {
test("simple", async () => {
const blob = new Blob(["hello"], { type: "application/octet-stream" });
const cloned = structuredClone(blob);
await compareBlobs(blob, cloned);
});
test("empty", async () => {
const emptyBlob = new Blob([], { type: "" });
const clonedEmpty = structuredClone(emptyBlob);
await compareBlobs(emptyBlob, clonedEmpty);
});
test("empty with type", async () => {
const emptyBlob = new Blob([], { type: "application/octet-stream" });
const clonedEmpty = structuredClone(emptyBlob);
await compareBlobs(emptyBlob, clonedEmpty);
});
test("unknown type", async () => {
const blob = new Blob(["hello type"], { type: "this is type" });
const cloned = structuredClone(blob);
await compareBlobs(blob, cloned);
});
test("file from path", async () => {
const blob = Bun.file(join(import.meta.dir, "example.txt"));
const cloned = structuredClone(blob);
expect(cloned.lastModified).toBe(blob.lastModified);
expect(cloned.name).toBe(blob.name);
});
test("file from fd", async () => {
const fd = openSync(join(import.meta.dir, "example.txt"), "r");
const blob = Bun.file(fd);
const cloned = structuredClone(blob);
expect(cloned.lastModified).toBe(blob.lastModified);
expect(cloned.name).toBe(blob.name);
});
test("unpaired high surrogate (invalid utf-8)", async () => {
const blob = createBlob(encode_cesu8([0xd800]));
const cloned = structuredClone(blob);
await compareBlobs(blob, cloned);
});
test("unpaired low surrogate (invalid utf-8)", async () => {
const blob = createBlob(encode_cesu8([0xdc00]));
const cloned = structuredClone(blob);
await compareBlobs(blob, cloned);
});
test("paired surrogates (invalid utf-8)", async () => {
const blob = createBlob(encode_cesu8([0xd800, 0xdc00]));
const cloned = structuredClone(blob);
await compareBlobs(blob, cloned);
});
});
describe("transferrables", () => {
test("ArrayBuffer", () => {
const buffer = Uint8Array.from([1]).buffer;
const cloned = structuredClone(buffer, { transfer: [buffer] });
expect(buffer.byteLength).toBe(0);
expect(cloned.byteLength).toBe(1);
});
test("A detached ArrayBuffer cannot be transferred", () => {
const buffer = new ArrayBuffer(2);
const cloned = structuredClone(buffer, { transfer: [buffer] });
expect(() => {
structuredClone(buffer, { transfer: [buffer] });
}).toThrow(DOMException);
});
test("Transferring a non-transferable platform object fails", () => {
const blob = new Blob();
expect(() => {
structuredClone(blob, { transfer: [blob] });
}).toThrow(DOMException);
});
});
});
async function compareBlobs(original: Blob, cloned: Blob) {
expect(cloned).toBeInstanceOf(Blob);
expect(cloned).not.toBe(original);
expect(cloned.size).toBe(original.size);
expect(cloned.type).toBe(original.type);
const ab1 = await new Response(cloned).arrayBuffer();
const ab2 = await new Response(original).arrayBuffer();
expect(ab1.byteLength).toBe(ab2.byteLength);
const ta1 = new Uint8Array(ab1);
const ta2 = new Uint8Array(ab2);
for (let i = 0; i < ta1.length; i++) {
expect(ta1[i]).toBe(ta2[i]);
}
}
function encode_cesu8(codeunits: number[]): number[] {
// http://www.unicode.org/reports/tr26/ section 2.2
// only the 3-byte form is supported
const rv: number[] = [];
codeunits.forEach(function (codeunit) {
rv.push(b("11100000") + ((codeunit & b("1111000000000000")) >> 12));
rv.push(b("10000000") + ((codeunit & b("0000111111000000")) >> 6));
rv.push(b("10000000") + (codeunit & b("0000000000111111")));
});
return rv;
}
function b(s: string): number {
return parseInt(s, 2);
}
function createBlob(arr: number[]): Blob {
const buffer = new ArrayBuffer(arr.length);
const view = new DataView(buffer);
for (let i = 0; i < arr.length; i++) {
view.setUint8(i, arr[i]);
}
return new Blob([view]);
}
red/linux'>jarred/linux
Unnamed repository; edit this file 'description' to name the repository. | |
Age | Commit message (Collapse) | Author | Files | Lines |
|
|
|
|
|
|
|
|