import { describe, expect, it } from "vitest"; import { SUDOKU_DOCUMENT_SCHEMA } from "../../src/formats"; import { PROJECT_RECORD_SCHEMA, ProjectLibrary, createProjectRecord, normalizeProjectRecord, } from "../../src/storage"; const puzzle = { schema: SUDOKU_DOCUMENT_SCHEMA, version: 1 as const, size: 9, givens: Array(81).fill(0), constraints: [], }; describe("local project library", () => { it("stores independent bounded clones in the memory fallback", async () => { const library = new ProjectLibrary({ indexedDB: null }); const record = createProjectRecord(puzzle, { id: "one", title: "First", now: 100, progress: { version: 1, values: Array(81).fill(0), cornerMarks: Array.from({ length: 81 }, () => [1, 2]), centerMarks: Array.from({ length: 81 }, () => [3]), colors: Array(81).fill(2), elapsedMs: 1234, }, }); await library.put(record); const loaded = await library.get("one"); expect(loaded).toEqual(record); (loaded?.puzzle.givens as number[])[0] = 9; expect((await library.get("one"))?.puzzle.givens[0]).toBe(0); expect(library.mode).toBe("memory"); }); it("lists newest first, deletes and clears", async () => { const library = new ProjectLibrary({ indexedDB: null }); await library.put( createProjectRecord(puzzle, { id: "old", title: "Old", now: 1 }), ); await library.put( createProjectRecord(puzzle, { id: "new", title: "New", now: 2 }), ); expect((await library.list()).map(({ id }) => id)).toEqual(["new", "old"]); expect(await library.delete("old")).toBe(true); expect(await library.delete("missing")).toBe(false); await library.clear(); expect(await library.list()).toEqual([]); }); it("exports and imports an explicitly versioned library", async () => { const source = new ProjectLibrary({ indexedDB: null }); await source.put(createProjectRecord(puzzle, { id: "one", now: 10 })); const exported = await source.exportAll(); const target = new ProjectLibrary({ indexedDB: null }); expect(await target.importAll(exported)).toBe(1); expect(await target.get("one")).toEqual(await source.get("one")); }); it("falls back when IndexedDB cannot be opened", async () => { const broken = { open: () => { throw new Error("blocked"); }, } as unknown as IDBFactory; const library = new ProjectLibrary({ indexedDB: broken }); expect(await library.ready()).toBe("memory"); await library.put(createProjectRecord(puzzle, { id: "fallback", now: 1 })); expect(await library.get("fallback")).toBeDefined(); }); it("rejects malformed record versions and progress", () => { expect(() => normalizeProjectRecord({ schema: PROJECT_RECORD_SCHEMA, version: 2, }), ).toThrow(/Unsupported project record/u); const record = createProjectRecord(puzzle, { id: "bad", now: 1 }); expect(() => normalizeProjectRecord({ ...record, progress: { version: 1, values: [0] }, }), ).toThrow(/must contain 81/u); }); });