clone

an offline map explorer where each world, from a game map to a city's open data, ships as one .atlas file

main
atlas / analysis / test / vectors.test.ts
vectors.test.ts 5.9K
1// The shared contract vectors, answered by the lane that owns the arithmetic.2//3// `analysis/testdata/cells/` is the language-neutral half of the two-lane4// bargain: the same JSON is read by this suite and by `tests/cells/` on the Go5// side, so the two copies of the cell arithmetic are held to one set of6// numbers rather than to each other's company. The hand-derived cases are7// marked `handDerived: true` — the geohash ones halved out on paper, the S28// ones the Go library's own test values — and every ground is either one of9// those derivations or a descriptor read from a public corpus bundle.10//11// Everything is compared as JSON text, byte for byte. That is not laziness:12// JSON is the only form both lanes share, it cannot carry a negative zero13// (which the surface arithmetic mints and both lanes must normalize away),14// and a comparison the fixture's own serialization defines is one no lane can15// quietly loosen.1617import assert from "node:assert/strict";18import { readFileSync, readdirSync } from "node:fs";19import { describe, it } from "node:test";20import path from "node:path";21import { fileURLToPath } from "node:url";2223import type { GroundedCellSystem } from "../cellsystems/contract.ts";24import type { Coordinate, Ground } from "../cellsystems/ground.ts";25import { surfaceExtent } from "../cellsystems/ground.ts";26import { applicableSystems, cellSystems, equivalentCell } from "../cellsystems/registry.ts";27import { geohashCellAt } from "../cellsystems/geohash.ts";28import { clipRingX } from "../cellsystems/ring.ts";29import type { Ring } from "../cellsystems/contract.ts";3031const here = path.dirname(fileURLToPath(import.meta.url));32const vectorsDir = path.join(here, "..", "testdata", "cells");3334/** One recorded ground: a Ground descriptor plus the two derived facts every consumer re-checks. */35interface RecordedGround extends Ground {36 readonly key: string;37 readonly surfaceExtent: readonly number[];38 readonly systems: readonly string[];39}4041/** One recorded call. Arguments are heterogeneous by family, so they stay unknown. */42interface Vector {43 readonly name: string;44 readonly ground: string;45 readonly system?: string;46 readonly call: string;47 readonly args?: readonly unknown[];48 readonly expect: unknown;49 readonly handDerived?: boolean;50}5152const readJSON = (name: string): unknown =>53 JSON.parse(readFileSync(path.join(vectorsDir, name), "utf8"));5455const grounds = (readJSON("grounds.json") as { grounds: Record<string, RecordedGround> }).grounds;5657const families = readdirSync(vectorsDir)58 .filter((name) => name.endsWith(".json") && name !== "grounds.json")59 .sort();6061/** JSON text is what "equal" means here; see the header. */62const text = (value: unknown): string => JSON.stringify(value) ?? "null";6364/**65 * The whole dispatch table a consumer of the vectors needs: four calls that66 * stand on their own, three contract methods that answer about the ground,67 * and the grounded fifteen behind everything else.68 */69function evaluate(ground: Ground, spec: Vector): unknown {70 const args = spec.args ?? [];71 switch (spec.call) {72 case "surfaceExtent":73 return surfaceExtent(ground);74 case "applicableSystems":75 return applicableSystems(ground).map((system) => system.slug);76 case "geohashCellAt":77 return geohashCellAt(ground, args[0] as Coordinate, args[1] as number);78 case "equivalentCell":79 return equivalentCell(80 ground,81 cellSystems.require(args[0] as string),82 cellSystems.require(args[1] as string),83 args[2] as string,84 );85 case "clipRingX":86 return clipRingX(args[0] as Ring, args[1] as number, args[2] as number);87 }88 assert.ok(spec.system, `${spec.name}: a contract call must name its system`);89 const system = cellSystems.require(spec.system);90 if (spec.call === "appliesTo" || spec.call === "maxLevel" || spec.call === "inputLength") {91 return system[spec.call](ground);92 }93 const grounded = system.on(ground);94 const method = grounded[spec.call as keyof GroundedCellSystem] as unknown;95 assert.equal(typeof method, "function", `${spec.system} has no method ${spec.call}`);96 return (method as (...rest: unknown[]) => unknown)(...args);97}9899describe("the shared vectors: grounds", () => {100 // The five hand-derived grounds and the two corpus ones, by name: a fixture101 // that silently lost a ground would otherwise pass by answering nothing.102 it("records the seven grounds both lanes stand on", () => {103 assert.deepEqual(Object.keys(grounds).sort(), [104 "bend-or/2026-08-02/0",105 "mars/global/0",106 "test/earth-8192x4096",107 "test/sphere-8192x4096",108 "test/square-1024",109 "test/square-1024-bounds",110 "test/square-1024-no-lens",111 ]);112 });113114 // The descriptors carry their own derived facts: the rectangle every115 // system divides, and which systems are willing to divide it. A candidate116 // free to carry the ground differently still has to land on these numbers.117 for (const [key, ground] of Object.entries(grounds)) {118 it(`${key} derives its own surface and systems`, () => {119 assert.equal(text(surfaceExtent(ground)), text(ground.surfaceExtent));120 assert.equal(121 text(applicableSystems(ground).map((system) => system.slug)),122 text(ground.systems),123 );124 });125 }126});127128for (const file of families) {129 const family = readJSON(file) as { family: string; cases: Vector[] };130 describe(`the shared vectors: ${family.family}`, () => {131 assert.ok(family.cases.length > 0, `${file} records no cases`);132 for (const spec of family.cases) {133 it(spec.name, () => {134 const ground = grounds[spec.ground];135 assert.ok(ground, `${file} names a ground grounds.json does not record: ${spec.ground}`);136 const value = evaluate(ground, spec);137 assert.equal(138 text(value),139 text(spec.expect),140 `${family.family}/${spec.name}${spec.handDerived ? " (hand-derived)" : ""}`,141 );142 });143 }144 });145}