From fe9ef2582d2dc8263dfa83fac598ae416ce9997d Mon Sep 17 00:00:00 2001 From: Fuwn Date: Tue, 3 Feb 2026 05:05:53 -0800 Subject: test(sdk): Add in-memory store tests --- packages/sdk/src/in-memory-project-store.test.ts | 490 +++++++++++++++++++++++ packages/sdk/src/in-memory-store.test.ts | 293 ++++++++++++++ 2 files changed, 783 insertions(+) create mode 100644 packages/sdk/src/in-memory-project-store.test.ts create mode 100644 packages/sdk/src/in-memory-store.test.ts (limited to 'packages') diff --git a/packages/sdk/src/in-memory-project-store.test.ts b/packages/sdk/src/in-memory-project-store.test.ts new file mode 100644 index 0000000..4bf485e --- /dev/null +++ b/packages/sdk/src/in-memory-project-store.test.ts @@ -0,0 +1,490 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { InMemoryProjectStore } from "./in-memory-project-store.js"; + +describe("InMemoryProjectStore", () => { + let store: InMemoryProjectStore; + + beforeEach(() => { + store = new InMemoryProjectStore(); + }); + + describe("create", () => { + it("creates a project and returns it with generated id", async () => { + const result = await store.create({ name: "Test Project" }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.id).toBeDefined(); + expect(result.value.name).toBe("Test Project"); + expect(result.value.description).toBeNull(); + expect(result.value.isGlobal).toBe(false); + expect(result.value.folders).toEqual([]); + expect(result.value.createdAt).toBeInstanceOf(Date); + expect(result.value.updatedAt).toBeInstanceOf(Date); + } + }); + + it("creates a project with optional fields", async () => { + const result = await store.create({ + name: "Test Project", + description: "A test project", + isGlobal: true, + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.description).toBe("A test project"); + expect(result.value.isGlobal).toBe(true); + } + }); + }); + + describe("get", () => { + it("returns a project by id", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.get(createResult.value.id); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value).toEqual(createResult.value); + } + }); + + it("returns failure when project does not exist", async () => { + const result = await store.get("non-existent-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("PROJECT_NOT_FOUND"); + expect(result.error.projectId).toBe("non-existent-id"); + } + }); + }); + + describe("update", () => { + it("updates a project and returns the updated version", async () => { + const createResult = await store.create({ name: "Original Name" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.update(createResult.value.id, { + name: "Updated Name", + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.name).toBe("Updated Name"); + expect(result.value.updatedAt.getTime()).toBeGreaterThanOrEqual( + createResult.value.updatedAt.getTime(), + ); + } + }); + + it("updates only specified fields", async () => { + const createResult = await store.create({ + name: "Test Project", + description: "Original description", + isGlobal: false, + }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.update(createResult.value.id, { + name: "Updated Name", + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.name).toBe("Updated Name"); + expect(result.value.description).toBe("Original description"); + expect(result.value.isGlobal).toBe(false); + } + }); + + it("allows setting description to null", async () => { + const createResult = await store.create({ + name: "Test Project", + description: "Original description", + }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.update(createResult.value.id, { + description: null, + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.description).toBeNull(); + } + }); + + it("returns failure when project does not exist", async () => { + const result = await store.update("non-existent-id", { + name: "Updated Name", + }); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("PROJECT_NOT_FOUND"); + expect(result.error.projectId).toBe("non-existent-id"); + } + }); + }); + + describe("delete", () => { + it("deletes a project", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const deleteResult = await store.delete(createResult.value.id); + + expect(deleteResult.success).toBe(true); + + const getResult = await store.get(createResult.value.id); + + expect(getResult.success).toBe(false); + }); + + it("returns failure when project does not exist", async () => { + const result = await store.delete("non-existent-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("PROJECT_NOT_FOUND"); + expect(result.error.projectId).toBe("non-existent-id"); + } + }); + }); + + describe("list", () => { + it("returns empty array when no projects exist", async () => { + const result = await store.list(); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value).toEqual([]); + } + }); + + it("returns all projects", async () => { + const createResult1 = await store.create({ name: "Project 1" }); + const createResult2 = await store.create({ name: "Project 2" }); + + if (!createResult1.success || !createResult2.success) { + throw new Error("Failed to create projects"); + } + + const result = await store.list(); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value).toHaveLength(2); + expect(result.value).toContainEqual(createResult1.value); + expect(result.value).toContainEqual(createResult2.value); + } + }); + }); + + describe("addFolder", () => { + it("adds a folder to a project", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.addFolder(createResult.value.id, { + name: "Test Folder", + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.id).toBeDefined(); + expect(result.value.name).toBe("Test Folder"); + expect(result.value.description).toBeNull(); + expect(result.value.projectId).toBe(createResult.value.id); + expect(result.value.createdAt).toBeInstanceOf(Date); + expect(result.value.updatedAt).toBeInstanceOf(Date); + } + }); + + it("adds a folder with description", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.addFolder(createResult.value.id, { + name: "Test Folder", + description: "A test folder", + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.description).toBe("A test folder"); + } + }); + + it("returns failure when project does not exist", async () => { + const result = await store.addFolder("non-existent-id", { + name: "Test Folder", + }); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("PROJECT_NOT_FOUND"); + expect(result.error.projectId).toBe("non-existent-id"); + } + }); + }); + + describe("updateFolder", () => { + it("updates a folder and returns the updated version", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const folderResult = await store.addFolder(createResult.value.id, { + name: "Original Name", + }); + + if (!folderResult.success) { + throw new Error("Failed to create folder"); + } + + const result = await store.updateFolder( + createResult.value.id, + folderResult.value.id, + { name: "Updated Name" }, + ); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.name).toBe("Updated Name"); + expect(result.value.updatedAt.getTime()).toBeGreaterThanOrEqual( + folderResult.value.updatedAt.getTime(), + ); + } + }); + + it("allows setting description to null", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const folderResult = await store.addFolder(createResult.value.id, { + name: "Test Folder", + description: "Original description", + }); + + if (!folderResult.success) { + throw new Error("Failed to create folder"); + } + + const result = await store.updateFolder( + createResult.value.id, + folderResult.value.id, + { description: null }, + ); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.description).toBeNull(); + } + }); + + it("returns failure when project does not exist", async () => { + const result = await store.updateFolder("non-existent-id", "folder-id", { + name: "Updated Name", + }); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("PROJECT_NOT_FOUND"); + } + }); + + it("returns failure when folder does not exist", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.updateFolder( + createResult.value.id, + "non-existent-folder-id", + { name: "Updated Name" }, + ); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("FOLDER_NOT_FOUND"); + + if (result.error.type === "FOLDER_NOT_FOUND") { + expect(result.error.folderId).toBe("non-existent-folder-id"); + } + } + }); + }); + + describe("removeFolder", () => { + it("removes a folder from a project", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const folderResult = await store.addFolder(createResult.value.id, { + name: "Test Folder", + }); + + if (!folderResult.success) { + throw new Error("Failed to create folder"); + } + + const removeResult = await store.removeFolder( + createResult.value.id, + folderResult.value.id, + ); + + expect(removeResult.success).toBe(true); + + const listResult = await store.listFolders(createResult.value.id); + + if (listResult.success) { + expect(listResult.value).toHaveLength(0); + } + }); + + it("returns failure when project does not exist", async () => { + const result = await store.removeFolder("non-existent-id", "folder-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("PROJECT_NOT_FOUND"); + } + }); + + it("returns failure when folder does not exist", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.removeFolder( + createResult.value.id, + "non-existent-folder-id", + ); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("FOLDER_NOT_FOUND"); + + if (result.error.type === "FOLDER_NOT_FOUND") { + expect(result.error.folderId).toBe("non-existent-folder-id"); + } + } + }); + }); + + describe("listFolders", () => { + it("returns empty array when project has no folders", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const result = await store.listFolders(createResult.value.id); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value).toEqual([]); + } + }); + + it("returns all folders for a project", async () => { + const createResult = await store.create({ name: "Test Project" }); + + if (!createResult.success) { + throw new Error("Failed to create project"); + } + + const folder1Result = await store.addFolder(createResult.value.id, { + name: "Folder 1", + }); + const folder2Result = await store.addFolder(createResult.value.id, { + name: "Folder 2", + }); + + if (!folder1Result.success || !folder2Result.success) { + throw new Error("Failed to create folders"); + } + + const result = await store.listFolders(createResult.value.id); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value).toHaveLength(2); + expect(result.value).toContainEqual(folder1Result.value); + expect(result.value).toContainEqual(folder2Result.value); + } + }); + + it("returns failure when project does not exist", async () => { + const result = await store.listFolders("non-existent-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("PROJECT_NOT_FOUND"); + expect(result.error.projectId).toBe("non-existent-id"); + } + }); + }); +}); diff --git a/packages/sdk/src/in-memory-store.test.ts b/packages/sdk/src/in-memory-store.test.ts new file mode 100644 index 0000000..e55eaf1 --- /dev/null +++ b/packages/sdk/src/in-memory-store.test.ts @@ -0,0 +1,293 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { InMemoryStore } from "./in-memory-store.js"; +import type { Tag } from "./types.js"; + +describe("InMemoryStore", () => { + let store: InMemoryStore; + + beforeEach(() => { + store = new InMemoryStore(); + }); + + describe("create", () => { + it("creates a memory and returns it with generated id", async () => { + const memory = await store.create({ + content: "Test memory content", + projectId: "project-1", + }); + + expect(memory.id).toBeDefined(); + expect(memory.content).toBe("Test memory content"); + expect(memory.projectId).toBe("project-1"); + expect(memory.folderId).toBeNull(); + expect(memory.tags).toEqual([]); + expect(memory.metadata).toEqual({}); + expect(memory.createdAt).toBeInstanceOf(Date); + expect(memory.updatedAt).toBeInstanceOf(Date); + }); + + it("creates a memory with optional fields", async () => { + const tags: Tag[] = [{ id: "tag-1", name: "important" }]; + const metadata = { source: "test" }; + const memory = await store.create({ + content: "Test memory content", + projectId: "project-1", + folderId: "folder-1", + tags, + metadata, + }); + + expect(memory.folderId).toBe("folder-1"); + expect(memory.tags).toEqual(tags); + expect(memory.metadata).toEqual(metadata); + }); + }); + + describe("read", () => { + it("returns a memory by id", async () => { + const created = await store.create({ + content: "Test memory content", + projectId: "project-1", + }); + const result = await store.read(created.id); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value).toEqual(created); + } + }); + + it("returns failure when memory does not exist", async () => { + const result = await store.read("non-existent-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("MEMORY_NOT_FOUND"); + expect(result.error.memoryId).toBe("non-existent-id"); + } + }); + }); + + describe("update", () => { + it("updates a memory and returns the updated version", async () => { + const created = await store.create({ + content: "Original content", + projectId: "project-1", + }); + const result = await store.update(created.id, { + content: "Updated content", + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.content).toBe("Updated content"); + expect(result.value.updatedAt.getTime()).toBeGreaterThanOrEqual( + created.updatedAt.getTime(), + ); + } + }); + + it("updates only specified fields", async () => { + const tags: Tag[] = [{ id: "tag-1", name: "important" }]; + const created = await store.create({ + content: "Original content", + projectId: "project-1", + folderId: "folder-1", + tags, + }); + const result = await store.update(created.id, { + content: "Updated content", + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.content).toBe("Updated content"); + expect(result.value.folderId).toBe("folder-1"); + expect(result.value.tags).toEqual(tags); + } + }); + + it("allows setting folderId to null", async () => { + const created = await store.create({ + content: "Test content", + projectId: "project-1", + folderId: "folder-1", + }); + const result = await store.update(created.id, { + folderId: null, + }); + + expect(result.success).toBe(true); + + if (result.success) { + expect(result.value.folderId).toBeNull(); + } + }); + + it("returns failure when memory does not exist", async () => { + const result = await store.update("non-existent-id", { + content: "Updated content", + }); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("MEMORY_NOT_FOUND"); + expect(result.error.memoryId).toBe("non-existent-id"); + } + }); + }); + + describe("delete", () => { + it("deletes a memory", async () => { + const created = await store.create({ + content: "Test content", + projectId: "project-1", + }); + const deleteResult = await store.delete(created.id); + + expect(deleteResult.success).toBe(true); + + const readResult = await store.read(created.id); + + expect(readResult.success).toBe(false); + }); + + it("returns failure when memory does not exist", async () => { + const result = await store.delete("non-existent-id"); + + expect(result.success).toBe(false); + + if (!result.success) { + expect(result.error.type).toBe("MEMORY_NOT_FOUND"); + expect(result.error.memoryId).toBe("non-existent-id"); + } + }); + }); + + describe("list", () => { + it("returns empty array when no memories exist", async () => { + const memories = await store.list(); + + expect(memories).toEqual([]); + }); + + it("returns all memories when no filter is provided", async () => { + const memory1 = await store.create({ + content: "Memory 1", + projectId: "project-1", + }); + const memory2 = await store.create({ + content: "Memory 2", + projectId: "project-2", + }); + const memories = await store.list(); + + expect(memories).toHaveLength(2); + expect(memories).toContainEqual(memory1); + expect(memories).toContainEqual(memory2); + }); + + it("filters memories by projectId", async () => { + const memory1 = await store.create({ + content: "Memory 1", + projectId: "project-1", + }); + + await store.create({ + content: "Memory 2", + projectId: "project-2", + }); + + const memories = await store.list({ projectId: "project-1" }); + + expect(memories).toHaveLength(1); + expect(memories[0]).toEqual(memory1); + }); + + it("filters memories by folderId", async () => { + const memory1 = await store.create({ + content: "Memory 1", + projectId: "project-1", + folderId: "folder-1", + }); + + await store.create({ + content: "Memory 2", + projectId: "project-1", + folderId: "folder-2", + }); + await store.create({ + content: "Memory 3", + projectId: "project-1", + }); + + const memories = await store.list({ folderId: "folder-1" }); + + expect(memories).toHaveLength(1); + expect(memories[0]).toEqual(memory1); + }); + + it("filters memories by tags", async () => { + const tag1: Tag = { id: "tag-1", name: "important" }; + const tag2: Tag = { id: "tag-2", name: "work" }; + const memory1 = await store.create({ + content: "Memory 1", + projectId: "project-1", + tags: [tag1, tag2], + }); + + await store.create({ + content: "Memory 2", + projectId: "project-1", + tags: [tag1], + }); + await store.create({ + content: "Memory 3", + projectId: "project-1", + tags: [], + }); + + const memories = await store.list({ tags: ["tag-1", "tag-2"] }); + + expect(memories).toHaveLength(1); + expect(memories[0]).toEqual(memory1); + }); + + it("filters memories by multiple criteria", async () => { + const tag: Tag = { id: "tag-1", name: "important" }; + const memory1 = await store.create({ + content: "Memory 1", + projectId: "project-1", + folderId: "folder-1", + tags: [tag], + }); + + await store.create({ + content: "Memory 2", + projectId: "project-1", + folderId: "folder-2", + tags: [tag], + }); + await store.create({ + content: "Memory 3", + projectId: "project-2", + folderId: "folder-1", + tags: [tag], + }); + + const memories = await store.list({ + projectId: "project-1", + folderId: "folder-1", + tags: ["tag-1"], + }); + + expect(memories).toHaveLength(1); + expect(memories[0]).toEqual(memory1); + }); + }); +}); -- cgit v1.2.3