import { describe, expect, it } from "@suaveplan/testing/runner"; import { type PasswordStrengthError, PWSTRENGTH_CODES, } from "../errors/error-codes.js"; import { AZERTY_GRAPH } from "./azerty/azerty.js"; import { DVORAK_GRAPH } from "./dvorak/dvorak.js"; import { QWERTY_GRAPH } from "./qwerty/qwerty.js"; import { validateGraph } from "./validate-graph.js"; describe("validateGraph", () => { it("accepts QWERTY", { timeout: 5000 }, () => { expect(() => validateGraph("qwerty", QWERTY_GRAPH)).not.toThrow(); }); it("accepts DVORAK", { timeout: 5000 }, () => { expect(() => validateGraph("dvorak", DVORAK_GRAPH)).not.toThrow(); }); it("accepts AZERTY", { timeout: 5000 }, () => { expect(() => validateGraph("azerty", AZERTY_GRAPH)).not.toThrow(); }); it("rejects self-adjacency", { timeout: 5000 }, () => { try { validateGraph("broken", { q: ["q"] }); } catch (e) { expect((e as PasswordStrengthError).code).toBe( PWSTRENGTH_CODES.GRAPH_INVALID ); } }); it("rejects asymmetric edges", { timeout: 5000 }, () => { try { validateGraph("asym", { a: ["b"], b: ["c"], c: ["b"] }); } catch (e) { expect((e as PasswordStrengthError).code).toBe( PWSTRENGTH_CODES.GRAPH_INVALID ); } }); it("skips null slots", { timeout: 5000 }, () => { // graph with only null slots is trivially symmetric expect(() => validateGraph("nullonly", { a: [null], b: [null] }) ).not.toThrow(); }); it("skips empty adjacency lists", { timeout: 5000 }, () => { expect(() => validateGraph("empty", { a: [] })).not.toThrow(); }); it("skips edges pointing to keys not in graph", { timeout: 5000 }, () => { // x not in graph → neighbor undefined, skip expect(() => validateGraph("dangling", { a: ["x"] })).not.toThrow(); }); });