import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import fs from 'fs/promises'; import path from 'path'; import os from 'os'; import { getAutomakerDir, getFeaturesDir, getFeatureDir, getFeatureImagesDir, getBoardDir, getImagesDir, getContextDir, getWorktreesDir, getAppSpecPath, getBranchTrackingPath, ensureAutomakerDir, getGlobalSettingsPath, getCredentialsPath, getProjectSettingsPath, ensureDataDir, } from '../src/paths'; describe('paths.ts', () => { let tempDir: string; let projectPath: string; let dataDir: string; beforeEach(async () => { // Create a temporary directory for testing tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'platform-paths-test-')); projectPath = path.join(tempDir, 'test-project'); dataDir = path.join(tempDir, 'user-data'); await fs.mkdir(projectPath, { recursive: true }); }); afterEach(async () => { // Clean up temporary directory try { await fs.rm(tempDir, { recursive: true, force: true }); } catch (error) { // Ignore cleanup errors } }); describe('Project-level path construction', () => { it('should return automaker directory path', () => { const result = getAutomakerDir(projectPath); expect(result).toBe(path.join(projectPath, '.automaker')); }); it('should return features directory path', () => { const result = getFeaturesDir(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'features')); }); it('should return feature directory path', () => { const featureId = 'auth-feature'; const result = getFeatureDir(projectPath, featureId); expect(result).toBe(path.join(projectPath, '.automaker', 'features', featureId)); }); it('should return feature images directory path', () => { const featureId = 'auth-feature'; const result = getFeatureImagesDir(projectPath, featureId); expect(result).toBe(path.join(projectPath, '.automaker', 'features', featureId, 'images')); }); it('should return board directory path', () => { const result = getBoardDir(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'board')); }); it('should return images directory path', () => { const result = getImagesDir(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'images')); }); it('should return context directory path', () => { const result = getContextDir(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'context')); }); it('should return worktrees directory path', () => { const result = getWorktreesDir(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'worktrees')); }); it('should return app spec file path', () => { const result = getAppSpecPath(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'app_spec.txt')); }); it('should return branch tracking file path', () => { const result = getBranchTrackingPath(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'active-branches.json')); }); it('should return project settings file path', () => { const result = getProjectSettingsPath(projectPath); expect(result).toBe(path.join(projectPath, '.automaker', 'settings.json')); }); }); describe('Global settings path construction', () => { it('should return global settings path', () => { const result = getGlobalSettingsPath(dataDir); expect(result).toBe(path.join(dataDir, 'settings.json')); }); it('should return credentials path', () => { const result = getCredentialsPath(dataDir); expect(result).toBe(path.join(dataDir, 'credentials.json')); }); }); describe('Directory creation', () => { it('should create automaker directory', async () => { const automakerDir = await ensureAutomakerDir(projectPath); expect(automakerDir).toBe(path.join(projectPath, '.automaker')); const stats = await fs.stat(automakerDir); expect(stats.isDirectory()).toBe(true); }); it('should be idempotent when creating automaker directory', async () => { // Create directory first time const firstResult = await ensureAutomakerDir(projectPath); // Create directory second time const secondResult = await ensureAutomakerDir(projectPath); expect(firstResult).toBe(secondResult); const stats = await fs.stat(firstResult); expect(stats.isDirectory()).toBe(true); }); it('should create data directory', async () => { const result = await ensureDataDir(dataDir); expect(result).toBe(dataDir); const stats = await fs.stat(dataDir); expect(stats.isDirectory()).toBe(true); }); it('should be idempotent when creating data directory', async () => { // Create directory first time const firstResult = await ensureDataDir(dataDir); // Create directory second time const secondResult = await ensureDataDir(dataDir); expect(firstResult).toBe(secondResult); const stats = await fs.stat(firstResult); expect(stats.isDirectory()).toBe(true); }); it('should create nested directories recursively', async () => { const deepProjectPath = path.join(tempDir, 'nested', 'deep', 'project'); await fs.mkdir(deepProjectPath, { recursive: true }); const automakerDir = await ensureAutomakerDir(deepProjectPath); const stats = await fs.stat(automakerDir); expect(stats.isDirectory()).toBe(true); }); }); describe('Path handling with special characters', () => { it('should handle feature IDs with special characters', () => { const featureId = 'feature-with-dashes_and_underscores'; const result = getFeatureDir(projectPath, featureId); expect(result).toContain(featureId); }); it('should handle paths with spaces', () => { const pathWithSpaces = path.join(tempDir, 'path with spaces'); const result = getAutomakerDir(pathWithSpaces); expect(result).toBe(path.join(pathWithSpaces, '.automaker')); }); }); describe('Path relationships', () => { it('should have feature dir as child of features dir', () => { const featuresDir = getFeaturesDir(projectPath); const featureDir = getFeatureDir(projectPath, 'test-feature'); expect(featureDir.startsWith(featuresDir)).toBe(true); }); it('should have all project paths under automaker dir', () => { const automakerDir = getAutomakerDir(projectPath); const paths = [ getFeaturesDir(projectPath), getBoardDir(projectPath), getImagesDir(projectPath), getContextDir(projectPath), getWorktreesDir(projectPath), getAppSpecPath(projectPath), getBranchTrackingPath(projectPath), getProjectSettingsPath(projectPath), ]; paths.forEach((p) => { expect(p.startsWith(automakerDir)).toBe(true); }); }); }); });