import { parseTransactionsQuery, parseWindow, parseVerifyTargets, isUuid } from "./validate.js"; describe("parseTransactionsQuery", () => { it("defaults type=core, dir=desc, sort undefined, and a 30-day window", () => { const { ok, value } = parseTransactionsQuery({}); expect(ok).toBe(true); expect(value.type).toBe("core"); expect(value.dir).toBe("desc"); expect(value.sort).toBeUndefined(); expect(value.limit).toBe(50); expect(value.offset).toBe(0); expect(value.from).toMatch(/^\d{4}-\d{2}-\d{2}$/); }); it("accepts valid discrete params", () => { const { ok, value } = parseTransactionsQuery({ type: "audit", sort: "size", dir: "asc" }); expect(ok).toBe(true); expect(value).toMatchObject({ type: "audit", sort: "size", dir: "asc" }); }); it("rejects an invalid type", () => { expect(parseTransactionsQuery({ type: "bogus" })).toMatchObject({ ok: false }); }); it("rejects an invalid sort key", () => { expect(parseTransactionsQuery({ sort: "sender; DROP" })).toMatchObject({ ok: false }); }); it("rejects an invalid dir", () => { expect(parseTransactionsQuery({ dir: "sideways" })).toMatchObject({ ok: false }); }); it("clamps limit/offset and caps search length", () => { const { value } = parseTransactionsQuery({ limit: "99999", offset: "-3", q: "x".repeat(500) }); expect(value.limit).toBe(200); expect(value.offset).toBe(0); expect(value.q).toHaveLength(200); }); }); describe("parseWindow", () => { it("normalizes to a { from, to } window", () => { expect(parseWindow({ from: "2026-01-01", to: "2026-01-31" })).toEqual({ from: "2026-01-01", to: "2026-01-31", }); }); }); describe("parseVerifyTargets", () => { const U1 = "3fa85f64-5717-4562-b3fc-2c963f66afa6"; const U2 = "11111111-2222-3333-4444-555555555555"; it("keeps valid UUIDs, drops junk, and de-duplicates", () => { expect(parseVerifyTargets({ ids: `${U1}, junk ,${U2},${U1}` })).toEqual({ eventUuids: [U1, U2], auditIds: [], }); }); it("parses audit ids as positive integers, dropping anything else", () => { expect(parseVerifyTargets({ auditIds: "9, 10 ,9,0,-3,abc,1.5" })).toEqual({ eventUuids: [], auditIds: [9, 10], }); }); it("accepts both lists at once (core rows by event, audit rows by audit id)", () => { expect(parseVerifyTargets({ ids: U1, auditIds: "42" })).toEqual({ eventUuids: [U1], auditIds: [42], }); }); it("returns empty lists when absent or empty", () => { expect(parseVerifyTargets({})).toEqual({ eventUuids: [], auditIds: [] }); expect(parseVerifyTargets({ ids: "", auditIds: "" })).toEqual({ eventUuids: [], auditIds: [] }); }); it("caps the two lists at 200 targets COMBINED", () => { const auditIds = Array.from({ length: 250 }, (_, i) => i + 1).join(","); const one = parseVerifyTargets({ auditIds }); expect(one.auditIds).toHaveLength(200); // 150 events leaves room for only 50 audit ids. const events = Array.from({ length: 150 }, (_, i) => `3fa85f64-5717-4562-b3fc-${String(i).padStart(12, "0")}`).join(","); const both = parseVerifyTargets({ ids: events, auditIds }); expect(both.eventUuids).toHaveLength(150); expect(both.auditIds).toHaveLength(50); }); }); describe("isUuid", () => { it("accepts canonical UUIDs and rejects junk", () => { expect(isUuid("3fa85f64-5717-4562-b3fc-2c963f66afa6")).toBe(true); expect(isUuid("not-a-uuid")).toBe(false); expect(isUuid("")).toBe(false); expect(isUuid(null)).toBe(false); }); });