import { describe, expect, it } from "vitest"; import { distanceToRouteM, evaluateRouteDeviation } from "../src/lib/route-deviation"; describe("route deviation", () => { it("calculates the cross-track distance to a route segment", () => { const distance = distanceToRouteM( { lat: 0.001, lon: 0.005 }, [[0, 0], [0.01, 0]] ); expect(distance).toBeGreaterThan(110); expect(distance).toBeLessThan(112.5); }); it("uses the endpoint when the nearest point lies beyond the segment", () => { const distance = distanceToRouteM( { lat: 0, lon: 0.02 }, [[0, 0], [0.01, 0]] ); expect(distance).toBeGreaterThan(1_110); expect(distance).toBeLessThan(1_113); }); it("handles a short segment crossing the antimeridian", () => { const distance = distanceToRouteM( { lat: 0.001, lon: 180 }, [[179.9, 0], [-179.9, 0]] ); expect(distance).toBeGreaterThan(110); expect(distance).toBeLessThan(113); }); it("accounts conservatively for GPS accuracy and suppresses unreliable alarms", () => { const route = [[0, 0], [0.01, 0]] as const; const near = evaluateRouteDeviation({ lat: 0.001, lon: 0.005 }, route, { thresholdM: 100, accuracyM: 30 }); const away = evaluateRouteDeviation({ lat: 0.002, lon: 0.005 }, route, { thresholdM: 100, accuracyM: 30 }); const inaccurate = evaluateRouteDeviation({ lat: 0.01, lon: 0.005 }, route, { thresholdM: 100, accuracyM: 500 }); expect(near?.isOffRoute).toBe(false); expect(near?.conservativeDistanceM).toBeLessThan(100); expect(away?.isOffRoute).toBe(true); expect(inaccurate?.reliable).toBe(false); expect(inaccurate?.isOffRoute).toBe(false); }); it("returns null instead of alarming for invalid or missing route data", () => { expect(distanceToRouteM({ lat: Number.NaN, lon: 7 }, [[7, 53], [7.1, 53.1]])).toBeNull(); expect(distanceToRouteM({ lat: 53, lon: 7 }, [])).toBeNull(); }); });