UNPKG

@workspace-fs/core

Version:

Multi-project workspace manager for Firesystem with support for multiple sources

283 lines (231 loc) 9.72 kB
import { describe, it, expect, beforeEach, afterEach } from "vitest"; import type { SourceProvider } from "../interfaces/SourceProvider"; import type { IReactiveFileSystem } from "@firesystem/core"; /** * Test suite genérica para providers do workspace * Garante que todos os providers implementam corretamente a interface */ export function createProviderTestSuite( providerName: string, createProvider: () => SourceProvider, validConfig?: any, invalidConfigs?: Array<{ config: any; expectedError: string }>, ) { describe(`${providerName} Provider Test Suite`, () => { let provider: SourceProvider; let filesystems: IReactiveFileSystem[] = []; beforeEach(() => { provider = createProvider(); filesystems = []; }); afterEach(async () => { // Limpar todos os file systems criados for (const fs of filesystems) { if (provider.dispose) { await provider.dispose!(fs); } } filesystems = []; }); describe("Provider Interface", () => { it("should have required properties", () => { expect(provider.scheme).toBeDefined(); expect(typeof provider.scheme).toBe("string"); expect(provider.scheme.length).toBeGreaterThan(0); expect(provider.displayName).toBeDefined(); expect(typeof provider.displayName).toBe("string"); expect(provider.displayName.length).toBeGreaterThan(0); }); it("should have required methods", () => { expect(typeof provider.createFileSystem).toBe("function"); expect(typeof provider.getCapabilities).toBe("function"); }); }); describe("createFileSystem", () => { it("should create a file system without config", async () => { const fs = await provider.createFileSystem({}); filesystems.push(fs); expect(fs).toBeDefined(); expect(fs.readFile).toBeDefined(); expect(fs.writeFile).toBeDefined(); expect(fs.deleteFile).toBeDefined(); expect(fs.exists).toBeDefined(); expect(fs.mkdir).toBeDefined(); expect(fs.readDir).toBeDefined(); }); if (validConfig) { it("should create a file system with valid config", async () => { const fs = await provider.createFileSystem(validConfig); filesystems.push(fs); expect(fs).toBeDefined(); // Testar operação básica await fs.writeFile("/test.txt", "Hello Provider"); const file = await fs.readFile("/test.txt"); expect(file.content).toBe("Hello Provider"); }); } it("should create multiple independent file systems", async () => { const fs1 = await provider.createFileSystem({}); const fs2 = await provider.createFileSystem({}); filesystems.push(fs1, fs2); // Escrever em fs1 await fs1.writeFile("/file1.txt", "FS1 Content"); // Verificar que fs2 não tem o arquivo expect(await fs2.exists("/file1.txt")).toBe(false); // Escrever em fs2 await fs2.writeFile("/file2.txt", "FS2 Content"); // Verificar independência expect(await fs1.exists("/file2.txt")).toBe(false); expect(await fs2.exists("/file1.txt")).toBe(false); }); }); describe("validateConfiguration", () => { if (provider.validateConfiguration) { it("should validate empty config", async () => { const result = await provider.validateConfiguration!({}); expect(result).toBeDefined(); expect(typeof result.valid).toBe("boolean"); }); if (validConfig) { it("should accept valid config", async () => { const result = await provider.validateConfiguration!(validConfig); expect(result.valid).toBe(true); expect(result.errors).toBeUndefined(); }); } if (invalidConfigs) { invalidConfigs.forEach(({ config, expectedError }, index) => { it(`should reject invalid config #${index + 1}`, async () => { const result = await provider.validateConfiguration!(config); expect(result.valid).toBe(false); expect(result.errors).toBeDefined(); expect( result.errors!.some((e) => e.includes(expectedError)), ).toBe(true); }); }); } } }); describe("getCapabilities", () => { it("should return valid capabilities", () => { const capabilities = provider.getCapabilities(); expect(capabilities).toBeDefined(); expect(typeof capabilities.readonly).toBe("boolean"); expect(typeof capabilities.caseSensitive).toBe("boolean"); expect(typeof capabilities.atomicRename).toBe("boolean"); expect(typeof capabilities.supportsWatch).toBe("boolean"); expect(typeof capabilities.supportsMetadata).toBe("boolean"); if (capabilities.maxFileSize !== undefined) { expect(typeof capabilities.maxFileSize).toBe("number"); expect(capabilities.maxFileSize).toBeGreaterThan(0); } if (capabilities.maxPathLength !== undefined) { expect(typeof capabilities.maxPathLength).toBe("number"); expect(capabilities.maxPathLength).toBeGreaterThan(0); } }); }); describe("dispose", () => { if (provider.dispose) { it("should properly dispose file system", async () => { const fs = await provider.createFileSystem({}); // Criar alguns arquivos await fs.writeFile("/test1.txt", "Content 1"); await fs.writeFile("/test2.txt", "Content 2"); await fs.mkdir("/folder"); // Verificar que existem expect(await fs.exists("/test1.txt")).toBe(true); expect(await fs.exists("/test2.txt")).toBe(true); expect(await fs.exists("/folder")).toBe(true); // Dispose await provider.dispose!(fs); // Comportamento após dispose pode variar por provider // Alguns podem limpar, outros podem desconectar // Não assumimos comportamento específico aqui }); } }); describe("FileSystem Operations", () => { it("should support basic file operations", async () => { const fs = await provider.createFileSystem({}); filesystems.push(fs); // Write await fs.writeFile("/hello.txt", "Hello World"); // Read const file = await fs.readFile("/hello.txt"); expect(file.content).toBe("Hello World"); expect(file.type).toBe("file"); // Exists expect(await fs.exists("/hello.txt")).toBe(true); expect(await fs.exists("/missing.txt")).toBe(false); // Delete await fs.deleteFile("/hello.txt"); expect(await fs.exists("/hello.txt")).toBe(false); }); it("should support directory operations", async () => { const fs = await provider.createFileSystem({}); filesystems.push(fs); // Create directory await fs.mkdir("/folder"); expect(await fs.exists("/folder")).toBe(true); // Create nested structure await fs.mkdir("/folder/subfolder", true); await fs.writeFile("/folder/file.txt", "In folder"); await fs.writeFile("/folder/subfolder/nested.txt", "Nested"); // Read directory const entries = await fs.readDir("/folder"); expect(entries.length).toBe(2); expect(entries.some((e) => e.name === "subfolder")).toBe(true); expect(entries.some((e) => e.name === "file.txt")).toBe(true); // Remove directory await fs.rmdir("/folder/subfolder", true); expect(await fs.exists("/folder/subfolder")).toBe(false); }); it("should support glob patterns", async () => { const fs = await provider.createFileSystem({}); filesystems.push(fs); // Create test structure await fs.writeFile("/file1.txt", "1"); await fs.writeFile("/file2.js", "2"); await fs.mkdir("/folder"); await fs.writeFile("/folder/file3.txt", "3"); await fs.writeFile("/folder/file4.js", "4"); // Test patterns const txtFiles = await fs.glob("**/*.txt"); expect(txtFiles.sort()).toEqual(["/file1.txt", "/folder/file3.txt"]); const jsFiles = await fs.glob("**/*.js"); expect(jsFiles.sort()).toEqual(["/file2.js", "/folder/file4.js"]); const allFiles = await fs.glob("**/*"); expect(allFiles.length).toBe(5); // 4 files + 1 directory }); }); describe("Events (if supported)", () => { it("should emit events if reactive", async () => { const fs = await provider.createFileSystem({}); filesystems.push(fs); if (fs.events) { const events: string[] = []; fs.events.on("file:written", ({ path }) => { events.push(`written:${path}`); }); fs.events.on("file:deleted", ({ path }) => { events.push(`deleted:${path}`); }); await fs.writeFile("/test.txt", "content"); await fs.deleteFile("/test.txt"); // Dar tempo para eventos serem processados await new Promise((resolve) => setTimeout(resolve, 10)); expect(events).toContain("written:/test.txt"); expect(events).toContain("deleted:/test.txt"); } }); }); }); } /** * Helper para criar testes de provider com configurações mínimas */ export function testProvider(provider: SourceProvider) { return createProviderTestSuite(provider.displayName, () => provider); }