import { describe, expect, it } from "vitest"; import { CONSTRAINT_REGISTRY, CONSTRAINT_TYPES, constraintAllowedFields, constraintCells, constraintLabel, constraintMetadata, isConstraintType, type ConstraintType, } from "../../src/domain"; const expectedTypes = [ "diagonal", "anti-knight", "anti-king", "non-consecutive", "disjoint-groups", "killer-cage", "thermo", "arrow", "kropki", "xv", "inequality", "renban", "palindrome", "x-sum", "skyscraper", "quadruple", "maximum", "minimum", "odd", "even", "little-killer", "sandwich", "between-line", "german-whisper", "region-sum-line", "clone", "extra-region", "modular-line", "entropic-line", "zipper-line", "double-arrow", "indexer", "fog", ] as const satisfies readonly ConstraintType[]; describe("constraint registry", () => { it("contains one complete metadata entry for every constraint type", () => { expect([...CONSTRAINT_TYPES].sort()).toEqual([...expectedTypes].sort()); expect(Object.keys(CONSTRAINT_REGISTRY).sort()).toEqual( [...expectedTypes].sort(), ); for (const type of expectedTypes) { const metadata = constraintMetadata(type); expect(metadata.type).toBe(type); expect(metadata.label.length).toBeGreaterThan(0); expect(metadata.fields[0]).toEqual({ key: "type", kind: "discriminator", required: true, }); expect(new Set(metadata.fields.map(({ key }) => key)).size).toBe( metadata.fields.length, ); expect(constraintAllowedFields(type).has("negated")).toBe( metadata.negatable, ); } }); it("provides labels, field metadata and a safe type guard", () => { expect(constraintLabel("little-killer")).toBe("Little killer"); expect(constraintLabel("future-rule")).toBe("Future Rule"); expect(isConstraintType("sandwich")).toBe(true); expect(isConstraintType("not-a-rule")).toBe(false); expect(constraintAllowedFields("little-killer")).toEqual( new Set(["type", "side", "index", "direction", "sum", "negated"]), ); }); it("resolves global, line, outside and local footprints centrally", () => { expect(constraintCells(4, { type: "diagonal", direction: "anti" })).toEqual( [3, 6, 9, 12], ); expect(constraintCells(4, { type: "disjoint-groups" })).toHaveLength(16); expect(constraintCells(4, { type: "minimum", cell: 5 })).toEqual([ 5, 1, 9, 4, 6, ]); expect(constraintCells(4, { type: "odd", cell: 5 })).toEqual([5]); expect( constraintCells(4, { type: "little-killer", side: "top", index: 0, direction: "down-right", sum: 10, }), ).toEqual([0, 5, 10, 15]); expect( constraintCells(4, { type: "sandwich", side: "right", index: 2, sum: 3, }), ).toEqual([11, 10, 9, 8]); expect( constraintCells(4, { type: "clone", cells: [0, 1], cloneCells: [10, 11], }), ).toEqual([0, 1, 10, 11]); expect( constraintCells(4, { type: "indexer", kind: "box", cell: 0 }), ).toEqual([0, 2, 8, 10]); expect( constraintCells(4, { type: "fog", lights: [0, 5], revealRadius: 1 }), ).toEqual([0, 5]); }); });