Files
suaveplan/packages/security-stack/security/password-strength/src/graphs/validate-graph.test.ts
2026-05-27 23:47:53 +01:00

60 lines
2.0 KiB
TypeScript

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();
});
});