pi-mono/packages/chord/test/link/values.test.ts
Mario Zechner e9c0ff4d84 feat(chord): Chord v2 is the package's root
src/next is src (the main export), src/next-node is src/node with short subpaths (/http, /workers, /plugins,
/plugins/runtime, /app, /surfaces, /web, /react, /tui, /tui/launcher); the foundations get /json and /watch;
Chord v1 moves to src/old (/old, /old/node) until p2 runs on v2; tests and docs move likewise (test/, docs/,
test/old, docs/old). Durable and env import the foundations from their subpaths.
2026-11-02 22:36:55 +00:00

72 lines
3.2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { isChordError } from "../../src/data/index.ts";
import { jsonPart, parsePart, parsePayload, payloadPart, resolveSegments } from "../../src/link/values.ts";
describe("parts", () => {
it("are JSON text at their origin, parsed from text or from UTF-8 bytes where they are owned", () => {
expect(jsonPart({ a: [1, "x"] })).toBe('{"a":[1,"x"]}');
expect(jsonPart(undefined)).toBe("null");
expect(parsePart('{"a":1}')).toEqual({ a: 1 });
expect(parsePart(new TextEncoder().encode('{"a":"\u00e9"}'))).toEqual({ a: "\u00e9" });
});
it("that are no strict UTF-8 JSON throw (a protocol error where they are parsed)", () => {
expect(() => parsePart("{")).toThrow();
expect(() => parsePart(new Uint8Array([0x22, 0xff, 0x22]))).toThrow();
});
});
describe("payloads", () => {
it("marked as carrying bytes write each byte leaf as a segment referenced by {$bytes: i}", () => {
const data = new Uint8Array(1024).fill(7);
const thumbs = [new Uint8Array([1, 2]), new Uint8Array([3])];
const { json, segments } = payloadPart({ name: "chart.png", data, thumbs }, true);
expect(json).toBe('{"name":"chart.png","data":{"$bytes":0},"thumbs":[{"$bytes":1},{"$bytes":2}]}');
expect(segments).toEqual([data, ...thumbs]);
expect(segments![0]).toBe(data);
const read = parsePayload(json, segments) as { data: Uint8Array; thumbs: Uint8Array[] };
expect(read.data).toBe(data);
expect(read.thumbs).toEqual(thumbs);
});
it("carry any Uint8Array subclass as bytes: a Node Buffer, whose toJSON the replacer never sees (slice 11)", () => {
const buffer = Buffer.from([1, 2, 3]);
const { json, segments } = payloadPart({ bytes: buffer, at: [buffer] }, true);
expect(json).toBe('{"bytes":{"$bytes":0},"at":[{"$bytes":1}]}');
expect(segments![0]).toBe(buffer);
expect(payloadPart(buffer, true)).toEqual({ json: '{"$bytes":0}', segments: [buffer] });
});
it("marked as carrying bytes refuse the reserved key $bytes with invalid/args", () => {
let thrown: unknown;
try {
payloadPart({ meta: { $bytes: 0 }, data: new Uint8Array(1) }, true);
} catch (error) {
thrown = error;
}
expect(isChordError(thrown, "invalid") && thrown.reason).toBe("args");
});
it("not marked are plain JSON, $bytes included; undefined is null", () => {
expect(payloadPart({ $bytes: 0 }, false)).toEqual({ json: '{"$bytes":0}', segments: undefined });
expect(payloadPart(undefined, false).json).toBe("null");
expect(parsePayload('{"$bytes":0}', undefined)).toEqual({ $bytes: 0 });
});
it.each([
["an index past the segments", { $bytes: 1 }],
["a non-integer index", { $bytes: "0" }],
["other keys next to $bytes", { $bytes: 0, x: 1 }],
])("refuse a malformed reference: %s", (_, value) => {
expect(() => resolveSegments({ a: [value] }, [new Uint8Array(1)])).toThrow(
"payload: a malformed byte segment reference",
);
});
it("define a resolved key __proto__ as an own property", () => {
const parsed = JSON.parse('{"__proto__":{"$bytes":0}}');
const resolved = resolveSegments(parsed, [new Uint8Array(1)]) as object;
expect(Object.getPrototypeOf(resolved)).toBe(Object.prototype);
expect(Object.getOwnPropertyDescriptor(resolved, "__proto__")?.value).toEqual(new Uint8Array(1));
});
});