Files
LangBot/tests/unit_tests/config/test_config_loader.py
huanghuoguoguo 9908dc7800 style: fix unused imports after ruff auto-fix
Remove unused imports in test files:
- test_config_loader.py: remove unused os
- test_taskmgr.py: remove unused Mock
- test_preproc.py: remove unused unsupported_query, image_chain

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 10:12:48 +08:00

309 lines
9.1 KiB
Python

"""
Unit tests for configuration loading and overrides.
Tests cover:
- Valid YAML config loading
- Valid JSON config loading
- Invalid YAML/JSON error behavior
- Missing config file behavior
- Template completion
"""
from __future__ import annotations
import pytest
import json
from langbot.pkg.config.impls.yaml import YAMLConfigFile
from langbot.pkg.config.impls.json import JSONConfigFile
from langbot.pkg.config.manager import ConfigManager
class TestYAMLConfigFile:
"""Tests for YAML config file handling."""
@pytest.mark.asyncio
async def test_valid_yaml_loads(self, tmp_path):
"""Valid YAML config should load correctly."""
config_file = tmp_path / "test_config.yaml"
# Write valid YAML
config_file.write_text("""
name: test_app
version: 1.0
settings:
debug: true
port: 8080
""")
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'default', 'version': '0.1'},
)
result = await yaml_file.load(completion=False)
assert result['name'] == 'test_app'
assert result['version'] == 1.0
assert result['settings']['debug'] is True
assert result['settings']['port'] == 8080
@pytest.mark.asyncio
async def test_invalid_yaml_raises_error(self, tmp_path):
"""Invalid YAML should raise clear error."""
config_file = tmp_path / "invalid.yaml"
# Write invalid YAML (unclosed bracket)
config_file.write_text("""
name: test
settings:
- item1
- item2
- [unclosed
""")
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'default'},
)
with pytest.raises(Exception, match="Syntax error"):
await yaml_file.load(completion=False)
@pytest.mark.asyncio
async def test_missing_config_creates_from_template(self, tmp_path):
"""Missing config file should be created from template."""
config_file = tmp_path / "new_config.yaml"
# File doesn't exist yet
assert not config_file.exists()
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'new_app', 'version': '1.0'},
)
result = await yaml_file.load()
assert config_file.exists()
assert result['name'] == 'new_app'
assert result['version'] == '1.0'
@pytest.mark.asyncio
async def test_template_completion(self, tmp_path):
"""Config should be completed with template defaults."""
config_file = tmp_path / "partial.yaml"
# Write partial config missing some template keys
config_file.write_text("""
name: custom_name
""")
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'default_name', 'version': '2.0', 'debug': False},
)
result = await yaml_file.load(completion=True)
# Existing key preserved
assert result['name'] == 'custom_name'
# Missing keys filled from template
assert result['version'] == '2.0'
assert result['debug'] is False
@pytest.mark.asyncio
async def test_yaml_save(self, tmp_path):
"""YAML config can be saved."""
config_file = tmp_path / "save_test.yaml"
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'test'},
)
await yaml_file.save({'name': 'saved_app', 'new_key': 'new_value'})
assert config_file.exists()
content = config_file.read_text()
assert 'saved_app' in content
assert 'new_key' in content
def test_yaml_save_sync(self, tmp_path):
"""YAML config can be saved synchronously."""
config_file = tmp_path / "sync_save.yaml"
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'test'},
)
yaml_file.save_sync({'name': 'sync_saved'})
assert config_file.exists()
content = config_file.read_text()
assert 'sync_saved' in content
class TestJSONConfigFile:
"""Tests for JSON config file handling."""
@pytest.mark.asyncio
async def test_valid_json_loads(self, tmp_path):
"""Valid JSON config should load correctly."""
config_file = tmp_path / "test_config.json"
# Write valid JSON
config_file.write_text(json.dumps({
'name': 'json_app',
'version': '1.0',
'settings': {'debug': True, 'port': 8080},
}))
json_file = JSONConfigFile(
str(config_file),
template_data={'name': 'default', 'version': '0.1'},
)
result = await json_file.load(completion=False)
assert result['name'] == 'json_app'
assert result['version'] == '1.0'
assert result['settings']['debug'] is True
@pytest.mark.asyncio
async def test_invalid_json_raises_error(self, tmp_path):
"""Invalid JSON should raise clear error."""
config_file = tmp_path / "invalid.json"
# Write invalid JSON (missing closing brace)
config_file.write_text('{"name": "test", "unclosed": ')
json_file = JSONConfigFile(
str(config_file),
template_data={'name': 'default'},
)
with pytest.raises(Exception, match="Syntax error"):
await json_file.load(completion=False)
@pytest.mark.asyncio
async def test_missing_json_creates_from_template(self, tmp_path):
"""Missing JSON file should be created from template."""
config_file = tmp_path / "new_config.json"
json_file = JSONConfigFile(
str(config_file),
template_data={'name': 'new_json_app', 'version': '1.0'},
)
result = await json_file.load()
assert config_file.exists()
assert result['name'] == 'new_json_app'
@pytest.mark.asyncio
async def test_json_save(self, tmp_path):
"""JSON config can be saved."""
config_file = tmp_path / "save_test.json"
json_file = JSONConfigFile(
str(config_file),
template_data={'name': 'test'},
)
await json_file.save({'name': 'saved_json', 'new_key': 'value'})
assert config_file.exists()
content = config_file.read_text()
data = json.loads(content)
assert data['name'] == 'saved_json'
class TestConfigManager:
"""Tests for ConfigManager."""
@pytest.mark.asyncio
async def test_config_manager_load(self, tmp_path):
"""ConfigManager loads config correctly."""
config_file = tmp_path / "manager_test.yaml"
config_file.write_text('name: managed_app\nversion: "1.0"\n')
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'default', 'version': '0.1'},
)
manager = ConfigManager(yaml_file)
await manager.load_config()
assert manager.data['name'] == 'managed_app'
assert manager.data['version'] == '1.0'
@pytest.mark.asyncio
async def test_config_manager_dump(self, tmp_path):
"""ConfigManager can dump config."""
config_file = tmp_path / "dump_test.yaml"
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'default'},
)
manager = ConfigManager(yaml_file)
manager.data = {'name': 'dumped', 'new_field': 'value'}
await manager.dump_config()
content = config_file.read_text()
assert 'dumped' in content
def test_config_manager_dump_sync(self, tmp_path):
"""ConfigManager can dump config synchronously."""
config_file = tmp_path / "sync_dump.yaml"
yaml_file = YAMLConfigFile(
str(config_file),
template_data={'name': 'default'},
)
manager = ConfigManager(yaml_file)
manager.data = {'name': 'sync_dumped'}
manager.dump_config_sync()
assert config_file.exists()
class TestConfigExists:
"""Tests for config file existence check."""
def test_yaml_exists_true(self, tmp_path):
"""exists() returns True for existing file."""
config_file = tmp_path / "exists.yaml"
config_file.write_text('name: test')
yaml_file = YAMLConfigFile(str(config_file), template_data={})
assert yaml_file.exists() is True
def test_yaml_exists_false(self, tmp_path):
"""exists() returns False for missing file."""
config_file = tmp_path / "missing.yaml"
yaml_file = YAMLConfigFile(str(config_file), template_data={})
assert yaml_file.exists() is False
def test_json_exists_true(self, tmp_path):
"""exists() returns True for existing JSON file."""
config_file = tmp_path / "exists.json"
config_file.write_text('{}')
json_file = JSONConfigFile(str(config_file), template_data={})
assert json_file.exists() is True
def test_json_exists_false(self, tmp_path):
"""exists() returns False for missing JSON file."""
config_file = tmp_path / "missing.json"
json_file = JSONConfigFile(str(config_file), template_data={})
assert json_file.exists() is False