1import { assert, assertEquals } from "@std/assert";2import {3 buildRegistry,4 exitPose,5 reverseDef,6 validateRegistry,7 windowCells,8} from "../src/gen/registry.ts";910const reg = buildRegistry();1112Deno.test("registry passes self-validation", () => {13 const errors = validateRegistry(reg);14 assertEquals(errors, []);15});1617Deno.test("corner reversed is a right turn exiting +x", () => {18 const corner = reg.variants.find((d) => d.id === "corner" && !d.reversed)!;19 const rev = reverseDef(corner);20 assertEquals(rev.moves, "R");21 const exit = exitPose(rev);22 assertEquals(exit.dir, 0); // +x23 assertEquals([exit.pos[0], exit.pos[2]], [0.5, 0]);24});2526Deno.test("curve window is F,L,F and covers a 2x2 block", () => {27 const curve = reg.variants.find((d) => d.id === "curve" && !d.reversed)!;28 assertEquals(curve.moves, "FLF");29 const cells = windowCells(curve).map((c) => c.cell);30 assertEquals(cells, [[0, 0], [0, 1], [-1, 1]]);31 assertEquals(curve.footprint.length, 4);32});3334Deno.test("slant descents exist as reversed variants", () => {35 const descents = reg.variants.filter((d) => d.reversed && d.deckDelta < 0);36 assert(descents.length >= 4, `only ${descents.length} descents`);37 for (const d of descents) {38 // Reversed climb: entry floor sits deckDelta above exit — exit base is 0.39 assertEquals(exitPose(d).baseY, d.deckDelta);40 }41});4243Deno.test("every moves-key has at least one variant; F has the straight fallback", () => {44 const f = reg.byMoves.get("F")!;45 assert(f.some((d) => d.id === "straight" && d.deckDelta === 0));46 assert(reg.byMoves.get("L")!.some((d) => d.id === "corner"));47 assert(reg.byMoves.get("R")!.some((d) => d.id === "corner" && d.reversed));48});4950Deno.test("bend is a 2-cell U-turn window with an RR reversed variant", () => {51 const bend = reg.variants.find((d) => d.id === "bend" && !d.reversed)!;52 assertEquals(bend.moves, "LL");53 const exit = exitPose(bend);54 assertEquals(exit.dir, 3); // exits −z, back out the entry face55 assertEquals([exit.pos[0], exit.pos[2]], [-1, -0.5]);56 assert(reg.byMoves.get("RR")!.some((d) => d.id === "bend" && d.reversed));57});5859Deno.test("mirrored short s-curve renders the left mesh flipped", () => {60 const right = reg.variants.find(61 (d) => d.id === "s-curve-short-right-c" && !d.reversed,62 )!;63 assertEquals(right.moves, "FLR");64 assertEquals(right.meshId, "s-curve-short-left-c");65 assert(right.mirrored);66 const exit = exitPose(right);67 assertEquals([exit.pos[0], exit.pos[2]], [-1, 1.5]);68});6970Deno.test("funnel's reversed variant survives dedup via width asymmetry", () => {71 const rev = reg.variants.find((d) => d.id === "funnel" && d.reversed);72 assert(rev, "reversed funnel missing");73 assertEquals(rev!.widthIn, "wide");74 assertEquals(rev!.widthOut, "narrow");75});7677Deno.test("helix-loop topology specs match the registry defs' moves", async () => {78 const { HELIX_LOOP_SPECS } = await import("../src/gen/topology.ts");79 for (const spec of HELIX_LOOP_SPECS) {80 const def = reg.variants.find((v) => v.id === spec.id && !v.reversed);81 assert(def, `no def for ${spec.id}`);82 assertEquals(def!.moves, spec.moves, spec.id);83 assertEquals(def!.moves[0], spec.turn, spec.id);84 }85});