import { describe, expect, it } from "vitest"; import { sampleOlpProject } from "../../src/olp/index.js"; import { MemoryWorkspaceStorage, detectWorkspaceDamage, exportWorkspaceBundle, importWorkspaceBundle, initializeWorkspace, migrateManifest, readJson, readManifest, readProjectModel, restoreWorkspace, snapshotWorkspace, writeJson, writeProjectModel } from "../../src/workspace/index.js"; const NOW = "2026-06-27T00:00:00.000Z"; describe("Workspace storage", () => { it("creates project manifest and conventional project layout", async () => { const storage = new MemoryWorkspaceStorage(); const manifest = await initializeWorkspace(storage, { projectId: "demo_cell", name: "Demo Cell", model: sampleOlpProject(), now: NOW }); expect(manifest.entrypoints.model).toBe("model/olp-project.json"); expect(await storage.list()).toEqual(["model/olp-project.json", "project.json"]); expect(await readManifest(storage)).toEqual(manifest); expect((await readProjectModel(storage)).project.id).toBe("demo_cell"); }); it("supports text/json read-write-delete with OPFS-like async storage", async () => { const storage = new MemoryWorkspaceStorage(); await storage.writeText("reports/readme.txt", "hello"); await writeJson(storage, "imports/report.json", { ok: true, count: 2 }); expect(await storage.readText("reports/readme.txt")).toBe("hello"); expect(await readJson(storage, "imports/report.json")).toEqual({ ok: true, count: 2 }); await storage.delete("reports/readme.txt"); expect(await storage.exists("reports/readme.txt")).toBe(false); }); it("snapshots and restores an equivalent workspace", async () => { const source = new MemoryWorkspaceStorage(); await initializeWorkspace(source, { projectId: "demo_cell", name: "Demo Cell", model: sampleOlpProject(), now: NOW }); await source.writeText("programs/main.grl", "language grl 0.1\n"); const snapshot = await snapshotWorkspace(source); const target = new MemoryWorkspaceStorage({ "old.txt": "delete me" }); await restoreWorkspace(target, snapshot); expect(await target.list()).toEqual(await source.list()); expect(await snapshotWorkspace(target)).toEqual(snapshot); }); it("exports and imports a stable JSON bundle with checksum", async () => { const source = new MemoryWorkspaceStorage(); await initializeWorkspace(source, { projectId: "demo_cell", name: "Demo Cell", model: sampleOlpProject(), now: NOW }); await source.writeText("programs/main.grl", "language grl 0.1\n"); const bundle = await exportWorkspaceBundle(source); const target = new MemoryWorkspaceStorage(); const report = await importWorkspaceBundle(target, bundle); expect(report).toEqual({ ok: true, damages: [] }); expect(await snapshotWorkspace(target)).toEqual(await snapshotWorkspace(source)); }); it("migrates legacy manifests and detects damaged workspaces", async () => { expect(migrateManifest({ schemaVersion: 0, projectId: "legacy", name: "Legacy", createdAt: NOW, updatedAt: NOW, modelPath: "legacy/model.json" })).toMatchObject({ schemaVersion: 1, projectId: "legacy", entrypoints: { model: "legacy/model.json" } }); const storage = new MemoryWorkspaceStorage(); await initializeWorkspace(storage, { projectId: "demo_cell", name: "Demo Cell", model: sampleOlpProject(), now: NOW }); const checksum = (await snapshotWorkspace(storage)).checksum; const model = await readProjectModel(storage); model.operations[0]!.pathId = "missing_path"; await writeProjectModel(storage, model, NOW); expect(await detectWorkspaceDamage(storage, checksum)).toMatchObject({ ok: false, damages: [ expect.objectContaining({ code: "WORKSPACE_MODEL_INVALID" }), expect.objectContaining({ code: "WORKSPACE_CHECKSUM_MISMATCH" }) ] }); }); it("rejects tampered bundles before import", async () => { const source = new MemoryWorkspaceStorage(); await initializeWorkspace(source, { projectId: "demo_cell", name: "Demo Cell", model: sampleOlpProject(), now: NOW }); const tampered = JSON.parse(await exportWorkspaceBundle(source)) as { files: Record; }; tampered.files["project.json"] = "{}"; const target = new MemoryWorkspaceStorage(); expect(await importWorkspaceBundle(target, JSON.stringify(tampered))).toMatchObject({ ok: false, damages: [expect.objectContaining({ code: "WORKSPACE_CHECKSUM_MISMATCH" })] }); expect(await target.list()).toEqual([]); }); });