import { describe, it, expect, afterEach, beforeEach, mock } from 'bun:test'; import { mkdirSync, writeFileSync, rmSync } from 'fs'; import { join } from 'path'; import { tmpdir } from 'os'; import { ConfigError } from '../utils/errors'; const TEST_DIR = join(tmpdir(), `planck-claw-config-test-${Date.now()}`); const CONFIG_PATH = join(TEST_DIR, 'config.json'); mock.module('../utils/helpers', () => ({ getHomeDir: () => TEST_DIR, getConfigDir: () => TEST_DIR, getConfigPath: () => CONFIG_PATH, getMemoryDir: () => join(TEST_DIR, 'memory'), getSkillsDir: () => join(TEST_DIR, 'skills'), getLogsDir: () => join(TEST_DIR, 'logs'), getCronJobsPath: () => join(TEST_DIR, 'cron.json'), sleep: (ms: number) => new Promise((r) => setTimeout(r, ms)), truncate: (text: string, max: number) => (text.length <= max ? text : text.slice(0, max - 3) + '...'), formatDate: (d: Date) => d.toISOString(), parseDate: (s: string) => new Date(s), generateId: () => crypto.randomUUID(), })); beforeEach(() => { mkdirSync(TEST_DIR, { recursive: true }); }); afterEach(() => { try { rmSync(TEST_DIR, { recursive: true, force: true }); } catch {} }); describe('loadConfig', () => { it('throws ConfigError when config file does not exist', async () => { try { rmSync(CONFIG_PATH); } catch {} const { loadConfig } = await import('./index'); expect(() => loadConfig()).toThrow(ConfigError); expect(() => loadConfig()).toThrow(/not found/); }); it('throws ConfigError with descriptive message when JSON is invalid', async () => { writeFileSync(CONFIG_PATH, '{invalid json'); const { loadConfig } = await import('./index'); expect(() => loadConfig()).toThrow(/Invalid JSON/); }); it('throws ConfigError with descriptive message when schema is invalid', async () => { writeFileSync(CONFIG_PATH, JSON.stringify({ agents: { defaults: { temperature: 999 } } })); const { loadConfig } = await import('./index'); expect(() => loadConfig()).toThrow(/Invalid configuration schema/); }); }); describe('getConfigOrDefault', () => { it('returns default config when no config file exists', async () => { try { rmSync(CONFIG_PATH); } catch {} const { getConfigOrDefault } = await import('./index'); const config = getConfigOrDefault(); expect(config).toBeDefined(); expect(config.agents).toBeDefined(); }); it('returns loaded config when file exists and is valid', async () => { const validConfig = { providers: {}, agents: { defaults: { model: 'test/model', temperature: 0.5, maxTokens: 2048 } }, tools: {}, }; writeFileSync(CONFIG_PATH, JSON.stringify(validConfig)); const { getConfigOrDefault } = await import('./index'); const config = getConfigOrDefault(); expect(config.agents?.defaults?.maxTokens).toBe(2048); }); });