Files
sudoku-tools/tests/domain/constraintRegistry.test.ts

124 lines
3.2 KiB
TypeScript

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