/*
Unit tests for source covering its documented public contract and regression-sensitive edge cases.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-0214: initial source tests.
*/
import { test, expect } from "vitest";
import { sourceDescriptorSchema, extractJsonPath, compareValues, coerceNumber } from "../source.ts";
test("descriptor: valid http-json passes", () => {
const r = sourceDescriptorSchema.safeParse({
id: "gov:destatis-backnang",
title: "Backnang residents",
kind: "http-json",
endpoint: "https://example.org/api",
extract: "$.population",
expectedType: "integer",
checkEvery: "P3M",
});
expect(r.success).toBe(true);
});
test("descriptor: http-json without extract fails", () => {
const r = sourceDescriptorSchema.safeParse({
id: "x",
title: "x",
kind: "http-json",
endpoint: "https://example.org/api",
expectedType: "integer",
checkEvery: "P3M",
});
expect(r.success).toBe(false);
});
test("descriptor: manual without endpoint passes", () => {
const r = sourceDescriptorSchema.safeParse({
id: "manual:civic",
title: "Civic registry",
kind: "manual",
expectedType: "string",
checkEvery: "P1Y",
});
expect(r.success).toBe(true);
});
test("extractJsonPath: dotted + array access", () => {
const payload = { region: { cities: [{ population: 39120 }, { population: 1 }] } };
expect(extractJsonPath(payload, "$.region.cities[0].population")).toBe(39120);
expect(extractJsonPath(payload, "$.region.cities[1].population")).toBe(1);
expect(extractJsonPath(payload, "$.region.missing")).toBe(undefined);
});
test("coerceNumber: pulls numbers from money strings", () => {
expect(coerceNumber("70 € / Monat")).toBe(70);
expect(coerceNumber("39.120")).toBe(39120);
expect(coerceNumber("39,120")).toBe(39120);
expect(coerceNumber(700)).toBe(700);
});
test("compareValues: exact numeric divergence", () => {
const r = compareValues("38500", "39120", "integer");
expect(r.withinTolerance).toBe(false);
});
test("compareValues: relative tolerance allows small drift", () => {
const r = compareValues(38500, 39120, "integer", { kind: "relative", value: 0.05 });
expect(r.withinTolerance).toBe(true); // 1.6% < 5%
});
test("compareValues: string normalized exact", () => {
expect(compareValues("DE ", "DE", "string").withinTolerance).toBe(true);
expect(compareValues("DE", "FR", "string").withinTolerance).toBe(false);
});