import { assert, assertStringIncludes } from "@std/assert"; import { expect } from "@std/expect"; import { describe, it as test } from "@std/testing/bdd"; import { eventGroup, legReference, type RefPart } from "#accounting/refs.ts"; import { describeWithEnv } from "#test-utils/db.ts"; describeWithEnv("accounting > refs", { encryptionKey: true }, () => { describe("eventGroup", () => { test("is deterministic for the same parts", async () => { expect(await eventGroup(["booking", "abc"])).toBe( await eventGroup(["booking", "abc"]), ); }); test("differs for different parts", async () => { expect(await eventGroup(["booking", "abc"])).not.toBe( await eventGroup(["booking", "xyz"]), ); }); test("does not collide across different tuple shapes", async () => { // A `|`-joined encoding would collapse each of these pairs onto one key; // JSON encoding keeps them distinct. expect(await eventGroup(["booking", "a|b"])).not.toBe( await eventGroup(["booking", "a", "b"]), ); expect(await eventGroup(["a", "b"])).not.toBe(await eventGroup(["ab"])); }); }); describe("unsafe numeric parts", () => { const rejectionMessage = async (parts: RefPart[]): Promise => { try { await eventGroup(parts); } catch (error) { return (error as Error).message; } return ""; }; test("rejects a non-finite part rather than hashing an ambiguous null", async () => { assertStringIncludes( await rejectionMessage(["booking", Number.NaN]), "safe integer", ); }); test("rejects an integer past MAX_SAFE_INTEGER that would round and collide", async () => { // 2 ** 53 and 2 ** 53 + 1 round to the same float, so hashing them raw // would alias two distinct ids onto one reference. assertStringIncludes( await rejectionMessage(["booking", 2 ** 53]), "safe integer", ); }); }); describe("legReference", () => { test("is distinct from an event group built from the same parts", async () => { expect(await legReference(["booking", "abc"])).not.toBe( await eventGroup(["booking", "abc"]), ); }); test("distinguishes legs of the same event", async () => { const sale = await legReference(["booking", "abc", "sale", 1]); const payment = await legReference(["booking", "abc", "payment"]); expect(sale).not.toBe(payment); }); test("is non-empty and reveals nothing about its input", async () => { const ref = await legReference(["booking", "secret-payment-id"]); expect(ref.length).toBeGreaterThan(0); assert(!ref.includes("secret-payment-id")); }); }); });