#!/usr/bin/env node /* * fixture-source.test.mjs — the fixture RoutingSource backend gates (F1–F8). * -------------------------------------------------------------------------- * RED first (plan 05-01 task 3): every case fails while * routing/src/fixture-source.ts does not exist. * * Datasets are SYNTHETIC and injected via createFixtureRoutingSource(data) — * never the network, never the committed file (that one is exercised by the * loader-env suite's L3 against the default source). * * F1 empty corpus -> null — the committed seed's state until 05-02 * F2 match serves best-first — backend tag, order, decoded geometry, * cumulative field, EMPTY steps (T-05-07) * F3 tolerance boundary — ~111 m serves; ~222 m is honest null * (the 200 m law, haversine-verified) * F4 slug guard — non-slug / over-long destinationId -> * null WITHOUT consulting the index (T-05-03) * F5 unknown destination — valid slug with no pair -> null (D-03, * never a nearest-match) * F6 malformed pair skipped — NaN distance / empty routes / throwing * geometry are skipped at index build; a * well-formed sibling still serves * F7 lazy index — source gate: no `new Map(` and no * `decodePolyline6(` call at TOP LEVEL * (gazetteer LAW 1 — Workers 1 s startup) * F8 getPairOrigin — slug-guarded lookup by pairId; positive * half is deferred while the committed * seed is empty (visible SKIP, the * loader-env L2/L3 precedent) * * Run: npm run routing:test (exit 0 = all green) */ import { strict as assert } from "node:assert"; import { readFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { test } from "./harness.mjs"; const here = path.dirname(fileURLToPath(import.meta.url)); // routing/test // Lazy module loads — missing modules => per-case ERR_MODULE_NOT_FOUND (RED). let polylinePromise = null; function loadPolyline() { if (!polylinePromise) polylinePromise = import("../src/polyline.ts"); return polylinePromise; } let sourcePromise = null; function loadSource() { if (!sourcePromise) sourcePromise = import("../src/fixture-source.ts"); return sourcePromise; } /* ————— synthetic dataset builder (public KL coordinates, 1e-6 grid) ————— */ const KL_TOWER = { lat: 3.1528, lng: 101.7038, label: "Kuala Lumpur Tower" }; const KL_SENTRAL = { lat: 3.1343, lng: 101.6869 }; const PATH_A = [ { lat: 3.1528, lng: 101.7038 }, { lat: 3.15, lng: 101.7 }, { lat: 3.14, lng: 101.69 }, { lat: 3.1343, lng: 101.6869 }, ]; const PATH_B = [ { lat: 3.1528, lng: 101.7038 }, { lat: 3.148, lng: 101.699 }, { lat: 3.1343, lng: 101.6869 }, ]; async function buildSyntheticDataset() { const { encodePolyline6 } = await loadPolyline(); return { version: 1, originToleranceM: 200, pairs: [ { pairId: "kl-tower-to-kl-sentral", origin: KL_TOWER, destinationId: "kl-sentral", routes: [ { geometry: encodePolyline6(PATH_A), distanceM: 4800, durationS: 600 }, { geometry: encodePolyline6(PATH_B), distanceM: 5200, durationS: 640 }, ], }, ], }; } /* ————— F1–F8 ————— */ test("F1 empty corpus -> null — every route() resolves null (the seed's state until 05-02)", async () => { const { createFixtureRoutingSource } = await loadSource(); const source = createFixtureRoutingSource({ version: 1, originToleranceM: 200, pairs: [] }); assert.equal(source.name, "fixture", "the backend tag is 'fixture'"); const result = await source.route({ origin: { lat: 3.1528, lng: 101.7038 }, destinationId: "kl-sentral", }); assert.equal(result, null, "an empty corpus is honest-null, never a fabricated route"); }); test("F2 match serves best-first — backend tag, order, decoded geometry, cumulative field, EMPTY steps", async () => { const { createFixtureRoutingSource } = await loadSource(); const data = await buildSyntheticDataset(); const source = createFixtureRoutingSource(data); const origin = { lat: 3.1528, lng: 101.7038 }; const result = await source.route({ origin, destinationId: "kl-sentral" }); assert.ok(result, "the pinned origin + matching destinationId must serve"); assert.equal(result.backend, "fixture"); assert.equal(result.destinationId, "kl-sentral"); assert.deepEqual(result.origin, origin); assert.equal(result.options.length, 2, "both synthetic routes serve, order preserved"); assert.deepEqual( result.options[0].geometry.points, PATH_A, "options[0] is fixture route 1 (best-first order preserved)", ); assert.equal(result.options[0].summary.distanceM, 4800); assert.equal(result.options[0].summary.durationS, 600); assert.equal(result.options[1].summary.distanceM, 5200); const cum = result.options[0].geometry.cumulativeDistanceM; assert.equal(cum.length, PATH_A.length, "cumulative is the same length as points"); assert.equal(cum[0], 0, "cumulative starts at 0"); for (let i = 1; i < cum.length; i++) { assert.ok(cum[i] >= cum[i - 1], "cumulative is non-decreasing"); assert.ok(Number.isFinite(cum[i]), "cumulative entries are finite meters"); } for (const option of result.options) { assert.deepEqual(option.steps, [], "fixture-world steps are ALWAYS empty (T-05-07, D-10)"); } }); test("F3 tolerance boundary — ~111 m from the pinned origin serves; ~222 m is honest null", async () => { const { createFixtureRoutingSource } = await loadSource(); const data = await buildSyntheticDataset(); const source = createFixtureRoutingSource(data); // 0.001 deg lat ~= 111 m (haversine) — inside the 200 m tolerance. const near = await source.route({ origin: { lat: 3.1538, lng: 101.7038 }, destinationId: "kl-sentral", }); assert.ok(near, "GPS jitter within ~111 m of the pinned origin must still serve"); // 0.002 deg lat ~= 222 m — outside the 200 m tolerance. const far = await source.route({ origin: { lat: 3.1548, lng: 101.7038 }, destinationId: "kl-sentral", }); assert.equal(far, null, "beyond the tolerance the backend must NOT fabricate a route (D-03)"); }); test("F4 slug guard — non-slug and over-long destinationIds are refused before the index is touched", async () => { const { createFixtureRoutingSource } = await loadSource(); const data = await buildSyntheticDataset(); const source = createFixtureRoutingSource(data); const origin = { lat: 3.1528, lng: 101.7038 }; assert.equal( await source.route({ origin, destinationId: "not a slug!" }), null, "spaces/punctuation are refused by the slug guard (T-05-03)", ); assert.equal( await source.route({ origin, destinationId: "a".repeat(65) }), null, "a 65-char id exceeds the 1..64 slug charset — refused (hostile-shape DoS bound)", ); }); test("F5 unknown destination -> null — a valid slug with no pair is the honest pending state (D-03)", async () => { const { createFixtureRoutingSource } = await loadSource(); const data = await buildSyntheticDataset(); const source = createFixtureRoutingSource(data); const result = await source.route({ origin: { lat: 3.1528, lng: 101.7038 }, destinationId: "petronas-twin-towers", }); assert.equal(result, null, "never a nearest-match geometry for an unknown destination"); }); test("F6 malformed pair skipped — NaN distance / empty routes / throwing geometry never throw to the caller", async () => { const { createFixtureRoutingSource } = await loadSource(); const { encodePolyline6 } = await loadPolyline(); const broken = { version: 1, originToleranceM: 200, pairs: [ { pairId: "broken-nan", origin: { lat: 3.1528, lng: 101.7038, label: "broken distance" }, destinationId: "kl-sentral", routes: [ { geometry: encodePolyline6([{ lat: 3.1528, lng: 101.7038 }]), distanceM: Number.NaN, durationS: 100, }, ], }, { pairId: "broken-empty-routes", origin: { lat: 3.1528, lng: 101.7038, label: "empty routes" }, destinationId: "kl-sentral", routes: [], }, { pairId: "broken-throwing-geometry", origin: { lat: 3.1528, lng: 101.7038, label: "truncated polyline" }, destinationId: "kl-sentral", routes: [{ geometry: "A", distanceM: 100, durationS: 10 }], }, { pairId: "kl-tower-to-kl-sentral", origin: KL_TOWER, destinationId: "kl-sentral", routes: [ { geometry: encodePolyline6(PATH_A), distanceM: 4800, durationS: 600, }, ], }, ], }; const source = createFixtureRoutingSource(broken); const served = await source.route({ origin: { lat: 3.1528, lng: 101.7038 }, destinationId: "kl-sentral", }); assert.ok(served, "the well-formed sibling pair still serves"); assert.equal(served.options.length, 1, "only the well-formed pair is admitted"); assert.equal(served.options[0].summary.distanceM, 4800); }); test("F7 lazy index — no `new Map(` and no `decodePolyline6(` call at TOP LEVEL (gazetteer LAW 1)", () => { const srcPath = path.join(here, "..", "src", "fixture-source.ts"); const src = readFileSync(srcPath, "utf8"); // Strip comments first (the no-storage gate pattern) — prose is not a call site. const code = src .replace(/\/\*[\s\S]*?\*\//g, " ") .replace(/(^|[^:\\])\/\/[^\n]*/g, "$1"); for (const line of code.split("\n")) { if (line.trim() === "") continue; if (/^\s/.test(line)) continue; // indented => inside a function — allowed assert.ok( !line.includes("new Map("), `top-level index construction — LAW 1 violated: ${line.trim().slice(0, 60)}`, ); assert.ok( !line.includes("decodePolyline6("), `top-level geometry decode — LAW 1 violated: ${line.trim().slice(0, 60)}`, ); } }); test("F8 getPairOrigin — slug-guarded lookup; positive half deferred while the seed is empty", async () => { const mod = await loadSource(); assert.equal(mod.getPairOrigin("not a slug!"), null, "garbage pairId -> null (slug guard)"); assert.equal(mod.getPairOrigin("a".repeat(65)), null, "over-long pairId -> null"); assert.equal(mod.getPairOrigin("unknown-pair"), null, "unknown pair -> honest null"); const pairs = mod.getPairs(); assert.ok(Array.isArray(pairs), "getPairs returns an array"); if (pairs.length === 0) { console.log( "SKIP F8 (positive half) — the committed seed is empty until plan 05-02 populates it; the lookup machinery is proven by F2's injected dataset", ); return; } const first = pairs[0]; const origin = mod.getPairOrigin(first.pairId); assert.deepEqual( origin, { lat: first.origin.lat, lng: first.origin.lng }, "getPairOrigin resolves the pinned origin for a known pairId", ); });