Files
wifi-densepose/npm/packages/agentic-synth/tests/unit/config/config.test.js
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

276 lines
7.6 KiB
JavaScript

/**
* Unit tests for Config
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { Config } from '../../../src/config/config.js';
import { writeFileSync, unlinkSync, existsSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
describe('Config', () => {
let testConfigPath;
let originalEnv;
beforeEach(() => {
originalEnv = { ...process.env };
testConfigPath = join(tmpdir(), `test-config-${Date.now()}.json`);
});
afterEach(() => {
process.env = originalEnv;
if (existsSync(testConfigPath)) {
unlinkSync(testConfigPath);
}
});
describe('constructor', () => {
it('should create config with defaults', () => {
const config = new Config({ loadEnv: false });
expect(config.values).toBeDefined();
expect(config.get('api.baseUrl')).toBeDefined();
});
it('should accept custom options', () => {
const config = new Config({
loadEnv: false,
api: { baseUrl: 'https://custom.com' }
});
expect(config.get('api.baseUrl')).toBe('https://custom.com');
});
it('should load from file if provided', () => {
writeFileSync(testConfigPath, JSON.stringify({
custom: { value: 'test' }
}));
const config = new Config({
loadEnv: false,
configPath: testConfigPath
});
expect(config.get('custom.value')).toBe('test');
});
});
describe('get', () => {
let config;
beforeEach(() => {
config = new Config({
loadEnv: false,
api: {
baseUrl: 'https://test.com',
timeout: 5000
},
nested: {
deep: {
value: 'found'
}
}
});
});
it('should get top-level value', () => {
expect(config.get('api')).toEqual({
baseUrl: 'https://test.com',
timeout: 5000
});
});
it('should get nested value with dot notation', () => {
expect(config.get('api.baseUrl')).toBe('https://test.com');
expect(config.get('nested.deep.value')).toBe('found');
});
it('should return default for non-existent key', () => {
expect(config.get('nonexistent', 'default')).toBe('default');
});
it('should return undefined for non-existent key without default', () => {
expect(config.get('nonexistent')).toBeUndefined();
});
it('should read from environment variables', () => {
process.env.AGENTIC_SYNTH_API_KEY = 'env-key-123';
const config = new Config({ loadEnv: false });
expect(config.get('api.key')).toBe('env-key-123');
});
it('should prioritize environment over config file', () => {
process.env.AGENTIC_SYNTH_CUSTOM_VALUE = 'from-env';
const config = new Config({
loadEnv: false,
custom: { value: 'from-config' }
});
expect(config.get('custom.value')).toBe('from-env');
});
});
describe('set', () => {
let config;
beforeEach(() => {
config = new Config({ loadEnv: false });
});
it('should set top-level value', () => {
config.set('newKey', 'newValue');
expect(config.get('newKey')).toBe('newValue');
});
it('should set nested value with dot notation', () => {
config.set('nested.deep.value', 'test');
expect(config.get('nested.deep.value')).toBe('test');
});
it('should create nested structure if not exists', () => {
config.set('a.b.c.d', 'deep');
expect(config.get('a.b.c.d')).toBe('deep');
});
it('should update existing value', () => {
config.set('api.baseUrl', 'https://new.com');
expect(config.get('api.baseUrl')).toBe('https://new.com');
});
});
describe('loadFromFile', () => {
it('should load JSON config', () => {
const configData = {
api: { baseUrl: 'https://json.com' }
};
writeFileSync(testConfigPath, JSON.stringify(configData));
const config = new Config({ loadEnv: false });
config.loadFromFile(testConfigPath);
expect(config.get('api.baseUrl')).toBe('https://json.com');
});
it('should load YAML config', () => {
const yamlPath = testConfigPath.replace('.json', '.yaml');
writeFileSync(yamlPath, 'api:\n baseUrl: https://yaml.com');
const config = new Config({ loadEnv: false });
config.loadFromFile(yamlPath);
expect(config.get('api.baseUrl')).toBe('https://yaml.com');
unlinkSync(yamlPath);
});
it('should throw error for invalid JSON', () => {
writeFileSync(testConfigPath, 'invalid json');
const config = new Config({ loadEnv: false });
expect(() => config.loadFromFile(testConfigPath)).toThrow();
});
it('should throw error for unsupported format', () => {
const txtPath = testConfigPath.replace('.json', '.txt');
writeFileSync(txtPath, 'text');
const config = new Config({ loadEnv: false });
expect(() => config.loadFromFile(txtPath)).toThrow('Unsupported config file format');
unlinkSync(txtPath);
});
it('should throw error for non-existent file', () => {
const config = new Config({ loadEnv: false });
expect(() => config.loadFromFile('/nonexistent/file.json')).toThrow();
});
});
describe('validate', () => {
let config;
beforeEach(() => {
config = new Config({
loadEnv: false,
api: { baseUrl: 'https://test.com' },
cache: { maxSize: 100 }
});
});
it('should pass validation for existing keys', () => {
expect(() => config.validate(['api.baseUrl', 'cache.maxSize'])).not.toThrow();
});
it('should throw error for missing required keys', () => {
expect(() => config.validate(['nonexistent'])).toThrow('Missing required configuration: nonexistent');
});
it('should list all missing keys', () => {
expect(() => config.validate(['missing1', 'missing2'])).toThrow('missing1, missing2');
});
it('should return true on successful validation', () => {
expect(config.validate(['api.baseUrl'])).toBe(true);
});
});
describe('getAll', () => {
it('should return all configuration', () => {
const config = new Config({
loadEnv: false,
custom: { value: 'test' }
});
const all = config.getAll();
expect(all).toHaveProperty('custom');
expect(all.custom.value).toBe('test');
});
it('should return copy not reference', () => {
const config = new Config({ loadEnv: false });
const all = config.getAll();
all.modified = true;
expect(config.get('modified')).toBeUndefined();
});
});
describe('_parseValue', () => {
let config;
beforeEach(() => {
config = new Config({ loadEnv: false });
});
it('should parse JSON strings', () => {
expect(config._parseValue('{"key":"value"}')).toEqual({ key: 'value' });
expect(config._parseValue('[1,2,3]')).toEqual([1, 2, 3]);
});
it('should parse booleans', () => {
expect(config._parseValue('true')).toBe(true);
expect(config._parseValue('false')).toBe(false);
});
it('should parse numbers', () => {
expect(config._parseValue('123')).toBe(123);
expect(config._parseValue('45.67')).toBe(45.67);
});
it('should return string for unparseable values', () => {
expect(config._parseValue('plain text')).toBe('plain text');
});
});
describe('default configuration', () => {
it('should have sensible defaults', () => {
const config = new Config({ loadEnv: false });
expect(config.get('api.timeout')).toBe(5000);
expect(config.get('cache.maxSize')).toBe(100);
expect(config.get('cache.ttl')).toBe(3600000);
expect(config.get('router.strategy')).toBe('round-robin');
});
});
});