@aigne/afs-testing 1.11.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["isValidator","isContainsMatcher","deepContains","isValidator"],"sources":["../src/assertions.ts","../src/suites/access-mode.ts","../src/suites/actions.ts","../src/suites/capabilities-operations.ts","../src/types.ts","../src/suites/deep-list.ts","../src/suites/delete-cases.ts","../src/suites/entry-fields.ts","../src/suites/error-types.ts","../src/suites/execute.ts","../src/suites/explain.ts","../src/suites/explain-existence.ts","../src/suites/list-options.ts","../src/suites/meta.ts","../src/suites/metadata-richness.ts","../src/suites/no-handler.ts","../src/suites/path-normalization.ts","../src/suites/read.ts","../src/suites/route-params.ts","../src/suites/search.ts","../src/suites/structure.ts","../src/suites/write-cases.ts","../src/runner.ts"],"sourcesContent":["import { expect } from \"bun:test\";\nimport type {\n AFSEntry,\n AFSListResult,\n AFSReadResult,\n AFSSearchResult,\n AFSStatResult,\n} from \"@aigne/afs\";\n\n/**\n * Validate that a result conforms to AFSListResult structure.\n */\nexport function validateListResult(result: unknown): asserts result is AFSListResult {\n expect(result).toBeDefined();\n expect(result).toHaveProperty(\"data\");\n expect(Array.isArray((result as AFSListResult).data)).toBe(true);\n\n for (const entry of (result as AFSListResult).data) {\n validateEntry(entry);\n }\n\n // total is optional\n if ((result as AFSListResult).total !== undefined) {\n expect(typeof (result as AFSListResult).total).toBe(\"number\");\n }\n}\n\n/**\n * Validate that an object conforms to AFSEntry structure.\n */\nexport function validateEntry(entry: unknown): asserts entry is AFSEntry {\n expect(entry).toBeDefined();\n expect(entry).toHaveProperty(\"id\");\n expect(entry).toHaveProperty(\"path\");\n expect(typeof (entry as AFSEntry).id).toBe(\"string\");\n expect(typeof (entry as AFSEntry).path).toBe(\"string\");\n\n // Optional fields type check\n const e = entry as AFSEntry;\n\n if (e.content !== undefined) {\n const isValidContent =\n typeof e.content === \"string\" || Buffer.isBuffer(e.content) || typeof e.content === \"object\";\n expect(isValidContent).toBe(true);\n }\n\n if (e.meta !== undefined && e.meta !== null) {\n expect(typeof e.meta).toBe(\"object\");\n }\n\n if (e.createdAt !== undefined) {\n expect(e.createdAt instanceof Date).toBe(true);\n }\n\n if (e.updatedAt !== undefined) {\n expect(e.updatedAt instanceof Date).toBe(true);\n }\n}\n\n/**\n * Validate that a result conforms to AFSReadResult structure.\n */\nexport function validateReadResult(result: unknown): asserts result is AFSReadResult {\n expect(result).toBeDefined();\n\n const r = result as AFSReadResult;\n if (r.data !== undefined) {\n validateEntry(r.data);\n }\n\n if (r.message !== undefined) {\n expect(typeof r.message).toBe(\"string\");\n }\n}\n\n/**\n * Validate that a result conforms to AFSSearchResult structure.\n */\nexport function validateSearchResult(result: unknown): asserts result is AFSSearchResult {\n expect(result).toBeDefined();\n expect(result).toHaveProperty(\"data\");\n expect(Array.isArray((result as AFSSearchResult).data)).toBe(true);\n\n for (const entry of (result as AFSSearchResult).data) {\n validateEntry(entry);\n }\n}\n\n/**\n * Validate that a result conforms to AFSStatResult structure.\n */\nexport function validateStatResult(result: unknown): asserts result is AFSStatResult {\n expect(result).toBeDefined();\n\n const r = result as AFSStatResult;\n if (r.data !== undefined) {\n expect(r.data).toHaveProperty(\"path\");\n expect(typeof r.data.path).toBe(\"string\");\n\n if (r.data.meta?.size !== undefined) {\n expect(typeof r.data.meta.size).toBe(\"number\");\n }\n if (r.data.meta?.childrenCount !== undefined) {\n expect(typeof r.data.meta.childrenCount).toBe(\"number\");\n }\n }\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { AFSReadonlyError } from \"@aigne/afs\";\nimport type { TestConfig } from \"../types.js\";\n\n/**\n * Run AccessMode test suite.\n * Tests that readonly providers reject write operations.\n */\nexport function runAccessModeTests(getProvider: () => AFSModule, _config: TestConfig): void {\n describe(\"access-mode\", () => {\n test(\"readonly: write should throw AFSReadonlyError\", async () => {\n const provider = getProvider();\n\n // Skip if provider is readwrite or doesn't have write\n if (provider.accessMode !== \"readonly\" || !provider.write) {\n return;\n }\n\n try {\n await provider.write(\"/test-readonly.txt\", { content: \"test\" });\n // Should not reach here\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSReadonlyError);\n expect((error as AFSReadonlyError).code).toBe(\"AFS_READONLY\");\n }\n });\n\n test(\"readonly: delete should throw AFSReadonlyError\", async () => {\n const provider = getProvider();\n\n if (provider.accessMode !== \"readonly\" || !provider.delete) {\n return;\n }\n\n try {\n await provider.delete(\"/test-readonly.txt\");\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSReadonlyError);\n expect((error as AFSReadonlyError).code).toBe(\"AFS_READONLY\");\n }\n });\n\n test(\"readonly: exec should throw AFSReadonlyError\", async () => {\n const provider = getProvider();\n\n if (provider.accessMode !== \"readonly\" || !provider.exec) {\n return;\n }\n\n try {\n await provider.exec(\"/test-action\", {}, {});\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSReadonlyError);\n expect((error as AFSReadonlyError).code).toBe(\"AFS_READONLY\");\n }\n });\n\n test(\"readonly: rename should throw AFSReadonlyError\", async () => {\n const provider = getProvider();\n\n if (provider.accessMode !== \"readonly\" || !provider.rename) {\n return;\n }\n\n try {\n await provider.rename(\"/old.txt\", \"/new.txt\");\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSReadonlyError);\n expect((error as AFSReadonlyError).code).toBe(\"AFS_READONLY\");\n }\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport type { ActionExpectedOutput, ActionTestCase, TestConfig } from \"../types.js\";\n\n/**\n * Check if expected output is a validator function.\n */\nfunction isValidator(expected: ActionExpectedOutput): expected is (\n result: {\n success: boolean;\n data?: Record<string, unknown>;\n error?: { code: string; message: string };\n },\n expect: typeof import(\"bun:test\").expect,\n) => void {\n return typeof expected === \"function\";\n}\n\n/**\n * Check if expected output is a contains matcher.\n */\nfunction isContainsMatcher(\n expected: ActionExpectedOutput,\n): expected is { contains: Record<string, unknown> } {\n return typeof expected === \"object\" && expected !== null && \"contains\" in expected;\n}\n\n/**\n * Check if expected output is a success-only matcher.\n */\nfunction isSuccessMatcher(expected: ActionExpectedOutput): expected is { success: boolean } {\n return (\n typeof expected === \"object\" &&\n expected !== null &&\n \"success\" in expected &&\n !(\"data\" in expected) &&\n !(\"contains\" in expected)\n );\n}\n\n/**\n * Check if expected output is a data matcher.\n */\nfunction isDataMatcher(\n expected: ActionExpectedOutput,\n): expected is { data: Record<string, unknown> } {\n return typeof expected === \"object\" && expected !== null && \"data\" in expected;\n}\n\n/**\n * Deep check if target contains all keys/values from subset.\n */\nfunction deepContains(target: unknown, subset: unknown): boolean {\n if (subset === null || subset === undefined) {\n return target === subset;\n }\n\n if (typeof subset !== \"object\") {\n return target === subset;\n }\n\n if (Array.isArray(subset)) {\n if (!Array.isArray(target)) return false;\n return subset.every((item, index) => deepContains(target[index], item));\n }\n\n if (typeof target !== \"object\" || target === null) {\n return false;\n }\n\n const targetObj = target as Record<string, unknown>;\n const subsetObj = subset as Record<string, unknown>;\n\n for (const key of Object.keys(subsetObj)) {\n if (!(key in targetObj)) return false;\n if (!deepContains(targetObj[key], subsetObj[key])) return false;\n }\n\n return true;\n}\n\n/**\n * Run action test suite.\n * Tests input/output behavior of actions on nodes.\n *\n * Actions are executed via exec() on .actions paths and return\n * AFSActionResult with success/data/error fields.\n */\nexport function runActionTests(\n getProvider: () => AFSModule,\n cases: ActionTestCase[],\n _config: TestConfig,\n): void {\n describe(\"actions\", () => {\n for (const testCase of cases) {\n test(`action ${testCase.path}: ${testCase.name}`, async () => {\n const provider = getProvider();\n\n if (!provider.exec) {\n // exec not supported, skip\n return;\n }\n\n if (testCase.shouldThrow) {\n // Expect execution to throw\n let threw = false;\n let errorMessage = \"\";\n\n try {\n await provider.exec(testCase.path, testCase.args as Record<string, any>, {});\n } catch (error) {\n threw = true;\n errorMessage = error instanceof Error ? error.message : String(error);\n }\n\n expect(threw).toBe(true);\n\n // Optionally match error message\n if (typeof testCase.shouldThrow === \"string\") {\n expect(errorMessage).toContain(testCase.shouldThrow);\n } else if (testCase.shouldThrow instanceof RegExp) {\n expect(errorMessage).toMatch(testCase.shouldThrow);\n }\n } else {\n // Expect successful execution\n const result = await provider.exec(\n testCase.path,\n testCase.args as Record<string, any>,\n {},\n );\n\n expect(result).toBeDefined();\n\n // AFSExecResult now extends AFSActionResult: { success, data?, error? }\n // Validate output if expected is specified\n if (testCase.expected !== undefined) {\n if (isValidator(testCase.expected)) {\n // Custom validator function - pass expect for assertions\n testCase.expected(result, expect);\n } else if (isSuccessMatcher(testCase.expected)) {\n // Just check success status\n expect(result.success).toBe(testCase.expected.success);\n } else if (isDataMatcher(testCase.expected)) {\n // Exact match on data field\n expect(result.success).toBe(true);\n expect(result.data).toEqual(testCase.expected.data);\n } else if (isContainsMatcher(testCase.expected)) {\n // Partial match with contains\n expect(result.success).toBe(true);\n const matches = deepContains(result.data, testCase.expected.contains);\n expect(matches).toBe(true);\n }\n }\n }\n });\n }\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport type { TestConfig, TestDataStructure } from \"../types.js\";\n\nconst OPERATION_KEYS: string[] = [\n \"read\",\n \"list\",\n \"write\",\n \"delete\",\n \"search\",\n \"exec\",\n \"stat\",\n \"explain\",\n];\n\n/**\n * Run capabilities operations validation suite.\n * Verifies that the provider's /.meta/.capabilities returns\n * a valid manifest with a complete operations declaration.\n */\nexport function runCapabilitiesOperationsTests(\n getProvider: () => AFSModule,\n _structure: TestDataStructure,\n _config: TestConfig,\n): void {\n describe(\"capabilities-operations\", () => {\n test(\"provider should return capabilities manifest via /.meta/.capabilities\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/.meta/.capabilities\");\n expect(result.data).toBeDefined();\n expect(result.data?.content).toBeDefined();\n });\n\n test(\"capabilities manifest should have operations field\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/.meta/.capabilities\");\n const manifest = result.data?.content as Record<string, unknown>;\n expect(manifest).toBeDefined();\n expect(manifest.operations).toBeDefined();\n expect(typeof manifest.operations).toBe(\"object\");\n });\n\n test(\"operations should declare all 8 operations as booleans\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/.meta/.capabilities\");\n const manifest = result.data?.content as Record<string, unknown>;\n const operations = manifest?.operations as Record<string, unknown>;\n if (!operations) return;\n\n for (const key of OPERATION_KEYS) {\n expect(operations[key]).toBeDefined();\n expect(typeof operations[key]).toBe(\"boolean\");\n }\n });\n\n test(\"operations should not have missing operation declarations\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/.meta/.capabilities\");\n const manifest = result.data?.content as Record<string, unknown>;\n const operations = manifest?.operations as Record<string, unknown>;\n if (!operations) return;\n\n const missing = OPERATION_KEYS.filter((key) => !(key in operations));\n expect(missing).toEqual([]);\n });\n\n test(\"extra fields in operations should be ignored (forward-compatible)\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/.meta/.capabilities\");\n const manifest = result.data?.content as Record<string, unknown>;\n const operations = manifest?.operations as Record<string, unknown>;\n if (!operations) return;\n\n // Just verify the 8 required fields exist - extra fields are fine\n for (const key of OPERATION_KEYS) {\n expect(key in operations).toBe(true);\n }\n });\n });\n}\n","import type { AFSModule } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\n\n/**\n * Expected action declaration for a test node.\n * Used to verify that actions are correctly exposed on nodes.\n */\nexport interface TestActionDeclaration {\n /** Action name */\n name: string;\n /** Optional description to verify */\n description?: string;\n}\n\n/**\n * A node in the test tree structure.\n * - If `children` is defined and non-empty, it's a directory\n * - If `content` is defined, it's a file\n * - Root node has name \"\" (empty string)\n */\nexport interface TestTreeNode {\n /** Node name (not full path). Root node uses empty string. */\n name: string;\n\n /** For files: expected content (optional, for read verification) */\n content?: string;\n\n /** For directories: child nodes. Presence with length > 0 indicates directory. */\n children?: TestTreeNode[];\n\n /** Expected meta for this node */\n meta?: Record<string, unknown>;\n\n /**\n * Expected actions for this node.\n * If specified, the framework will verify these actions exist via list(.actions).\n */\n actions?: TestActionDeclaration[];\n}\n\n/**\n * Describes the test data structure using a tree.\n */\nexport interface TestDataStructure {\n /**\n * Root of the tree structure representing \"/\".\n * All paths are derived from traversing this tree.\n * The framework validates that provider data matches this tree.\n */\n root: TestTreeNode;\n}\n\n// ============ Tree Helper Types ============\n\n/**\n * A flattened node with its computed path.\n * Used internally for iterating over the tree.\n */\nexport interface FlattenedNode {\n /** Full path from root (e.g., \"/docs/readme.md\") */\n path: string;\n\n /** The tree node */\n node: TestTreeNode;\n\n /** Depth from root (root = 0) */\n depth: number;\n}\n\n// ============ Tree Helper Functions ============\n\n/**\n * Check if a tree node represents a directory (has children).\n */\nexport function isDirectory(node: TestTreeNode): boolean {\n return node.children !== undefined && node.children.length > 0;\n}\n\n/**\n * Check if a tree node represents a file (has content or is a leaf without children).\n */\nexport function isFile(node: TestTreeNode): boolean {\n return node.content !== undefined || !isDirectory(node);\n}\n\n/**\n * Compute the full path for a node given its parent path.\n */\nexport function computePath(parentPath: string, nodeName: string): string {\n if (parentPath === \"/\" && nodeName === \"\") return \"/\";\n return joinURL(parentPath, nodeName);\n}\n\n/**\n * Flatten a tree into an array of nodes with their paths.\n * Traverses in BFS order.\n */\nexport function flattenTree(root: TestTreeNode): FlattenedNode[] {\n const result: FlattenedNode[] = [];\n const queue: Array<{ node: TestTreeNode; path: string; depth: number }> = [\n { node: root, path: \"/\", depth: 0 },\n ];\n\n while (queue.length > 0) {\n const { node, path, depth } = queue.shift()!;\n result.push({ path, node, depth });\n\n if (node.children) {\n for (const child of node.children) {\n const childPath = computePath(path, child.name);\n queue.push({ node: child, path: childPath, depth: depth + 1 });\n }\n }\n }\n\n return result;\n}\n\n/**\n * Find a node in the tree by path.\n */\nexport function findNode(root: TestTreeNode, targetPath: string): TestTreeNode | undefined {\n if (targetPath === \"/\") return root;\n\n const segments = targetPath.split(\"/\").filter(Boolean);\n let current: TestTreeNode | undefined = root;\n\n for (const segment of segments) {\n if (!current?.children) return undefined;\n current = current.children.find((c) => c.name === segment);\n if (!current) return undefined;\n }\n\n return current;\n}\n\n/**\n * Find the first file node in the tree (excluding root).\n */\nexport function findFirstFile(root: TestTreeNode): FlattenedNode | undefined {\n const flattened = flattenTree(root);\n return flattened.find((n) => n.path !== \"/\" && isFile(n.node) && !isDirectory(n.node));\n}\n\n/**\n * Find the first directory node in the tree (excluding root).\n */\nexport function findFirstDirectory(root: TestTreeNode): FlattenedNode | undefined {\n const flattened = flattenTree(root);\n return flattened.find((n) => n.path !== \"/\" && isDirectory(n.node));\n}\n\n/**\n * Find a nested directory (depth >= 2) in the tree.\n */\nexport function findNestedDirectory(root: TestTreeNode): FlattenedNode | undefined {\n const flattened = flattenTree(root);\n return flattened.find((n) => isDirectory(n.node) && n.depth >= 2);\n}\n\n/**\n * Get all file nodes from the tree.\n */\nexport function getAllFiles(root: TestTreeNode): FlattenedNode[] {\n return flattenTree(root).filter((n) => isFile(n.node) && !isDirectory(n.node));\n}\n\n/**\n * Get all directory nodes from the tree.\n */\nexport function getAllDirectories(root: TestTreeNode): FlattenedNode[] {\n return flattenTree(root).filter((n) => isDirectory(n.node));\n}\n\n/**\n * Configuration options for test behavior.\n */\nexport interface TestConfig {\n /** Custom timeout for slow providers (ms) */\n timeout?: number;\n}\n\n// ============ Execute test types ============\n\n/**\n * Validator function for execute test output.\n * Use expect() assertions inside to validate the output.\n * @example\n * ```typescript\n * (output, expect) => {\n * expect(output.content).toBeDefined();\n * expect(output.content[0].text).toContain(\"hello\");\n * }\n * ```\n */\nexport type ExecuteOutputValidator = (\n output: Record<string, unknown>,\n expect: typeof import(\"bun:test\").expect,\n) => void;\n\n/**\n * Expected output specification for execute tests.\n * Can be:\n * - An exact object to match (deep equality)\n * - A validator function that uses expect() assertions\n * - An object with `contains` for partial matching\n */\nexport type ExecuteExpectedOutput =\n | Record<string, unknown>\n | ExecuteOutputValidator\n | { contains: Record<string, unknown> };\n\n/**\n * A single execute test case.\n */\nexport interface ExecuteTestCase {\n /** Test case name/description */\n name: string;\n\n /** Path to execute (e.g., \"/tools/echo\") */\n path: string;\n\n /** Input arguments for execution */\n args: Record<string, unknown>;\n\n /**\n * Expected output validation.\n * - Object: exact deep equality match\n * - Function: custom validator\n * - { contains: ... }: partial match (output should contain these keys/values)\n */\n expected?: ExecuteExpectedOutput;\n\n /**\n * If true, the execution is expected to throw an error.\n * Can also be a string/regex to match the error message.\n */\n shouldThrow?: boolean | string | RegExp;\n}\n\n// ============ Write test types ============\n\n/**\n * Validator function for write test result.\n * Uses a more flexible type to accommodate AFSWriteResult structure.\n */\nexport type WriteOutputValidator = (\n result: { data?: { path: string; content?: unknown; meta?: Record<string, unknown> | null } },\n expect: typeof import(\"bun:test\").expect,\n) => void;\n\n/**\n * Expected output specification for write tests.\n */\nexport type WriteExpectedOutput =\n | { content: unknown }\n | { contentContains: string }\n | { meta: Record<string, unknown> }\n | WriteOutputValidator;\n\n/**\n * A single write test case.\n * Tests write operations including content and meta writes.\n */\nexport interface WriteTestCase {\n /** Test case name/description */\n name: string;\n\n /**\n * Path to write to.\n * - Can be an existing path from structure (tests overwrite)\n * - Can be a new path (tests creation)\n * - Use payload.meta for meta-only writes (.meta paths are read-only)\n */\n path: string;\n\n /**\n * Payload to write.\n * At least one of content or meta should be provided.\n */\n payload: {\n content?: string | Record<string, unknown>;\n meta?: Record<string, unknown>;\n };\n\n /**\n * Expected output validation.\n * - { content: ... }: verify written content matches\n * - { contentContains: ... }: verify content contains string\n * - { meta: ... }: verify meta matches\n * - Function: custom validator with expect()\n */\n expected?: WriteExpectedOutput;\n\n /**\n * If true, the write is expected to throw an error.\n * Can also be a string/regex to match the error message.\n */\n shouldThrow?: boolean | string | RegExp;\n}\n\n// ============ Delete test types ============\n\n/**\n * A single delete test case.\n * Tests delete operations on paths from the structure.\n */\nexport interface DeleteTestCase {\n /** Test case name/description */\n name: string;\n\n /**\n * Path to delete.\n * Should typically be a path that exists in the structure.\n */\n path: string;\n\n /**\n * If true, the delete is expected to throw an error.\n * Can also be a string/regex to match the error message.\n */\n shouldThrow?: boolean | string | RegExp;\n\n /**\n * If true, verify the path no longer exists after deletion.\n * Uses list() or read() to confirm deletion.\n * @default true\n */\n verifyDeleted?: boolean;\n}\n\n// ============ Action test types ============\n\n/**\n * Validator function for action test output.\n * Use expect() assertions inside to validate the output.\n * @example\n * ```typescript\n * (result, expect) => {\n * expect(result.success).toBe(true);\n * expect(result.data?.newId).toBeDefined();\n * }\n * ```\n */\nexport type ActionOutputValidator = (\n result: {\n success: boolean;\n data?: Record<string, unknown>;\n error?: { code: string; message: string };\n },\n expect: typeof import(\"bun:test\").expect,\n) => void;\n\n/**\n * Expected output specification for action tests.\n * Can be:\n * - An exact object to match (deep equality on data field)\n * - A validator function that uses expect() assertions\n * - An object with `contains` for partial matching\n * - An object with `success` to just check success/failure\n */\nexport type ActionExpectedOutput =\n | { success: boolean }\n | { data: Record<string, unknown> }\n | { contains: Record<string, unknown> }\n | ActionOutputValidator;\n\n/**\n * A single action test case.\n * Tests input/output behavior of actions on nodes.\n */\nexport interface ActionTestCase {\n /** Test case name/description */\n name: string;\n\n /**\n * Path to the action (e.g., \"/users/.actions/insert\" or \"/.actions/create-table\").\n * This is the full action path including the .actions segment.\n */\n path: string;\n\n /** Input arguments for the action */\n args: Record<string, unknown>;\n\n /**\n * Expected output validation.\n * - { success: true/false }: just check success status\n * - { data: ... }: exact match on result.data\n * - { contains: ... }: partial match on result.data\n * - Function: custom validator\n */\n expected?: ActionExpectedOutput;\n\n /**\n * If true, the action execution is expected to throw an error.\n * Can also be a string/regex to match the error message.\n */\n shouldThrow?: boolean | string | RegExp;\n}\n\n/**\n * Fixture interface for provider conformance tests.\n * Providers implement this to define their test environment.\n */\nexport interface ProviderTestFixture<T extends AFSModule = AFSModule> {\n /** Human-readable name for test output */\n name: string;\n\n /** Create a fresh provider instance */\n createProvider: () => Promise<T> | T;\n\n /** Describe the test data structure that will be available */\n structure: TestDataStructure;\n\n /**\n * Execute test cases.\n * Tests input/output behavior of executable nodes (e.g., tools, prompts).\n */\n executeCases?: ExecuteTestCase[];\n\n /**\n * Action test cases.\n * Tests action execution on nodes (e.g., create-table, insert, delete).\n * Actions are executed via exec() on .actions paths.\n * These tests run LAST because they may modify the data structure.\n */\n actionCases?: ActionTestCase[];\n\n /**\n * Write test cases.\n * Tests write operations including content and meta writes.\n * These tests run LAST because they may modify the data structure.\n */\n writeCases?: WriteTestCase[];\n\n /**\n * Delete test cases.\n * Tests delete operations on paths from the structure.\n * These tests run LAST because they modify the data structure.\n */\n deleteCases?: DeleteTestCase[];\n\n /** Optional lifecycle hooks */\n beforeAll?: () => Promise<void> | void;\n afterAll?: () => Promise<void> | void;\n beforeEach?: () => Promise<void> | void;\n afterEach?: () => Promise<void> | void;\n\n /** Optional test configuration */\n config?: TestConfig;\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { validateListResult } from \"../assertions.js\";\nimport {\n findNestedDirectory,\n flattenTree,\n isDirectory,\n type TestConfig,\n type TestDataStructure,\n} from \"../types.js\";\n\n/**\n * Run deep list traversal test suite.\n * Tests BFS depth expansion and pattern matching:\n * - maxDepth > 1 traversal\n * - Pattern filtering with glob\n * - Total count semantics\n *\n * IMPORTANT: list() only returns children, never includes the requested path itself.\n * - maxDepth=0: returns [] (no children at depth 0)\n * - maxDepth=1 or undefined: returns direct children only\n * - maxDepth=N (N>1): returns children + all descendants up to N-1 levels deep\n */\nexport function runDeepListTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n config: TestConfig,\n): void {\n const root = structure.root;\n const allNodes = flattenTree(root);\n const nestedDir = findNestedDirectory(root);\n\n // Count total nodes and directories in tree (excluding root)\n const _totalNodes = allNodes.length;\n const _directories = allNodes.filter((n) => isDirectory(n.node));\n const maxDepth = Math.max(...allNodes.map((n) => n.depth));\n\n // Test options with timeout from config\n const testOpts = config.timeout ? { timeout: config.timeout } : undefined;\n\n describe(\"deep-list\", () => {\n describe(\"depth traversal\", () => {\n test(\n \"maxDepth=0: should return empty array\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 0 });\n validateListResult(result);\n\n // maxDepth=0 returns empty array (no children levels to expand)\n expect(result.data.length).toBe(0);\n },\n testOpts,\n );\n\n test(\n \"maxDepth=1: should return only direct children (not self)\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n validateListResult(result);\n\n const rootChildCount = root.children?.length ?? 0;\n\n // Should return exactly the direct children count\n expect(result.data.length).toBe(rootChildCount);\n\n // Should NOT include the root path itself\n expect(result.data.some((e) => e.path === \"/\")).toBe(false);\n\n // All entries should be direct children (depth 1)\n for (const entry of result.data) {\n const depth = entry.path.split(\"/\").filter(Boolean).length;\n expect(depth).toBe(1);\n }\n },\n testOpts,\n );\n\n if (maxDepth >= 2) {\n test(\n \"maxDepth=2: should include children and grandchildren (not self)\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const depth1Result = await provider.list(\"/\", { maxDepth: 1 });\n const depth2Result = await provider.list(\"/\", { maxDepth: 2 });\n validateListResult(depth2Result);\n\n // depth=2 should have at least as many entries as depth=1\n expect(depth2Result.data.length).toBeGreaterThanOrEqual(depth1Result.data.length);\n\n // If there are nested directories with children, depth=2 should have more\n if (nestedDir) {\n expect(depth2Result.data.length).toBeGreaterThan(depth1Result.data.length);\n }\n\n // Should NOT include root path\n expect(depth2Result.data.some((e) => e.path === \"/\")).toBe(false);\n\n // All entries should be at depth 1 or 2\n for (const entry of depth2Result.data) {\n const depth = entry.path.split(\"/\").filter(Boolean).length;\n expect(depth).toBeGreaterThanOrEqual(1);\n expect(depth).toBeLessThanOrEqual(2);\n }\n },\n testOpts,\n );\n\n test(\n \"maxDepth=3: should traverse three levels (not including self)\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const depth2Result = await provider.list(\"/\", { maxDepth: 2 });\n const depth3Result = await provider.list(\"/\", { maxDepth: 3 });\n validateListResult(depth3Result);\n\n // Should have at least as many as depth=2\n expect(depth3Result.data.length).toBeGreaterThanOrEqual(depth2Result.data.length);\n\n // Should NOT include root path\n expect(depth3Result.data.some((e) => e.path === \"/\")).toBe(false);\n },\n testOpts,\n );\n }\n\n test(\n \"large maxDepth: should handle gracefully (not include self)\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // Request very deep traversal\n const result = await provider.list(\"/\", { maxDepth: 100 });\n validateListResult(result);\n\n const rootChildCount = root.children?.length ?? 0;\n\n // If root has children, should return at least that many\n // If root has no children, should return empty array\n if (rootChildCount > 0) {\n expect(result.data.length).toBeGreaterThanOrEqual(rootChildCount);\n } else {\n expect(result.data.length).toBe(0);\n }\n\n // Should NOT include root path\n expect(result.data.some((e) => e.path === \"/\")).toBe(false);\n },\n testOpts,\n );\n\n if (nestedDir) {\n test(\n \"depth from subdirectory: should traverse relative to path\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // Get parent of nested dir\n const parentPath = nestedDir.path.split(\"/\").slice(0, -1).join(\"/\") || \"/\";\n\n const result = await provider.list(parentPath, { maxDepth: 2 });\n validateListResult(result);\n\n // Should include the nested directory\n expect(result.data.some((e) => e.path === nestedDir.path)).toBe(true);\n },\n testOpts,\n );\n }\n });\n\n describe(\"pattern filtering\", () => {\n test(\n \"pattern *: should match all at current level\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const rootChildCount = root.children?.length ?? 0;\n\n try {\n const result = await provider.list(\"/\", { pattern: \"*\", maxDepth: 1 });\n validateListResult(result);\n // Should have entries if root has children\n if (rootChildCount > 0) {\n expect(result.data.length).toBeGreaterThanOrEqual(1);\n }\n // Should NOT include root path\n expect(result.data.some((e) => e.path === \"/\")).toBe(false);\n } catch {\n // Pattern not supported by this provider\n }\n },\n testOpts,\n );\n\n test(\n \"pattern *.md: should filter by extension\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // Find if there are any .md files in structure\n const _mdFiles = allNodes.filter((n) => n.path.endsWith(\".md\"));\n\n try {\n const result = await provider.list(\"/\", { pattern: \"*.md\", maxDepth: 10 });\n validateListResult(result);\n\n // All results should match *.md pattern (or be directories containing .md files)\n // And should NOT include root\n for (const entry of result.data) {\n // Either ends with .md or has children (directory)\n const isMatch = entry.path.endsWith(\".md\") || entry.meta?.childrenCount !== undefined;\n expect(isMatch).toBe(true);\n // Root should never be included\n expect(entry.path).not.toBe(\"/\");\n }\n } catch {\n // Pattern not supported\n }\n },\n testOpts,\n );\n\n test(\n \"pattern with no matches: should return empty or just directories\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n try {\n const result = await provider.list(\"/\", {\n pattern: \"*.nonexistentextension12345\",\n maxDepth: 10,\n });\n validateListResult(result);\n // Should have few or no results\n } catch {\n // Pattern not supported\n }\n },\n testOpts,\n );\n });\n\n describe(\"limit and total\", () => {\n test(\n \"limit with deep traversal: should respect limit\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 10, limit: 3 });\n validateListResult(result);\n\n expect(result.data.length).toBeLessThanOrEqual(3);\n },\n testOpts,\n );\n\n test(\n \"total: should indicate complete count if available\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n validateListResult(result);\n\n // total may or may not be present\n // If present, should be >= data.length\n if (result.total !== undefined) {\n expect(result.total).toBeGreaterThanOrEqual(result.data.length);\n }\n },\n testOpts,\n );\n\n test(\n \"small limit: should still work\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { limit: 1 });\n validateListResult(result);\n\n expect(result.data.length).toBeLessThanOrEqual(1);\n },\n testOpts,\n );\n });\n\n describe(\"BFS order\", () => {\n test(\n \"entries should be in breadth-first order (no root included)\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 10 });\n validateListResult(result);\n\n // Verify BFS order: entries at depth N should come before depth N+1\n // Root (depth 0) should never be in results\n for (const entry of result.data) {\n const depth = entry.path.split(\"/\").filter(Boolean).length;\n // All entries should have depth >= 1 (children or deeper)\n expect(depth).toBeGreaterThanOrEqual(1);\n // Root should never be included\n expect(entry.path).not.toBe(\"/\");\n }\n },\n testOpts,\n );\n });\n\n describe(\"default maxDepth behavior\", () => {\n test(\n \"maxDepth=undefined defaults to 1 (direct children only)\",\n async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const undefinedResult = await provider.list(\"/\");\n const depth1Result = await provider.list(\"/\", { maxDepth: 1 });\n validateListResult(undefinedResult);\n\n // Both should return the same results\n expect(undefinedResult.data.length).toBe(depth1Result.data.length);\n\n // Should NOT include root\n expect(undefinedResult.data.some((e) => e.path === \"/\")).toBe(false);\n },\n testOpts,\n );\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport type { DeleteTestCase, TestConfig } from \"../types.js\";\n\n/**\n * Run delete case tests.\n * Tests delete operations based on fixture-defined cases.\n * These tests run LAST because they modify the data structure.\n */\nexport function runDeleteCaseTests(\n getProvider: () => AFSModule,\n cases: DeleteTestCase[],\n _config: TestConfig,\n): void {\n describe(\"delete-cases\", () => {\n for (const testCase of cases) {\n test(`delete ${testCase.path}: ${testCase.name}`, async () => {\n const provider = getProvider();\n\n if (!provider.delete) {\n // delete not supported, skip\n return;\n }\n\n if (testCase.shouldThrow) {\n // Expect delete to throw\n let threw = false;\n let errorMessage = \"\";\n\n try {\n await provider.delete(testCase.path, {});\n } catch (error) {\n threw = true;\n errorMessage = error instanceof Error ? error.message : String(error);\n }\n\n expect(threw).toBe(true);\n\n // Optionally match error message\n if (typeof testCase.shouldThrow === \"string\") {\n expect(errorMessage).toContain(testCase.shouldThrow);\n } else if (testCase.shouldThrow instanceof RegExp) {\n expect(errorMessage).toMatch(testCase.shouldThrow);\n }\n } else {\n // Expect successful delete\n const result = await provider.delete(testCase.path, {});\n\n expect(result).toBeDefined();\n\n // Verify deletion if verifyDeleted is true (default)\n const shouldVerify = testCase.verifyDeleted !== false;\n if (shouldVerify && provider.list) {\n // Try to access the deleted path - should throw or return empty\n let deleted = false;\n try {\n const listResult = await provider.list(testCase.path, {});\n // If list succeeds but returns nothing, consider it deleted\n deleted = !listResult.data || listResult.data.length === 0;\n } catch {\n // Path not found = successfully deleted\n deleted = true;\n }\n\n expect(deleted).toBe(true);\n }\n }\n });\n }\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\nimport {\n findFirstDirectory,\n findFirstFile,\n type TestConfig,\n type TestDataStructure,\n} from \"../types.js\";\n\n/**\n * Run entry fields validation test suite.\n * Tests that entries have required fields with correct types.\n */\nexport function runEntryFieldsTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n const fileNode = findFirstFile(root);\n const dirNode = findFirstDirectory(root);\n\n describe(\"entry-fields\", () => {\n describe(\"required fields\", () => {\n test(\"read: entry should have id field\", async () => {\n const provider = getProvider();\n if (!provider.read || !fileNode) return;\n\n const result = await provider.read(fileNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.id).toBeDefined();\n expect(typeof result.data?.id).toBe(\"string\");\n });\n\n test(\"read: entry should have path field\", async () => {\n const provider = getProvider();\n if (!provider.read || !fileNode) return;\n\n const result = await provider.read(fileNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBeDefined();\n expect(typeof result.data?.path).toBe(\"string\");\n expect(result.data?.path.startsWith(\"/\")).toBe(true);\n });\n\n test(\"list: entries should have id and path\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n expect(result.data).toBeDefined();\n\n for (const entry of result.data) {\n expect(entry.id).toBeDefined();\n expect(typeof entry.id).toBe(\"string\");\n expect(entry.path).toBeDefined();\n expect(typeof entry.path).toBe(\"string\");\n }\n });\n });\n\n describe(\"metadata fields\", () => {\n if (dirNode) {\n test(\"directory: should have childrenCount in metadata\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(dirNode.path);\n expect(result.data).toBeDefined();\n\n // childrenCount may be in metadata\n if (result.data?.meta?.childrenCount !== undefined) {\n expect(typeof result.data.meta.childrenCount).toBe(\"number\");\n expect(result.data.meta.childrenCount).toBeGreaterThanOrEqual(0);\n }\n });\n }\n\n test(\"meta read: should return metadata object\", async () => {\n const provider = getProvider();\n if (!provider.read || !fileNode) return;\n\n const metaPath = joinURL(fileNode.path, \".meta\");\n const result = await provider.read(metaPath);\n\n expect(result.data).toBeDefined();\n expect(result.data?.meta).toBeDefined();\n expect(typeof result.data?.meta).toBe(\"object\");\n });\n });\n\n describe(\"optional fields\", () => {\n if (fileNode) {\n test(\"file: content field should be present\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(fileNode.path);\n expect(result.data).toBeDefined();\n // Content should be defined (can be any type)\n expect(\"content\" in (result.data || {})).toBe(true);\n });\n }\n\n test(\"entry: dates should be Date objects if present\", async () => {\n const provider = getProvider();\n if (!provider.read || !fileNode) return;\n\n const result = await provider.read(fileNode.path);\n expect(result.data).toBeDefined();\n\n if (result.data?.createdAt !== undefined) {\n expect(result.data.createdAt).toBeInstanceOf(Date);\n }\n\n if (result.data?.updatedAt !== undefined) {\n expect(result.data.updatedAt).toBeInstanceOf(Date);\n }\n });\n });\n\n describe(\"stat fields\", () => {\n test(\"stat: should return path field\", async () => {\n const provider = getProvider();\n if (!provider.stat || !fileNode) return;\n\n const result = await provider.stat(fileNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBeDefined();\n expect(result.data?.path).toBe(fileNode.path);\n });\n\n if (dirNode) {\n test(\"stat directory: childrenCount should be number if present\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const result = await provider.stat(dirNode.path);\n expect(result.data).toBeDefined();\n\n if (result.data?.meta?.childrenCount !== undefined) {\n expect(typeof result.data.meta.childrenCount).toBe(\"number\");\n }\n });\n }\n\n if (fileNode) {\n test(\"stat file: size should be number if present\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const result = await provider.stat(fileNode.path);\n expect(result.data).toBeDefined();\n\n if (result.data?.meta?.size !== undefined) {\n expect(typeof result.data.meta.size).toBe(\"number\");\n expect(result.data.meta.size).toBeGreaterThanOrEqual(0);\n }\n });\n }\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { AFSNotFoundError } from \"@aigne/afs\";\nimport type { TestConfig } from \"../types.js\";\n\n/**\n * Run error types test suite.\n * Tests that errors are thrown with correct types and properties.\n */\nexport function runErrorTypesTests(getProvider: () => AFSModule, _config: TestConfig): void {\n describe(\"error-types\", () => {\n describe(\"AFSNotFoundError\", () => {\n test(\"list not-found: should throw AFSNotFoundError with path\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const nonExistentPath = \"/non-existent-path-for-error-test-12345\";\n\n try {\n await provider.list(nonExistentPath);\n // Should not reach here\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n expect((error as AFSNotFoundError).path).toBe(nonExistentPath);\n expect((error as AFSNotFoundError).code).toBe(\"AFS_NOT_FOUND\");\n expect((error as AFSNotFoundError).name).toBe(\"AFSNotFoundError\");\n }\n });\n\n test(\"read not-found: should throw AFSNotFoundError with path\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const nonExistentPath = \"/non-existent-file-for-error-test-12345.txt\";\n\n try {\n await provider.read(nonExistentPath);\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n expect((error as AFSNotFoundError).path).toBe(nonExistentPath);\n expect((error as AFSNotFoundError).code).toBe(\"AFS_NOT_FOUND\");\n }\n });\n\n test(\"stat not-found: should throw AFSNotFoundError with path\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const nonExistentPath = \"/non-existent-stat-path-12345\";\n\n try {\n await provider.stat(nonExistentPath);\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n expect((error as AFSNotFoundError).path).toBe(nonExistentPath);\n expect((error as AFSNotFoundError).code).toBe(\"AFS_NOT_FOUND\");\n }\n });\n\n test(\"meta not-found: should throw AFSNotFoundError\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const nonExistentPath = \"/non-existent-meta-path-12345/.meta\";\n\n try {\n await provider.read(nonExistentPath);\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n expect((error as AFSNotFoundError).code).toBe(\"AFS_NOT_FOUND\");\n }\n });\n });\n\n describe(\"error message\", () => {\n test(\"not-found error should have descriptive message\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const nonExistentPath = \"/test-error-message-12345.txt\";\n\n try {\n await provider.read(nonExistentPath);\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(Error);\n expect((error as Error).message).toBeDefined();\n expect((error as Error).message.length).toBeGreaterThan(0);\n }\n });\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport type { ExecuteExpectedOutput, ExecuteTestCase, TestConfig } from \"../types.js\";\n\n/**\n * Check if expected output is a validator function.\n */\nfunction isValidator(\n expected: ExecuteExpectedOutput,\n): expected is (output: Record<string, unknown>, expect: typeof import(\"bun:test\").expect) => void {\n return typeof expected === \"function\";\n}\n\n/**\n * Check if expected output is a contains matcher.\n */\nfunction isContainsMatcher(\n expected: ExecuteExpectedOutput,\n): expected is { contains: Record<string, unknown> } {\n return typeof expected === \"object\" && expected !== null && \"contains\" in expected;\n}\n\n/**\n * Deep check if target contains all keys/values from subset.\n */\nfunction deepContains(target: unknown, subset: unknown): boolean {\n if (subset === null || subset === undefined) {\n return target === subset;\n }\n\n if (typeof subset !== \"object\") {\n return target === subset;\n }\n\n if (Array.isArray(subset)) {\n if (!Array.isArray(target)) return false;\n return subset.every((item, index) => deepContains(target[index], item));\n }\n\n if (typeof target !== \"object\" || target === null) {\n return false;\n }\n\n const targetObj = target as Record<string, unknown>;\n const subsetObj = subset as Record<string, unknown>;\n\n for (const key of Object.keys(subsetObj)) {\n if (!(key in targetObj)) return false;\n if (!deepContains(targetObj[key], subsetObj[key])) return false;\n }\n\n return true;\n}\n\n/**\n * Run execute test suite.\n * Tests input/output behavior of executable nodes.\n */\nexport function runExecuteTests(\n getProvider: () => AFSModule,\n cases: ExecuteTestCase[],\n _config: TestConfig,\n): void {\n describe(\"execute\", () => {\n for (const testCase of cases) {\n test(`exec ${testCase.path}: ${testCase.name}`, async () => {\n const provider = getProvider();\n\n if (!provider.exec) {\n // exec not supported, skip\n return;\n }\n\n if (testCase.shouldThrow) {\n // Expect execution to throw\n let threw = false;\n let errorMessage = \"\";\n\n try {\n await provider.exec(testCase.path, testCase.args as Record<string, any>, {});\n } catch (error) {\n threw = true;\n errorMessage = error instanceof Error ? error.message : String(error);\n }\n\n expect(threw).toBe(true);\n\n // Optionally match error message\n if (typeof testCase.shouldThrow === \"string\") {\n expect(errorMessage).toContain(testCase.shouldThrow);\n } else if (testCase.shouldThrow instanceof RegExp) {\n expect(errorMessage).toMatch(testCase.shouldThrow);\n }\n } else {\n // Expect successful execution\n const result = await provider.exec(\n testCase.path,\n testCase.args as Record<string, any>,\n {},\n );\n\n expect(result).toBeDefined();\n expect(result.data).toBeDefined();\n\n // Validate output if expected is specified\n if (testCase.expected !== undefined) {\n if (isValidator(testCase.expected)) {\n // Custom validator function - pass expect for assertions\n testCase.expected(result.data ?? {}, expect);\n } else if (isContainsMatcher(testCase.expected)) {\n // Partial match with contains\n const matches = deepContains(result.data ?? {}, testCase.expected.contains);\n expect(matches).toBe(true);\n } else {\n // Exact deep equality match\n expect(result.data).toEqual(testCase.expected);\n }\n }\n }\n });\n }\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSExplainResult, AFSModule } from \"@aigne/afs\";\nimport { findFirstFile, type TestConfig, type TestDataStructure } from \"../types.js\";\n\n/**\n * Run explain operation test suite.\n * Tests the explain() method for getting human-readable descriptions.\n */\nexport function runExplainTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n const fileNode = findFirstFile(root);\n\n describe(\"explain\", () => {\n test(\"explain: method should exist or be undefined\", () => {\n const provider = getProvider();\n // explain is optional - should be either a function or undefined\n expect(provider.explain === undefined || typeof provider.explain === \"function\").toBe(true);\n });\n\n test(\"explain root: should return explanation if supported\", async () => {\n const provider = getProvider();\n if (!provider.explain) return;\n\n try {\n const result = (await provider.explain(\"/\")) as AFSExplainResult;\n expect(result).toBeDefined();\n // AFSExplainResult has format and content directly (not wrapped in data)\n if (result.content !== undefined) {\n expect(typeof result.content).toBe(\"string\");\n }\n if (result.format !== undefined) {\n expect(typeof result.format).toBe(\"string\");\n expect([\"markdown\", \"text\"]).toContain(result.format);\n }\n } catch (error) {\n // No explain handler is acceptable - should throw \"No explain handler\" error\n expect(error).toBeInstanceOf(Error);\n expect((error as Error).message).toContain(\"explain\");\n }\n });\n\n if (fileNode) {\n test(\"explain file: should return explanation for file path\", async () => {\n const provider = getProvider();\n if (!provider.explain) return;\n\n try {\n const result = (await provider.explain(fileNode.path)) as AFSExplainResult;\n expect(result).toBeDefined();\n // AFSExplainResult has format and content directly (not wrapped in data)\n expect(result.format).toBeDefined();\n expect(result.content).toBeDefined();\n } catch (error) {\n // No handler is acceptable\n expect(error).toBeInstanceOf(Error);\n }\n });\n }\n\n test(\"explain: no handler should throw descriptive error\", async () => {\n const provider = getProvider();\n if (!provider.explain) return;\n\n // Try to explain a path that likely has no handler\n const testPath = \"/test-explain-no-handler-12345\";\n\n try {\n await provider.explain(testPath);\n // If it doesn't throw, that's also acceptable (provider may have catch-all handler)\n } catch (error) {\n expect(error).toBeInstanceOf(Error);\n const message = (error as Error).message;\n // Should mention either \"explain\" or \"handler\" or the path\n expect(\n message.includes(\"explain\") || message.includes(\"handler\") || message.includes(testPath),\n ).toBe(true);\n }\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSExplainResult, AFSModule } from \"@aigne/afs\";\nimport type { TestConfig, TestDataStructure } from \"../types.js\";\n\n/**\n * Run explain existence validation suite.\n * Verifies that the provider implements an explain handler\n * and that it returns non-empty content for the root path.\n */\nexport function runExplainExistenceTests(\n getProvider: () => AFSModule,\n _structure: TestDataStructure,\n _config: TestConfig,\n): void {\n describe(\"explain-existence\", () => {\n test(\"provider should implement explain handler\", () => {\n const provider = getProvider();\n expect(provider.explain).toBeDefined();\n expect(typeof provider.explain).toBe(\"function\");\n });\n\n test(\"explain root should return non-empty result\", async () => {\n const provider = getProvider();\n if (!provider.explain) return;\n\n const result = (await provider.explain(\"/\")) as AFSExplainResult;\n expect(result).toBeDefined();\n expect(result.content).toBeDefined();\n expect(typeof result.content).toBe(\"string\");\n expect(result.content.length).toBeGreaterThan(0);\n });\n\n test(\"explain result should have format field\", async () => {\n const provider = getProvider();\n if (!provider.explain) return;\n\n const result = (await provider.explain(\"/\")) as AFSExplainResult;\n expect(result.format).toBeDefined();\n expect(typeof result.format).toBe(\"string\");\n expect([\"markdown\", \"text\"]).toContain(result.format);\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { validateListResult } from \"../assertions.js\";\nimport { findNestedDirectory, type TestConfig, type TestDataStructure } from \"../types.js\";\n\n/**\n * Run advanced list options test suite.\n * Tests list operations with various options.\n */\nexport function runListOptionsTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n\n // Find a nested directory for deep traversal tests\n const nestedDir = findNestedDirectory(root);\n\n describe(\"list-options\", () => {\n describe(\"maxDepth\", () => {\n test(\"maxDepth=2: should traverse two levels deep\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 2 });\n validateListResult(result);\n\n // Should have more entries than maxDepth=1\n const depth1Result = await provider.list(\"/\", { maxDepth: 1 });\n // If there are nested directories, depth 2 should have more entries\n if (nestedDir) {\n expect(result.data.length).toBeGreaterThanOrEqual(depth1Result.data.length);\n }\n });\n\n test(\"maxDepth=0: should return empty array\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 0 });\n validateListResult(result);\n\n // maxDepth=0 returns empty array (no children levels to expand)\n expect(result.data.length).toBe(0);\n });\n\n if (nestedDir) {\n test(\"maxDepth on subdirectory: should respect depth from that point\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(nestedDir.path, { maxDepth: 1 });\n validateListResult(result);\n\n // Should NOT include the directory itself - list() never includes self\n expect(result.data.some((e) => e.path === nestedDir.path)).toBe(false);\n });\n }\n });\n\n describe(\"limit\", () => {\n test(\"limit=1: should return at most 1 entry\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { limit: 1 });\n validateListResult(result);\n expect(result.data.length).toBeLessThanOrEqual(1);\n });\n\n test(\"limit larger than total: should return all entries\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { limit: 10000 });\n validateListResult(result);\n // Should work without error\n });\n });\n\n describe(\"offset\", () => {\n test(\"offset=0: should return from beginning\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { offset: 0 });\n validateListResult(result);\n });\n\n test(\"offset with limit: should be accepted without error\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // Note: Not all providers fully implement offset pagination.\n // This test verifies the options are accepted without error.\n const result = await provider.list(\"/\", { limit: 2, offset: 1 });\n validateListResult(result);\n // Just verify it returns a valid result - pagination behavior varies\n });\n });\n\n describe(\"pattern\", () => {\n test(\"pattern matching: should filter by glob pattern\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // This test depends on provider supporting pattern\n // Some providers may not support it\n try {\n const result = await provider.list(\"/\", { pattern: \"*\", maxDepth: 1 });\n validateListResult(result);\n } catch {\n // Pattern not supported, skip\n }\n });\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\nimport {\n findFirstDirectory,\n findFirstFile,\n flattenTree,\n isDirectory,\n type TestConfig,\n type TestDataStructure,\n} from \"../types.js\";\n\n/**\n * Run MetaOperations test suite.\n * Tests the .meta path suffix for reading and writing metadata.\n */\nexport function runMetaTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n const allNodes = flattenTree(root);\n\n // Find entries with pre-existing metadata\n const rootHasMeta = root.meta !== undefined;\n const fileWithMeta = allNodes.find(\n (n) => n.path !== \"/\" && !isDirectory(n.node) && n.node.meta !== undefined,\n );\n const subdirFileWithMeta = allNodes.find(\n (n) => n.depth >= 2 && !isDirectory(n.node) && n.node.meta !== undefined,\n );\n const dirWithMeta = allNodes.find(\n (n) => n.path !== \"/\" && isDirectory(n.node) && n.node.meta !== undefined,\n );\n const dirNode = findFirstDirectory(root);\n const fileNode = findFirstFile(root);\n\n // Find a file in subdirectory (depth >= 2)\n const subdirFileNode = allNodes.find(\n (n) => n.depth >= 2 && n.node.content !== undefined && !isDirectory(n.node),\n );\n\n describe(\"meta-read-existing\", () => {\n if (rootHasMeta) {\n test(\"meta-read-root-existing: should read pre-existing root metadata\", async () => {\n const provider = getProvider();\n if (!provider.read) {\n // read not supported, skip\n return;\n }\n\n const result = await provider.read(\"/.meta\");\n expect(result.data).toBeDefined();\n expect(result.data?.meta).toBeDefined();\n\n // Verify expected metadata values\n for (const [key, value] of Object.entries(root.meta!)) {\n expect(result.data?.meta?.[key]).toEqual(value);\n }\n });\n }\n\n if (fileWithMeta) {\n test(\"meta-read-file-existing: should read pre-existing file metadata\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(joinURL(fileWithMeta.path, \".meta\"));\n expect(result.data).toBeDefined();\n expect(result.data?.meta).toBeDefined();\n\n // Verify expected metadata values\n for (const [key, value] of Object.entries(fileWithMeta.node.meta!)) {\n expect(result.data?.meta?.[key]).toEqual(value);\n }\n });\n }\n\n if (dirWithMeta) {\n test(\"meta-read-directory-existing: should read pre-existing directory metadata\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(joinURL(dirWithMeta.path, \".meta\"));\n expect(result.data).toBeDefined();\n expect(result.data?.meta).toBeDefined();\n\n // Verify expected metadata values\n for (const [key, value] of Object.entries(dirWithMeta.node.meta!)) {\n expect(result.data?.meta?.[key]).toEqual(value);\n }\n });\n }\n\n if (subdirFileWithMeta) {\n test(\"meta-read-subdir-file-existing: should read pre-existing subdir file metadata\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(joinURL(subdirFileWithMeta.path, \".meta\"));\n expect(result.data).toBeDefined();\n expect(result.data?.meta).toBeDefined();\n\n // Verify expected metadata values\n for (const [key, value] of Object.entries(subdirFileWithMeta.node.meta!)) {\n expect(result.data?.meta?.[key]).toEqual(value);\n }\n });\n }\n });\n\n describe(\"meta-write-read\", () => {\n // Helper to check if provider supports meta writes via node path\n // New design: metadata is written via the node path with payload.meta, not via .meta path\n // Does round-trip verification: writes metadata, reads it back, verifies it was stored\n async function supportsMetaWrite(provider: AFSModule, nodePath: string): Promise<boolean> {\n if (!provider.write || !provider.read) return false;\n try {\n // Write test metadata via node path\n await provider.write(nodePath, { meta: { __afs_test_meta_support: true } });\n\n // Read back via .meta path to verify it was actually stored\n const metaPath = joinURL(nodePath, \".meta\");\n const result = await provider.read(metaPath);\n\n // Check if our test metadata is present\n const stored = result.data?.meta?.__afs_test_meta_support;\n return stored === true;\n } catch (e) {\n // \"No write handler\" means provider doesn't support meta writes\n // \"No valid columns\" means meta path was routed to a row update handler (provider doesn't support meta writes)\n if (\n e instanceof Error &&\n (e.message.includes(\"No write handler\") || e.message.includes(\"No valid columns\"))\n ) {\n return false;\n }\n // Other errors (e.g., path not found, read errors) mean metadata write isn't supported\n return false;\n }\n }\n\n // Test writing metadata to an existing file at root level\n if (fileNode) {\n test(\"meta-write-read-file-root: should write and read metadata for existing file\", async () => {\n const provider = getProvider();\n if (!provider.write || !provider.read) {\n // write or read not supported, skip\n return;\n }\n\n // Use existing file from structure\n const testPath = fileNode.path;\n const metaPath = joinURL(testPath, \".meta\");\n\n // Check if provider supports meta writes (via node path)\n if (!(await supportsMetaWrite(provider, testPath))) {\n // Provider doesn't support meta writes (e.g., read-only schema introspection)\n return;\n }\n\n // Write metadata via node path (new design)\n const testMeta = { customField: \"rootValue\", count: 100 };\n const writeResult = await provider.write(testPath, { meta: testMeta });\n expect(writeResult).toBeDefined();\n expect(writeResult.data).toBeDefined();\n\n // Read back metadata via .meta path\n const readResult = await provider.read(metaPath);\n expect(readResult.data).toBeDefined();\n expect(readResult.data?.meta).toBeDefined();\n expect(readResult.data?.meta?.customField).toBe(\"rootValue\");\n expect(readResult.data?.meta?.count).toBe(100);\n });\n }\n\n // Test writing metadata to a file in subdirectory\n if (subdirFileNode) {\n test(\"meta-write-read-file-subdir: should write and read metadata for file in subdirectory\", async () => {\n const provider = getProvider();\n if (!provider.write || !provider.read) return;\n\n // Use existing file from structure in subdirectory\n const testPath = subdirFileNode.path;\n const metaPath = joinURL(testPath, \".meta\");\n\n // Check if provider supports meta writes (via node path)\n if (!(await supportsMetaWrite(provider, testPath))) {\n return;\n }\n\n // Write metadata via node path (new design)\n const testMeta = { location: \"subdir\", priority: 5 };\n const writeResult = await provider.write(testPath, { meta: testMeta });\n expect(writeResult).toBeDefined();\n\n // Read back metadata via .meta path\n const readResult = await provider.read(metaPath);\n expect(readResult.data).toBeDefined();\n expect(readResult.data?.meta?.location).toBe(\"subdir\");\n expect(readResult.data?.meta?.priority).toBe(5);\n });\n }\n\n if (dirNode) {\n test(\"meta-write-read-directory: should write and read metadata for directory\", async () => {\n const provider = getProvider();\n if (!provider.write || !provider.read) return;\n\n // Write metadata for existing directory via node path\n const testPath = dirNode.path;\n const metaPath = joinURL(testPath, \".meta\");\n\n // Check if provider supports meta writes (via node path)\n if (!(await supportsMetaWrite(provider, testPath))) {\n return;\n }\n\n // Write metadata via node path (new design)\n const testMeta = { dirType: \"documentation\", indexed: true };\n const writeResult = await provider.write(testPath, { meta: testMeta });\n expect(writeResult).toBeDefined();\n\n // Read back metadata via .meta path\n const readResult = await provider.read(metaPath);\n expect(readResult.data).toBeDefined();\n expect(readResult.data?.meta?.dirType).toBe(\"documentation\");\n expect(readResult.data?.meta?.indexed).toBe(true);\n });\n }\n\n test(\"meta-write-read-root: should write and read metadata for root directory\", async () => {\n const provider = getProvider();\n if (!provider.write || !provider.read) {\n // write or read not supported, skip\n return;\n }\n\n // Write metadata for root via root path (new design)\n const rootPath = \"/\";\n const metaPath = \"/.meta\";\n\n // Check if provider supports meta writes (via node path)\n if (!(await supportsMetaWrite(provider, rootPath))) {\n return;\n }\n\n // Write metadata via root path (new design)\n const testMeta = { projectName: \"test-project\", version: \"1.0.0\" };\n const writeResult = await provider.write(rootPath, { meta: testMeta });\n expect(writeResult).toBeDefined();\n\n // Read back metadata via .meta path\n const readResult = await provider.read(metaPath);\n expect(readResult.data).toBeDefined();\n expect(readResult.data?.meta?.projectName).toBe(\"test-project\");\n expect(readResult.data?.meta?.version).toBe(\"1.0.0\");\n });\n\n // Test metadata merge on an existing file\n if (fileNode) {\n test(\"meta-merge: should merge metadata on subsequent writes\", async () => {\n const provider = getProvider();\n if (!provider.write || !provider.read) {\n // write or read not supported, skip\n return;\n }\n\n // Use existing file from structure\n const testPath = fileNode.path;\n const metaPath = joinURL(testPath, \".meta\");\n\n // Check if provider supports meta writes (via node path)\n if (!(await supportsMetaWrite(provider, testPath))) {\n return;\n }\n\n // Write first batch of metadata via node path (new design)\n await provider.write(testPath, { meta: { field1: \"value1\", field2: \"value2\" } });\n\n // Write second batch - should merge\n await provider.write(testPath, { meta: { field2: \"updated\", field3: \"value3\" } });\n\n // Read back and verify merge via .meta path\n const readResult = await provider.read(metaPath);\n expect(readResult.data?.meta?.field1).toBe(\"value1\");\n expect(readResult.data?.meta?.field2).toBe(\"updated\");\n expect(readResult.data?.meta?.field3).toBe(\"value3\");\n });\n }\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { flattenTree, isDirectory, type TestConfig, type TestDataStructure } from \"../types.js\";\n\n/**\n * Run metadata richness validation suite.\n * Checks that list entries have required metadata fields:\n * - meta.kind: must be a non-empty string\n * - meta.childrenCount: must be defined for directory nodes\n * - meta.description: recommended but not enforced\n */\nexport function runMetadataRichnessTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n const allNodes = flattenTree(root).filter((n) => n.path !== \"/\");\n\n describe(\"metadata-richness\", () => {\n describe(\"kind field\", () => {\n test(\"list entries should have meta.kind as non-empty string\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n expect(result.data).toBeDefined();\n\n for (const entry of result.data) {\n expect(entry.meta?.kind).toBeDefined();\n expect(typeof entry.meta?.kind).toBe(\"string\");\n expect((entry.meta?.kind as string).length).toBeGreaterThan(0);\n }\n });\n\n test(\"kind is any non-empty string (no format restriction)\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n if (result.data.length === 0) return;\n\n const entry = result.data[0]!;\n expect(typeof entry.meta?.kind).toBe(\"string\");\n // Any non-empty string is valid - no format enforcement\n expect((entry.meta?.kind as string).length).toBeGreaterThan(0);\n });\n });\n\n describe(\"childrenCount field\", () => {\n for (const node of allNodes.filter((n) => isDirectory(n.node))) {\n test(`directory \"${node.path}\" should have childrenCount defined`, async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // List the parent to find this directory entry\n const parentPath = node.path.split(\"/\").slice(0, -1).join(\"/\") || \"/\";\n const result = await provider.list(parentPath, { maxDepth: 1 });\n\n const entry = result.data.find((e) => e.path === node.path || e.id === node.node.name);\n if (!entry) return; // Skip if not found in parent list\n\n expect(entry.meta?.childrenCount).toBeDefined();\n expect(typeof entry.meta?.childrenCount).toBe(\"number\");\n });\n }\n\n test(\"childrenCount = -1 is valid (unknown children count)\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n for (const entry of result.data) {\n if (entry.meta?.childrenCount !== undefined) {\n expect(typeof entry.meta.childrenCount).toBe(\"number\");\n // -1, 0, and positive are all valid\n expect(entry.meta.childrenCount >= -1).toBe(true);\n }\n }\n });\n\n test(\"childrenCount = 0 is valid for leaf nodes and empty directories\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n for (const entry of result.data) {\n if (entry.meta?.childrenCount === 0) {\n // 0 is valid for both files and empty directories\n expect(entry.meta.childrenCount).toBe(0);\n }\n }\n });\n });\n\n describe(\"description field\", () => {\n test(\"description is recommended but not required\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n // Just check that if description exists, it's a string\n for (const entry of result.data) {\n if (entry.meta?.description !== undefined) {\n expect(typeof entry.meta.description).toBe(\"string\");\n }\n }\n // No assertion for existence - it's recommended, not required\n });\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { AFSNotFoundError } from \"@aigne/afs\";\nimport type { TestConfig } from \"../types.js\";\n\n/**\n * Run not-found error test suite.\n * Tests that operations on non-existent paths throw AFSNotFoundError.\n *\n * Expected behavior:\n * - read/list/stat on non-existent path: throw AFSNotFoundError\n * - search on non-existent path: returns empty results (not error)\n * - write/delete/rename on non-existent path: throw AFSNotFoundError\n * - Unsupported operations: method is undefined\n */\nexport function runNoHandlerTests(getProvider: () => AFSModule, _config: TestConfig): void {\n // Use a path that definitely does not exist\n const nonExistentPath = \"/____path-that-does-not-exist-12345____\";\n\n describe(\"not-found-errors\", () => {\n describe(\"read operations\", () => {\n test(\"read: non-existent path should throw AFSNotFoundError\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n try {\n await provider.read(nonExistentPath);\n // Should not reach here\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n }\n });\n\n test(\"list: non-existent path should throw AFSNotFoundError\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n try {\n await provider.list(nonExistentPath);\n // Should not reach here\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n }\n });\n\n test(\"stat: non-existent path should throw AFSNotFoundError\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n try {\n await provider.stat(nonExistentPath);\n // Should not reach here\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n }\n });\n });\n\n describe(\"search behavior\", () => {\n test(\"search: non-existent path should return empty results or throw error\", async () => {\n const provider = getProvider();\n if (!provider.search) return;\n\n try {\n // Search on non-existent path may return empty array or throw error\n const result = await provider.search(nonExistentPath, \"query\");\n expect(result).toBeDefined();\n expect(result.data).toBeDefined();\n expect(Array.isArray(result.data)).toBe(true);\n expect(result.data.length).toBe(0);\n } catch (error) {\n // Throwing an error is also acceptable (e.g., AFSNotFoundError or search tool error)\n expect(error).toBeInstanceOf(Error);\n }\n });\n });\n\n describe(\"write operations\", () => {\n test(\"delete: non-existent path should throw AFSNotFoundError\", async () => {\n const provider = getProvider();\n if (!provider.delete) return;\n if (provider.accessMode === \"readonly\") return;\n\n try {\n await provider.delete(nonExistentPath);\n // Should not reach here\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n }\n });\n\n test(\"rename: non-existent source should throw AFSNotFoundError\", async () => {\n const provider = getProvider();\n if (!provider.rename) return;\n if (provider.accessMode === \"readonly\") return;\n\n const newPath = \"/____new-path____\";\n try {\n await provider.rename(nonExistentPath, newPath);\n // Should not reach here\n expect(true).toBe(false);\n } catch (error) {\n expect(error).toBeInstanceOf(AFSNotFoundError);\n }\n });\n });\n\n describe(\"method availability\", () => {\n test(\"unsupported operations should have undefined methods\", () => {\n const provider = getProvider();\n\n // Methods are either functions or undefined (not some other value)\n const operations = [\n \"list\",\n \"read\",\n \"write\",\n \"delete\",\n \"exec\",\n \"search\",\n \"stat\",\n \"explain\",\n \"rename\",\n ] as const;\n\n for (const op of operations) {\n const method = provider[op];\n expect(method === undefined || typeof method === \"function\").toBe(true);\n }\n });\n\n test(\"accessMode should be defined\", () => {\n const provider = getProvider();\n expect(provider.accessMode).toBeDefined();\n expect([\"readonly\", \"readwrite\"]).toContain(provider.accessMode as string);\n });\n\n test(\"name should be defined\", () => {\n const provider = getProvider();\n expect(provider.name).toBeDefined();\n expect(typeof provider.name).toBe(\"string\");\n expect(provider.name.length).toBeGreaterThan(0);\n });\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\nimport { findFirstFile, type TestConfig, type TestDataStructure } from \"../types.js\";\n\n/**\n * Run path normalization test suite.\n * Tests that various path formats are handled correctly.\n */\nexport function runPathNormalizationTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n\n // Find a file entry for testing\n const fileNode = findFirstFile(root);\n\n describe(\"path-normalization\", () => {\n describe(\"list\", () => {\n test(\"root with trailing slash: list('/') should work\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\");\n expect(result.data).toBeDefined();\n expect(Array.isArray(result.data)).toBe(true);\n });\n\n test(\"empty string path: should normalize to root\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // Some providers may throw, some may normalize\n try {\n const result = await provider.list(\"\");\n expect(result.data).toBeDefined();\n } catch {\n // Acceptable behavior\n }\n });\n\n if (fileNode) {\n test(\"path with trailing slash: should normalize\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const parentPath = fileNode.path.split(\"/\").slice(0, -1).join(\"/\") || \"/\";\n\n // Try with trailing slash\n try {\n const result = await provider.list(joinURL(parentPath, \"/\"));\n expect(result.data).toBeDefined();\n } catch {\n // Some providers may not support trailing slash\n }\n });\n }\n });\n\n describe(\"read\", () => {\n if (fileNode) {\n test(\"read with exact path: should return entry\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(fileNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(fileNode.path);\n });\n\n test(\"read path without leading slash: should normalize\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const pathWithoutSlash = fileNode.path.slice(1); // Remove leading /\n\n try {\n const result = await provider.read(pathWithoutSlash);\n expect(result.data).toBeDefined();\n // Normalized path should have leading slash\n expect(result.data?.path?.startsWith(\"/\")).toBe(true);\n } catch {\n // Acceptable behavior - some providers require leading slash\n }\n });\n }\n });\n\n describe(\"stat\", () => {\n test(\"stat root path: should work\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const result = await provider.stat(\"/\");\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(\"/\");\n });\n\n if (fileNode) {\n test(\"stat file path: should return path in result\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const result = await provider.stat(fileNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBeDefined();\n });\n }\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport {\n validateEntry,\n validateListResult,\n validateReadResult,\n validateStatResult,\n} from \"../assertions.js\";\nimport {\n findFirstDirectory,\n findFirstFile,\n flattenTree,\n isDirectory,\n type TestConfig,\n type TestDataStructure,\n} from \"../types.js\";\n\n/**\n * Run ReadOperations test suite.\n */\nexport function runReadTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n\n // Find test data from tree structure\n const fileNode = findFirstFile(root);\n const dirNode = findFirstDirectory(root);\n\n // Find an empty directory (has children array but length 0)\n const allNodes = flattenTree(root);\n const emptyDirNode = allNodes.find(\n (n) => n.node.children !== undefined && n.node.children.length === 0,\n );\n\n // Find a file in a subdirectory (depth >= 2)\n const subdirFileNode = allNodes.find(\n (n) => n.depth >= 2 && n.node.content !== undefined && !isDirectory(n.node),\n );\n\n describe(\"list\", () => {\n test(\"list-root: should list children at root (not including root itself)\", async () => {\n const provider = getProvider();\n if (!provider.list) {\n // list not supported, skip\n return;\n }\n\n const result = await provider.list(\"/\");\n validateListResult(result);\n\n // If root has children, should have results; otherwise empty\n const rootChildCount = root.children?.length ?? 0;\n if (rootChildCount > 0) {\n expect(result.data.length).toBeGreaterThan(0);\n }\n\n // list() should NOT include the requested path itself\n expect(result.data.some((e) => e.path === \"/\")).toBe(false);\n });\n\n if (dirNode) {\n test(\"list-subdir: should list children in subdirectory (not including self)\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(dirNode.path);\n validateListResult(result);\n\n // list() should NOT include the requested path itself\n expect(result.data.some((e) => e.path === dirNode.path)).toBe(false);\n });\n }\n\n if (emptyDirNode) {\n test(\"list-empty-dir: should return empty array for empty directory\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(emptyDirNode.path);\n validateListResult(result);\n\n // Empty dir should return empty array (no children)\n expect(result.data.length).toBe(0);\n });\n }\n\n test(\"list-not-found: should throw for non-existent path\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n await expect(provider.list(\"/non-existent-path-12345\")).rejects.toThrow();\n });\n\n test(\"list-depth-0: should return empty array for maxDepth=0\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 0 });\n validateListResult(result);\n // maxDepth=0 returns empty array (no children levels to expand)\n expect(result.data.length).toBe(0);\n });\n\n test(\"list-depth-1: should return direct children for maxDepth=1\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n validateListResult(result);\n\n // Should NOT include root\n expect(result.data.some((e) => e.path === \"/\")).toBe(false);\n\n // All entries should be direct children (depth 1)\n for (const entry of result.data) {\n const depth = entry.path.split(\"/\").filter(Boolean).length;\n expect(depth).toBe(1);\n }\n });\n\n test(\"list-with-limit: should respect limit parameter\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { limit: 2 });\n validateListResult(result);\n expect(result.data.length).toBeLessThanOrEqual(2);\n });\n });\n\n describe(\"list-read consistency\", () => {\n test(\"all listed entries must be readable\", async () => {\n const provider = getProvider();\n if (!provider.list || !provider.read) return;\n\n // Recursive function to check list-read consistency\n async function checkPath(path: string, maxRecursionDepth = 3): Promise<void> {\n if (maxRecursionDepth <= 0) return;\n\n const listResult = await provider.list!(path, { maxDepth: 1 });\n validateListResult(listResult);\n\n for (const entry of listResult.data) {\n // Every listed entry must be readable\n const readResult = await provider.read!(entry.path);\n expect(readResult.data).toBeDefined();\n expect(readResult.data?.path).toBe(entry.path);\n\n // Recursively check children if this entry has children\n const childrenCount = readResult.data?.meta?.childrenCount;\n if (childrenCount !== undefined && childrenCount !== 0) {\n await checkPath(entry.path, maxRecursionDepth - 1);\n }\n }\n }\n\n await checkPath(\"/\");\n });\n\n test(\"nested directories: all descendants should be readable\", async () => {\n const provider = getProvider();\n if (!provider.list || !provider.read) return;\n\n // Get all entries up to depth 3\n const result = await provider.list(\"/\", { maxDepth: 3 });\n validateListResult(result);\n\n // Every entry in the list must be readable\n for (const entry of result.data) {\n const readResult = await provider.read(entry.path);\n expect(readResult.data).toBeDefined();\n expect(readResult.data?.path).toBe(entry.path);\n }\n });\n });\n\n describe(\"read\", () => {\n if (fileNode) {\n test(\"read-file-root: should read file content\", async () => {\n const provider = getProvider();\n if (!provider.read) {\n // read not supported, skip\n return;\n }\n\n const result = await provider.read(fileNode.path);\n validateReadResult(result);\n expect(result.data).toBeDefined();\n validateEntry(result.data!);\n });\n }\n\n if (subdirFileNode) {\n test(\"read-file-subdir: should read file in subdirectory\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(subdirFileNode.path);\n validateReadResult(result);\n expect(result.data).toBeDefined();\n validateEntry(result.data!);\n });\n }\n\n if (dirNode) {\n test(\"read-directory: should read directory entry\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(dirNode.path);\n validateReadResult(result);\n expect(result.data).toBeDefined();\n });\n }\n\n test(\"read-not-found: should throw for non-existent path\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n await expect(provider.read(\"/non-existent-file-12345.txt\")).rejects.toThrow();\n });\n });\n\n describe(\"stat\", () => {\n if (fileNode) {\n test(\"stat-file: should get file stats\", async () => {\n const provider = getProvider();\n if (!provider.stat) {\n // stat not supported, skip\n return;\n }\n\n const result = await provider.stat(fileNode.path);\n validateStatResult(result);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBeDefined();\n });\n }\n\n if (dirNode) {\n test(\"stat-directory: should get directory stats\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const result = await provider.stat(dirNode.path);\n validateStatResult(result);\n expect(result.data).toBeDefined();\n });\n }\n\n test(\"stat-not-found: should throw for non-existent path\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n await expect(provider.stat(\"/non-existent-path-12345\")).rejects.toThrow();\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\nimport {\n findFirstDirectory,\n findFirstFile,\n flattenTree,\n type TestConfig,\n type TestDataStructure,\n} from \"../types.js\";\n\n/**\n * Run route params test suite.\n * Tests that path parameters are correctly extracted and entries have proper structure.\n * This validates that the router correctly parses dynamic segments like :id, :path*, etc.\n */\nexport function runRouteParamsTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n const allNodes = flattenTree(root);\n const fileNode = findFirstFile(root);\n const dirNode = findFirstDirectory(root);\n\n // Find a deeply nested path for testing\n const deepNode = allNodes.find((n) => n.depth >= 2);\n\n describe(\"route-params\", () => {\n describe(\"path extraction\", () => {\n test(\"root path: should have path '/'\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/\");\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(\"/\");\n });\n\n if (fileNode) {\n test(\"file path: should match request path exactly\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(fileNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(fileNode.path);\n });\n }\n\n if (dirNode) {\n test(\"directory path: should match request path exactly\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(dirNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(dirNode.path);\n });\n }\n\n if (deepNode) {\n test(\"deep path: should preserve full path structure\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(deepNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(deepNode.path);\n\n // Verify path segments are preserved\n const segments = deepNode.path.split(\"/\").filter(Boolean);\n const resultSegments = result.data?.path?.split(\"/\").filter(Boolean) ?? [];\n expect(resultSegments).toEqual(segments);\n });\n }\n });\n\n describe(\"id generation\", () => {\n test(\"entry id: should be defined and non-empty\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/\");\n expect(result.data).toBeDefined();\n expect(result.data?.id).toBeDefined();\n expect(typeof result.data?.id).toBe(\"string\");\n expect(result.data?.id?.length).toBeGreaterThan(0);\n });\n\n if (fileNode) {\n test(\"file id: should be string\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(fileNode.path);\n expect(result.data).toBeDefined();\n expect(typeof result.data?.id).toBe(\"string\");\n });\n }\n\n test(\"list entries: all should have valid ids\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 2 });\n expect(result.data).toBeDefined();\n\n for (const entry of result.data) {\n expect(entry.id).toBeDefined();\n expect(typeof entry.id).toBe(\"string\");\n expect(entry.id.length).toBeGreaterThan(0);\n }\n });\n });\n\n describe(\"path consistency\", () => {\n test(\"list entries: paths should be consistent with parent\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(\"/\", { maxDepth: 1 });\n expect(result.data).toBeDefined();\n\n for (const entry of result.data) {\n // All paths should start with /\n expect(entry.path.startsWith(\"/\")).toBe(true);\n\n // Non-root paths should not end with /\n if (entry.path !== \"/\") {\n expect(entry.path.endsWith(\"/\")).toBe(false);\n }\n\n // Child paths should start with parent path (or be root)\n if (entry.path !== \"/\") {\n const parentPath = entry.path.split(\"/\").slice(0, -1).join(\"/\") || \"/\";\n expect(parentPath === \"/\" || result.data.some((e) => e.path === parentPath)).toBe(true);\n }\n }\n });\n\n if (dirNode) {\n test(\"subdirectory list: child paths should be prefixed correctly\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(dirNode.path, { maxDepth: 1 });\n expect(result.data).toBeDefined();\n\n for (const entry of result.data) {\n // All entries should either be the directory itself or children\n const dirPathWithSlash = joinURL(dirNode.path, \"/\");\n expect(entry.path === dirNode.path || entry.path.startsWith(dirPathWithSlash)).toBe(\n true,\n );\n }\n });\n }\n });\n\n describe(\"meta path handling\", () => {\n test(\".meta path: should have correct path in response\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(\"/.meta\");\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(\"/.meta\");\n });\n\n if (fileNode) {\n test(\"file .meta path: should preserve full meta path\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const metaPath = joinURL(fileNode.path, \".meta\");\n const result = await provider.read(metaPath);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(metaPath);\n });\n }\n\n if (dirNode) {\n test(\"directory .meta path: should preserve full meta path\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const metaPath = joinURL(dirNode.path, \".meta\");\n const result = await provider.read(metaPath);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(metaPath);\n });\n }\n });\n\n describe(\"stat path handling\", () => {\n test(\"stat: path should match request\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const result = await provider.stat(\"/\");\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(\"/\");\n });\n\n if (fileNode) {\n test(\"stat file: path should match request\", async () => {\n const provider = getProvider();\n if (!provider.stat) return;\n\n const result = await provider.stat(fileNode.path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(fileNode.path);\n });\n }\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { validateSearchResult } from \"../assertions.js\";\nimport {\n findFirstDirectory,\n flattenTree,\n isDirectory,\n type TestConfig,\n type TestDataStructure,\n} from \"../types.js\";\n\n/**\n * Run SearchOperations test suite.\n */\nexport function runSearchTests(\n getProvider: () => AFSModule,\n structure: TestDataStructure,\n _config: TestConfig,\n): void {\n const root = structure.root;\n\n // Find a file with content for search testing\n const allNodes = flattenTree(root);\n const fileWithContent = allNodes.find(\n (n) =>\n n.node.content !== undefined && typeof n.node.content === \"string\" && !isDirectory(n.node),\n );\n\n const dirNode = findFirstDirectory(root);\n\n describe(\"search\", () => {\n test(\"search-basic-root: should search with simple query at root\", async () => {\n const provider = getProvider();\n if (!provider.search) {\n // search not supported, skip\n return;\n }\n\n // Use a common pattern that should exist in most test setups\n const content = fileWithContent?.node.content;\n const query = typeof content === \"string\" ? content.slice(0, 10) : \"test\";\n const result = await provider.search(\"/\", query);\n\n validateSearchResult(result);\n });\n\n if (dirNode) {\n test(\"search-basic-subdir: should search within subdirectory\", async () => {\n const provider = getProvider();\n if (!provider.search) return;\n\n const query = \"test\";\n const result = await provider.search(dirNode.path, query);\n\n validateSearchResult(result);\n });\n }\n\n test(\"search-no-results: should return empty when no match\", async () => {\n const provider = getProvider();\n if (!provider.search) return;\n\n const result = await provider.search(\"/\", \"nonexistentquerystring12345xyz\");\n\n validateSearchResult(result);\n expect(result.data.length).toBe(0);\n });\n\n test(\"search-with-limit: should respect limit parameter\", async () => {\n const provider = getProvider();\n if (!provider.search) return;\n\n // Use a query that might match multiple files\n const result = await provider.search(\"/\", \"e\", { limit: 1 });\n\n validateSearchResult(result);\n expect(result.data.length).toBeLessThanOrEqual(1);\n });\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\nimport { isDirectory, isFile, type TestConfig, type TestTreeNode } from \"../types.js\";\n\n/**\n * Run structure validation tests.\n * Strictly validates that every node in the defined tree structure:\n * 1. Can be read via read()\n * 2. Can be listed via list()\n * 3. Has accessible metadata via read(.meta)\n * 4. Has expected content/children/metadata values if specified\n */\nexport function runStructureTests(\n getProvider: () => AFSModule,\n root: TestTreeNode,\n _config: TestConfig,\n): void {\n describe(\"structure-validation\", () => {\n // Collect all nodes with their paths for testing\n const nodesToTest: Array<{ path: string; node: TestTreeNode }> = [];\n\n function collectNodes(node: TestTreeNode, parentPath: string): void {\n const currentPath =\n parentPath === \"/\" && node.name === \"\" ? \"/\" : joinURL(parentPath, node.name);\n\n nodesToTest.push({ path: currentPath, node });\n\n if (node.children) {\n for (const child of node.children) {\n collectNodes(child, currentPath);\n }\n }\n }\n\n collectNodes(root, \"/\");\n\n // Test each node in the tree\n for (const { path, node } of nodesToTest) {\n const isDir = isDirectory(node);\n const isFileNode = isFile(node);\n const nodeType = isDir ? \"directory\" : isFileNode ? \"file\" : \"node\";\n\n describe(`${path} (${nodeType})`, () => {\n // ========== Required: Read API ==========\n test(\"read: should be readable\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(path);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBeDefined();\n });\n\n // ========== Required: List API ==========\n test(\"list: should be listable with maxDepth=1\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(path, { maxDepth: 1 });\n expect(result.data).toBeDefined();\n expect(Array.isArray(result.data)).toBe(true);\n // list() should NOT include the requested path itself\n expect(result.data.some((e) => e.path === path)).toBe(false);\n });\n\n test(\"list: maxDepth=0 should return empty array\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(path, { maxDepth: 0 });\n expect(result.data).toBeDefined();\n expect(Array.isArray(result.data)).toBe(true);\n // maxDepth=0 returns empty array (no children levels to expand)\n expect(result.data.length).toBe(0);\n });\n\n // ========== Required: Meta API ==========\n test(\"meta: should have accessible metadata\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n // Use joinURL to properly construct meta path\n const metaPath = joinURL(path, \".meta\");\n const result = await provider.read(metaPath);\n expect(result.data).toBeDefined();\n expect(result.data?.path).toBe(metaPath);\n expect(result.data?.meta).toBeDefined();\n });\n\n // ========== Optional: Validate content if specified ==========\n if (isFileNode && node.content !== undefined && node.content !== \"\") {\n test(\"content: should have expected content\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const result = await provider.read(path);\n expect(result.data).toBeDefined();\n // Content can be a partial match (contains)\n expect(result.data?.content).toContain(node.content);\n });\n }\n\n // ========== Optional: Validate children if specified ==========\n if (isDir && node.children && node.children.length > 0) {\n test(\"children: should list expected children\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n const result = await provider.list(path, { maxDepth: 1 });\n expect(result.data).toBeDefined();\n expect(Array.isArray(result.data)).toBe(true);\n\n // list() returns only children, not the path itself\n const listedPaths = result.data.map((e) => e.path);\n\n // Verify each expected child is present\n const expectedChildPaths = node.children!.map((child) => joinURL(path, child.name));\n\n for (const expectedPath of expectedChildPaths) {\n expect(listedPaths).toContain(expectedPath);\n }\n });\n }\n\n // ========== Compliance: childrenCount consistency ==========\n test(\"childrenCount: should match actual children count\", async () => {\n const provider = getProvider();\n if (!provider.read || !provider.list) return;\n\n // Get childrenCount from read result\n const readResult = await provider.read(path);\n const childrenCount = readResult.data?.meta?.childrenCount;\n\n // Get actual children from list\n const listResult = await provider.list(path, { maxDepth: 1 });\n const actualChildCount = listResult.data.length;\n\n // Validate based on childrenCount semantics:\n // - undefined or 0: no children (leaf node)\n // - N > 0: exactly N children\n // - -1: has children, count unknown\n if (childrenCount === undefined || childrenCount === 0) {\n // Leaf node: should have no children\n expect(actualChildCount).toBe(0);\n } else if (childrenCount === -1) {\n // Unknown count: should have at least 1 child\n expect(actualChildCount).toBeGreaterThanOrEqual(1);\n } else if (childrenCount > 0) {\n // Exact count: should match\n expect(actualChildCount).toBe(childrenCount);\n }\n });\n\n // ========== Optional: Validate metadata values if specified ==========\n if (node.meta && Object.keys(node.meta).length > 0) {\n test(\"meta: should have expected metadata values\", async () => {\n const provider = getProvider();\n if (!provider.read) return;\n\n const metaPath = joinURL(path, \".meta\");\n const result = await provider.read(metaPath);\n expect(result.data).toBeDefined();\n expect(result.data?.meta).toBeDefined();\n\n // Verify each expected metadata key\n for (const [key, value] of Object.entries(node.meta!)) {\n expect(result.data?.meta?.[key]).toEqual(value);\n }\n });\n }\n\n // ========== Optional: Validate actions if specified ==========\n if (node.actions && node.actions.length > 0) {\n test(\"actions: should have expected actions\", async () => {\n const provider = getProvider();\n if (!provider.list) return;\n\n // List actions at this node\n const actionsPath = joinURL(path, \".actions\");\n const result = await provider.list(actionsPath, { maxDepth: 1 });\n expect(result.data).toBeDefined();\n expect(Array.isArray(result.data)).toBe(true);\n\n // Get action names from the listing\n // Actions are entries where path ends with .actions/<name>\n const listedActionNames = result.data\n .filter((e) => e.path !== actionsPath)\n .map((e) => {\n const parts = e.path.split(\"/\");\n return parts[parts.length - 1];\n });\n\n // Verify each expected action is present\n for (const expectedAction of node.actions!) {\n expect(listedActionNames).toContain(expectedAction.name);\n\n // Optionally verify action description if specified\n if (expectedAction.description) {\n const actionEntry = result.data.find((e) =>\n e.path.endsWith(`/.actions/${expectedAction.name}`),\n );\n expect(actionEntry?.meta?.description ?? actionEntry?.summary).toContain(\n expectedAction.description,\n );\n }\n }\n });\n }\n });\n }\n });\n}\n","import { describe, expect, test } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport type { TestConfig, WriteExpectedOutput, WriteTestCase } from \"../types.js\";\n\n/**\n * Check if expected output is a validator function.\n */\nfunction isValidator(\n expected: WriteExpectedOutput,\n): expected is (\n result: { data?: { path: string; content?: unknown; meta?: Record<string, unknown> | null } },\n expect: typeof import(\"bun:test\").expect,\n) => void {\n return typeof expected === \"function\";\n}\n\n/**\n * Check if expected output is a content matcher.\n */\nfunction isContentMatcher(expected: WriteExpectedOutput): expected is { content: unknown } {\n return typeof expected === \"object\" && expected !== null && \"content\" in expected;\n}\n\n/**\n * Check if expected output is a contentContains matcher.\n */\nfunction isContentContainsMatcher(\n expected: WriteExpectedOutput,\n): expected is { contentContains: string } {\n return typeof expected === \"object\" && expected !== null && \"contentContains\" in expected;\n}\n\n/**\n * Check if expected output is a meta matcher.\n */\nfunction isMetaMatcher(\n expected: WriteExpectedOutput,\n): expected is { meta: Record<string, unknown> } {\n return typeof expected === \"object\" && expected !== null && \"meta\" in expected;\n}\n\n/**\n * Run write case tests.\n * Tests write operations based on fixture-defined cases.\n * These tests run LAST because they may modify the data structure.\n */\nexport function runWriteCaseTests(\n getProvider: () => AFSModule,\n cases: WriteTestCase[],\n _config: TestConfig,\n): void {\n describe(\"write-cases\", () => {\n for (const testCase of cases) {\n test(`write ${testCase.path}: ${testCase.name}`, async () => {\n const provider = getProvider();\n\n if (!provider.write) {\n // write not supported, skip\n return;\n }\n\n if (testCase.shouldThrow) {\n // Expect write to throw\n let threw = false;\n let errorMessage = \"\";\n\n try {\n await provider.write(testCase.path, testCase.payload, {});\n } catch (error) {\n threw = true;\n errorMessage = error instanceof Error ? error.message : String(error);\n }\n\n expect(threw).toBe(true);\n\n // Optionally match error message\n if (typeof testCase.shouldThrow === \"string\") {\n expect(errorMessage).toContain(testCase.shouldThrow);\n } else if (testCase.shouldThrow instanceof RegExp) {\n expect(errorMessage).toMatch(testCase.shouldThrow);\n }\n } else {\n // Expect successful write\n const result = await provider.write(testCase.path, testCase.payload, {});\n\n expect(result).toBeDefined();\n\n // Validate output if expected is specified\n if (testCase.expected !== undefined) {\n if (isValidator(testCase.expected)) {\n // Custom validator function\n testCase.expected(result, expect);\n } else if (isContentMatcher(testCase.expected)) {\n // Verify written content matches\n expect(result.data?.content).toEqual(testCase.expected.content);\n } else if (isContentContainsMatcher(testCase.expected)) {\n // Verify content contains string\n const content = result.data?.content;\n expect(typeof content === \"string\").toBe(true);\n expect(content as string).toContain(testCase.expected.contentContains);\n } else if (isMetaMatcher(testCase.expected)) {\n // Verify meta matches\n expect(result.data?.meta).toMatchObject(testCase.expected.meta);\n }\n }\n\n // Optionally verify by reading back\n if (testCase.expected && provider.read) {\n const readResult = await provider.read(testCase.path, {});\n expect(readResult).toBeDefined();\n }\n }\n });\n }\n });\n}\n","import { afterAll, afterEach, beforeAll, beforeEach, describe } from \"bun:test\";\nimport type { AFSModule } from \"@aigne/afs\";\nimport {\n runAccessModeTests,\n runActionTests,\n runCapabilitiesOperationsTests,\n runDeepListTests,\n runDeleteCaseTests,\n runEntryFieldsTests,\n runErrorTypesTests,\n runExecuteTests,\n runExplainExistenceTests,\n runExplainTests,\n runListOptionsTests,\n runMetadataRichnessTests,\n runMetaTests,\n runNoHandlerTests,\n runPathNormalizationTests,\n runReadTests,\n runRouteParamsTests,\n runSearchTests,\n runStructureTests,\n runWriteCaseTests,\n} from \"./suites/index.js\";\nimport type { ProviderTestFixture, TestDataStructure } from \"./types.js\";\n\n/**\n * Run provider conformance tests.\n *\n * @example\n * ```typescript\n * import { runProviderTests } from \"@aigne/afs/testing\";\n *\n * describe(\"MyProvider Conformance\", () => {\n * runProviderTests({\n * name: \"MyProvider\",\n * createProvider: () => new MyProvider({ ... }),\n * structure: {\n * root: {\n * name: \"\",\n * children: [\n * { name: \"file.txt\", content: \"Hello\" },\n * {\n * name: \"docs\",\n * children: [\n * { name: \"readme.md\", content: \"# Readme\" },\n * ],\n * },\n * ],\n * },\n * },\n * });\n * });\n * ```\n */\nexport function runProviderTests<T extends AFSModule>(fixture: ProviderTestFixture<T>): void {\n let provider: T;\n\n const config = fixture.config ?? {};\n const structure: TestDataStructure = fixture.structure;\n\n describe(fixture.name, () => {\n // Setup lifecycle hooks\n if (fixture.beforeAll) {\n beforeAll(fixture.beforeAll);\n }\n\n beforeAll(async () => {\n provider = await fixture.createProvider();\n });\n\n if (fixture.afterAll) {\n afterAll(fixture.afterAll);\n }\n\n if (fixture.beforeEach) {\n beforeEach(fixture.beforeEach);\n }\n\n if (fixture.afterEach) {\n afterEach(fixture.afterEach);\n }\n\n // Run structure validation tests\n describe(\"StructureValidation\", () => {\n runStructureTests(() => provider, structure.root, config);\n });\n\n // Run core operation test suites\n describe(\"ReadOperations\", () => {\n runReadTests(() => provider, structure, config);\n });\n\n describe(\"SearchOperations\", () => {\n runSearchTests(() => provider, structure, config);\n });\n\n describe(\"MetaOperations\", () => {\n runMetaTests(() => provider, structure, config);\n });\n\n // Run execute tests if cases are provided\n if (fixture.executeCases && fixture.executeCases.length > 0) {\n describe(\"ExecuteOperations\", () => {\n runExecuteTests(() => provider, fixture.executeCases!, config);\n });\n }\n\n // Run explain tests\n describe(\"ExplainOperations\", () => {\n runExplainTests(() => provider, structure, config);\n });\n\n // Run validation test suites\n describe(\"AccessModeValidation\", () => {\n runAccessModeTests(() => provider, config);\n });\n\n describe(\"ErrorTypesValidation\", () => {\n runErrorTypesTests(() => provider, config);\n });\n\n describe(\"EntryFieldsValidation\", () => {\n runEntryFieldsTests(() => provider, structure, config);\n });\n\n describe(\"ListOptionsValidation\", () => {\n runListOptionsTests(() => provider, structure, config);\n });\n\n describe(\"PathNormalizationValidation\", () => {\n runPathNormalizationTests(() => provider, structure, config);\n });\n\n // Run deep list traversal tests\n describe(\"DeepListValidation\", () => {\n runDeepListTests(() => provider, structure, config);\n });\n\n // Run no-handler error tests\n describe(\"NoHandlerValidation\", () => {\n runNoHandlerTests(() => provider, config);\n });\n\n // Run route params tests\n describe(\"RouteParamsValidation\", () => {\n runRouteParamsTests(() => provider, structure, config);\n });\n\n // Run agent-friendliness validation suites\n describe(\"MetadataRichnessValidation\", () => {\n runMetadataRichnessTests(() => provider, structure, config);\n });\n\n describe(\"ExplainExistenceValidation\", () => {\n runExplainExistenceTests(() => provider, structure, config);\n });\n\n describe(\"CapabilitiesOperationsValidation\", () => {\n runCapabilitiesOperationsTests(() => provider, structure, config);\n });\n\n // ============================================================\n // DESTRUCTIVE TESTS - Run these LAST because they modify data\n // ============================================================\n\n // Run action case tests if cases are provided\n if (fixture.actionCases && fixture.actionCases.length > 0) {\n describe(\"ActionOperations\", () => {\n runActionTests(() => provider, fixture.actionCases!, config);\n });\n }\n\n // Run write case tests if cases are provided\n if (fixture.writeCases && fixture.writeCases.length > 0) {\n describe(\"WriteCaseOperations\", () => {\n runWriteCaseTests(() => provider, fixture.writeCases!, config);\n });\n }\n\n // Run delete case tests if cases are provided\n if (fixture.deleteCases && fixture.deleteCases.length > 0) {\n describe(\"DeleteCaseOperations\", () => {\n runDeleteCaseTests(() => provider, fixture.deleteCases!, config);\n });\n }\n });\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@aigne/afs-testing",
3
+ "version": "1.11.0-beta.7",
4
+ "description": "Testing framework for AFS provider conformance testing",
5
+ "license": "UNLICENSED",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "author": "Arcblock <blocklet@arcblock.io> https://github.com/arcblock",
10
+ "homepage": "https://github.com/arcblock/afs",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/arcblock/afs"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/arcblock/afs/issues"
17
+ },
18
+ "type": "module",
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/index.d.cts",
22
+ "exports": {
23
+ ".": {
24
+ "require": "./dist/index.cjs",
25
+ "import": "./dist/index.mjs"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "LICENSE",
31
+ "README.md",
32
+ "CHANGELOG.md"
33
+ ],
34
+ "dependencies": {
35
+ "ufo": "^1.6.3",
36
+ "@aigne/afs": "1.11.0-beta.7"
37
+ },
38
+ "devDependencies": {
39
+ "@types/bun": "^1.3.6",
40
+ "rimraf": "^6.1.2",
41
+ "tsdown": "0.20.0-beta.3",
42
+ "typescript": "5.9.2",
43
+ "@aigne/typescript-config": "0.0.0"
44
+ },
45
+ "scripts": {
46
+ "build": "tsdown",
47
+ "check-types": "tsc --noEmit",
48
+ "clean": "rimraf dist",
49
+ "test": "bun test"
50
+ }
51
+ }