eleven / ocho Public

Clone
git clone https://amadan.net/eleven/ocho

Plain git — no account needed to clone.

Download

Download this file

1// 🤖 Card schema contract tests: normalizeCard against every vector in
2// test/event-vectors/cards.json (the same file LChatCore's CardVectorTests
3// consumes). A failure here means the web renderer has drifted from the
4// contract — fix the implementation, never the vector, unless the schema
5// itself is deliberately changing on both platforms in one PR.
6import { readFileSync } from "node:fs";
7import { normalizeCard, CARD_SCHEMA } from "../web/static/cards.js";
8
9let failures = 0;
10function check(name, cond, detail) {
11 if (cond) {
12 console.log("PASS ", name);
13 } else {
14 failures++;
15 console.error("FAIL ", name, detail ?? "");
16 }
17}
18
19// Canonical (sorted-key) stringify: the contract is about VALUES — JSON key
20// order is an artifact of each language's object representation.
21function canon(v) {
22 if (Array.isArray(v)) return "[" + v.map(canon).join(",") + "]";
23 if (v && typeof v === "object") {
24 return "{" + Object.keys(v).sort().map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
25 }
26 return JSON.stringify(v);
27}
28
29const { schema, vectors } = JSON.parse(readFileSync(new URL("./event-vectors/cards.json", import.meta.url)));
30check("vector file schema matches CARD_SCHEMA", schema === CARD_SCHEMA);
31
32for (const v of vectors) {
33 const got = normalizeCard(v.card);
34 const ok = canon(got) === canon(v.want);
35 check(v.name, ok, ok ? "" : `\n got ${canon(got)}\n want ${canon(v.want)}`);
36}
37
38// Bounds behave as bounds: 33 top-level blocks is one too many.
39const many = { schema: 1, blocks: Array.from({ length: 33 }, () => ({ b: "text", text: "x" })) };
40check("block cap fails closed", normalizeCard(many) === null);
41const atCap = { schema: 1, blocks: Array.from({ length: 32 }, () => ({ b: "text", text: "x" })) };
42check("block cap is inclusive", normalizeCard(atCap) !== null);
43
44// Normalizing is idempotent: normalize(normalize(c)) === normalize(c).
45for (const v of vectors) {
46 if (!v.want) continue;
47 const once = normalizeCard(v.card);
48 check(`idempotent: ${v.name}`, canon(normalizeCard(once)) === canon(once));
49}
50
51// The Swift test fixture must be a byte-identical copy of the canonical
52// vectors — the bundled copy exists only because SwiftPM tests can't reach
53// outside the package. Drift here means the native suite is pinning a stale
54// contract: re-copy test/event-vectors/cards.json over the fixture.
55const canonical = readFileSync(new URL("./event-vectors/cards.json", import.meta.url), "utf8");
56const fixture = readFileSync(new URL("../ios/LChatCore/Tests/LChatCoreTests/Fixtures/cards-vector.json", import.meta.url), "utf8");
57check("Swift fixture matches canonical vectors byte-for-byte", canonical === fixture);
58
59if (failures) {
60 console.error(`\n${failures} failure(s)`);
61 process.exit(1);
62}
63console.log("\nALL PASSED");
64