import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { join } from 'path'; import { mkdir, rm, writeFile as fsWriteFile, readFile } from 'fs/promises'; import { tmpdir } from 'os'; import { fileExists, readFileContent, writeFileAtomic, readJsonFile, writeJsonFile, ensureDir } from '../utils/files.js'; describe('File Utilities', () => { const testDir = join(tmpdir(), `ralph-files-test-${Date.now()}`); beforeEach(async () => { await mkdir(testDir, { recursive: true }); }); afterEach(async () => { await rm(testDir, { recursive: true, force: true }); }); describe('ensureDir', () => { it('creates directory if it does not exist', async () => { const newDir = join(testDir, 'new', 'nested', 'dir'); await ensureDir(newDir); expect(await fileExists(newDir)).toBe(true); }); it('does not throw if directory exists', async () => { await expect(ensureDir(testDir)).resolves.not.toThrow(); }); }); describe('fileExists', () => { it('returns true for existing file', async () => { const filePath = join(testDir, 'test.txt'); await fsWriteFile(filePath, 'test'); expect(await fileExists(filePath)).toBe(true); }); it('returns false for non-existing file', async () => { expect(await fileExists(join(testDir, 'nonexistent.txt'))).toBe(false); }); }); describe('readFileContent', () => { it('reads file content', async () => { const filePath = join(testDir, 'read-test.txt'); await fsWriteFile(filePath, 'hello world'); const content = await readFileContent(filePath); expect(content).toBe('hello world'); }); }); describe('writeFileAtomic', () => { it('writes file atomically', async () => { const filePath = join(testDir, 'atomic.txt'); await writeFileAtomic(filePath, 'atomic content'); const content = await readFile(filePath, 'utf-8'); expect(content).toBe('atomic content'); }); it('creates parent directories', async () => { const filePath = join(testDir, 'new', 'deep', 'file.txt'); await writeFileAtomic(filePath, 'nested'); expect(await fileExists(filePath)).toBe(true); }); }); describe('readJsonFile', () => { it('reads and parses JSON file', async () => { const filePath = join(testDir, 'data.json'); await fsWriteFile(filePath, JSON.stringify({ name: 'test', value: 42 })); const data = await readJsonFile<{ name: string; value: number }>(filePath); expect(data.name).toBe('test'); expect(data.value).toBe(42); }); }); describe('writeJsonFile', () => { it('writes JSON file with formatting', async () => { const filePath = join(testDir, 'output.json'); await writeJsonFile(filePath, { key: 'value' }); const content = await readFile(filePath, 'utf-8'); expect(content).toContain('"key"'); expect(content).toContain('"value"'); // Check it's formatted (has newlines) expect(content).toContain('\n'); }); }); });