Some checks failed
Multi-MDX Regression (IMP-91) / multi-mdx-regression (push) Failing after 23s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
223 lines
9.3 KiB
TypeScript
223 lines
9.3 KiB
TypeScript
// IMP-44 (#73) u3 — vitest coverage for `validateZoneGeometriesAgainstLayout`.
|
|
//
|
|
// Pairs with the backend [override-warning] guards added in u1 (1-D
|
|
// horizontal-2 / vertical-2 branches of `build_layout_css`) and u2 (2-D
|
|
// `_override_to_grid_tracks` call site). Same WARN+DROP unknown / KEEP known
|
|
// contract; this helper lets handleGenerate (u4) validate against the active
|
|
// layout before forwarding so the user sees a toast on dropped keys rather
|
|
// than the backend silently even-splitting non-overridden zones with a false
|
|
// `computation=user_override_geometry` signal.
|
|
//
|
|
// Cases (Stage 2 scope-lock):
|
|
// 1) horizontal-2 → vertical-2 mismatch (all keys dropped)
|
|
// 2) passthrough (all keys recognized)
|
|
// 3) partial mix (some kept, some dropped)
|
|
// 4) empty input ({} on a known layout)
|
|
// 5) unknown-layout fail-safe (preset null / undefined / unknown string)
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { validateZoneGeometriesAgainstLayout } from "../src/utils/slidePlanUtils";
|
|
|
|
const g = (x: number, y: number, w: number, h: number) => ({ x, y, w, h });
|
|
|
|
describe("validateZoneGeometriesAgainstLayout (IMP-44 u3)", () => {
|
|
// ── 1. mismatch ──────────────────────────────────────────────────────────
|
|
it("drops horizontal-2 keys when the active layout is vertical-2", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{ top: g(0, 0, 1, 0.4), bottom: g(0, 0.4, 1, 0.6) },
|
|
"vertical-2",
|
|
);
|
|
expect(result.kept).toEqual({});
|
|
expect(result.dropped).toEqual({
|
|
top: g(0, 0, 1, 0.4),
|
|
bottom: g(0, 0.4, 1, 0.6),
|
|
});
|
|
expect(result.expectedPositions).toEqual(["left", "right"]);
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
|
|
it("drops vertical-2 keys when the active layout is horizontal-2", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{ left: g(0, 0, 0.5, 1), right: g(0.5, 0, 0.5, 1) },
|
|
"horizontal-2",
|
|
);
|
|
expect(result.kept).toEqual({});
|
|
expect(Object.keys(result.dropped).sort()).toEqual(["left", "right"]);
|
|
expect(result.expectedPositions).toEqual(["top", "bottom"]);
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
|
|
// ── 2. passthrough ───────────────────────────────────────────────────────
|
|
it("keeps all keys when every input key is in the active layout positions", () => {
|
|
const input = {
|
|
top: g(0, 0, 1, 0.4),
|
|
bottom: g(0, 0.4, 1, 0.6),
|
|
};
|
|
const result = validateZoneGeometriesAgainstLayout(input, "horizontal-2");
|
|
expect(result.kept).toEqual(input);
|
|
expect(result.dropped).toEqual({});
|
|
expect(result.expectedPositions).toEqual(["top", "bottom"]);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it("passes a single 'primary' key through on the 'single' preset", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{ primary: g(0, 0, 1, 1) },
|
|
"single",
|
|
);
|
|
expect(result.kept).toEqual({ primary: g(0, 0, 1, 1) });
|
|
expect(result.dropped).toEqual({});
|
|
expect(result.expectedPositions).toEqual(["primary"]);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it("recognizes the 2-D preset positions reported by computeZonePositions (top-1-bottom-2)", () => {
|
|
const input = {
|
|
top: g(0, 0, 1, 0.5),
|
|
"bottom-left": g(0, 0.5, 0.5, 0.5),
|
|
"bottom-right": g(0.5, 0.5, 0.5, 0.5),
|
|
};
|
|
const result = validateZoneGeometriesAgainstLayout(input, "top-1-bottom-2");
|
|
expect(result.kept).toEqual(input);
|
|
expect(result.dropped).toEqual({});
|
|
expect(result.expectedPositions).toEqual([
|
|
"top",
|
|
"bottom-left",
|
|
"bottom-right",
|
|
]);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
// ── 3. partial mix ───────────────────────────────────────────────────────
|
|
it("keeps known keys and drops unknown keys on a partial-mix input", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{ top: g(0, 0, 1, 0.4), foo: g(0, 0, 1, 1) },
|
|
"horizontal-2",
|
|
);
|
|
expect(result.kept).toEqual({ top: g(0, 0, 1, 0.4) });
|
|
expect(result.dropped).toEqual({ foo: g(0, 0, 1, 1) });
|
|
expect(result.expectedPositions).toEqual(["top", "bottom"]);
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
|
|
it("on a 2-D preset, keeps known 2-D track keys and drops legacy 1-D keys", () => {
|
|
// Simulates the user resizing under top-1-bottom-2, then flipping to
|
|
// grid-2x2 — legacy `bottom-left` stays valid; `top` (no longer a 2x2
|
|
// position) gets dropped.
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{
|
|
top: g(0, 0, 1, 0.5),
|
|
"bottom-left": g(0, 0.5, 0.5, 0.5),
|
|
"top-left": g(0, 0, 0.5, 0.5),
|
|
},
|
|
"grid-2x2",
|
|
);
|
|
expect(result.kept).toEqual({
|
|
"bottom-left": g(0, 0.5, 0.5, 0.5),
|
|
"top-left": g(0, 0, 0.5, 0.5),
|
|
});
|
|
expect(result.dropped).toEqual({ top: g(0, 0, 1, 0.5) });
|
|
expect(result.expectedPositions).toEqual([
|
|
"top-left",
|
|
"top-right",
|
|
"bottom-left",
|
|
"bottom-right",
|
|
]);
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
|
|
// ── 4. empty input ───────────────────────────────────────────────────────
|
|
it("returns empty kept/dropped and valid=true on an empty {} input", () => {
|
|
const result = validateZoneGeometriesAgainstLayout({}, "horizontal-2");
|
|
expect(result.kept).toEqual({});
|
|
expect(result.dropped).toEqual({});
|
|
expect(result.expectedPositions).toEqual(["top", "bottom"]);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it("treats null / undefined geoms as empty input (no throw, valid=true on a known layout)", () => {
|
|
const nullResult = validateZoneGeometriesAgainstLayout(null, "vertical-2");
|
|
expect(nullResult.kept).toEqual({});
|
|
expect(nullResult.dropped).toEqual({});
|
|
expect(nullResult.expectedPositions).toEqual(["left", "right"]);
|
|
expect(nullResult.valid).toBe(true);
|
|
|
|
const undefResult = validateZoneGeometriesAgainstLayout(
|
|
undefined,
|
|
"vertical-2",
|
|
);
|
|
expect(undefResult.kept).toEqual({});
|
|
expect(undefResult.dropped).toEqual({});
|
|
expect(undefResult.expectedPositions).toEqual(["left", "right"]);
|
|
expect(undefResult.valid).toBe(true);
|
|
});
|
|
|
|
it("ignores array payloads (defensive against hand-edited persisted files)", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
[] as unknown as Record<string, { x: number; y: number; w: number; h: number }>,
|
|
"horizontal-2",
|
|
);
|
|
expect(result.kept).toEqual({});
|
|
expect(result.dropped).toEqual({});
|
|
expect(result.expectedPositions).toEqual(["top", "bottom"]);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
// ── 5. unknown-layout fail-safe ──────────────────────────────────────────
|
|
it("drops every input key when layout is null (fail-safe)", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{ top: g(0, 0, 1, 0.4), bottom: g(0, 0.4, 1, 0.6) },
|
|
null,
|
|
);
|
|
expect(result.kept).toEqual({});
|
|
expect(result.dropped).toEqual({
|
|
top: g(0, 0, 1, 0.4),
|
|
bottom: g(0, 0.4, 1, 0.6),
|
|
});
|
|
expect(result.expectedPositions).toEqual([]);
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
|
|
it("drops every input key when layout is undefined (fail-safe)", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{ primary: g(0, 0, 1, 1) },
|
|
undefined,
|
|
);
|
|
expect(result.kept).toEqual({});
|
|
expect(result.dropped).toEqual({ primary: g(0, 0, 1, 1) });
|
|
expect(result.expectedPositions).toEqual([]);
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
|
|
it("drops every input key when layout is an unknown preset string (fail-safe)", () => {
|
|
const result = validateZoneGeometriesAgainstLayout(
|
|
{ top: g(0, 0, 1, 0.4) },
|
|
"rogue-preset" as unknown as string,
|
|
);
|
|
expect(result.kept).toEqual({});
|
|
expect(result.dropped).toEqual({ top: g(0, 0, 1, 0.4) });
|
|
expect(result.expectedPositions).toEqual([]);
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
|
|
it("returns empty kept/dropped/expectedPositions when layout is unknown AND geoms is empty", () => {
|
|
const result = validateZoneGeometriesAgainstLayout({}, null);
|
|
expect(result.kept).toEqual({});
|
|
expect(result.dropped).toEqual({});
|
|
expect(result.expectedPositions).toEqual([]);
|
|
// No keys to drop ⇒ vacuously valid; handleGenerate (u4) gates the toast
|
|
// on `Object.keys(dropped).length > 0`, not `valid`, so this is safe.
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
// ── purity / mutation safety ─────────────────────────────────────────────
|
|
it("does not mutate the input geometries object", () => {
|
|
const input = { top: g(0, 0, 1, 0.4), foo: g(0, 0, 1, 1) };
|
|
const inputKeysBefore = Object.keys(input).sort();
|
|
validateZoneGeometriesAgainstLayout(input, "horizontal-2");
|
|
expect(Object.keys(input).sort()).toEqual(inputKeysBefore);
|
|
// Sample value still pristine.
|
|
expect(input.top).toEqual(g(0, 0, 1, 0.4));
|
|
});
|
|
});
|