Files
cutThenThink/tests/test_settings.py

353 lines
11 KiB
Python
Raw Normal View History

"""
配置管理模块测试
"""
import pytest
import tempfile
import shutil
from pathlib import Path
from src.config.settings import (
Settings,
SettingsManager,
AIConfig,
OCRConfig,
CloudStorageConfig,
UIConfig,
Hotkey,
AdvancedConfig,
AIProvider,
OCRMode,
CloudStorageType,
Theme,
ConfigError,
get_config,
get_settings
)
class TestAIConfig:
"""测试 AI 配置"""
def test_default_config(self):
"""测试默认配置"""
config = AIConfig()
assert config.provider == AIProvider.ANTHROPIC
assert config.model == "claude-3-5-sonnet-20241022"
assert config.temperature == 0.7
assert config.max_tokens == 4096
def test_validation_success(self):
"""测试验证成功"""
config = AIConfig(
provider=AIProvider.OPENAI,
api_key="sk-test",
temperature=1.0,
max_tokens=2048
)
config.validate() # 不应抛出异常
def test_validation_missing_api_key(self):
"""测试缺少 API key"""
config = AIConfig(provider=AIProvider.OPENAI, api_key="")
with pytest.raises(ConfigError, match="API key"):
config.validate()
def test_validation_invalid_temperature(self):
"""测试无效的 temperature"""
config = AIConfig(temperature=3.0)
with pytest.raises(ConfigError, match="temperature"):
config.validate()
def test_validation_invalid_max_tokens(self):
"""测试无效的 max_tokens"""
config = AIConfig(max_tokens=0)
with pytest.raises(ConfigError, match="max_tokens"):
config.validate()
class TestOCRConfig:
"""测试 OCR 配置"""
def test_default_config(self):
"""测试默认配置"""
config = OCRConfig()
assert config.mode == OCRMode.LOCAL
assert config.lang == "ch"
assert config.use_gpu is False
def test_cloud_mode_validation(self):
"""测试云端模式验证"""
config = OCRConfig(mode=OCRMode.CLOUD, api_endpoint="")
with pytest.raises(ConfigError, match="api_endpoint"):
config.validate()
class TestCloudStorageConfig:
"""测试云存储配置"""
def test_default_config(self):
"""测试默认配置"""
config = CloudStorageConfig()
assert config.type == CloudStorageType.NONE
def test_no_storage_skip_validation(self):
"""测试不使用云存储时跳过验证"""
config = CloudStorageConfig(type=CloudStorageType.NONE)
config.validate() # 不应抛出异常
def test_s3_validation_success(self):
"""测试 S3 配置验证成功"""
config = CloudStorageConfig(
type=CloudStorageType.S3,
endpoint="https://s3.amazonaws.com",
access_key="test-key",
secret_key="test-secret",
bucket="test-bucket"
)
config.validate() # 不应抛出异常
def test_storage_validation_missing_endpoint(self):
"""测试缺少 endpoint"""
config = CloudStorageConfig(
type=CloudStorageType.S3,
endpoint=""
)
with pytest.raises(ConfigError, match="endpoint"):
config.validate()
def test_storage_validation_missing_credentials(self):
"""测试缺少凭证"""
config = CloudStorageConfig(
type=CloudStorageType.S3,
endpoint="https://s3.amazonaws.com",
access_key="",
secret_key=""
)
with pytest.raises(ConfigError, match="access_key.*secret_key"):
config.validate()
class TestUIConfig:
"""测试界面配置"""
def test_default_config(self):
"""测试默认配置"""
config = UIConfig()
assert config.theme == Theme.AUTO
assert config.language == "zh_CN"
assert config.window_width == 1200
assert config.window_height == 800
def test_hotkeys_default(self):
"""测试默认快捷键"""
config = UIConfig()
assert config.hotkeys.screenshot == "Ctrl+Shift+A"
assert config.hotkeys.ocr == "Ctrl+Shift+O"
def test_validation_invalid_size(self):
"""测试无效窗口大小"""
config = UIConfig(window_width=300)
with pytest.raises(ConfigError, match="window_width"):
config.validate()
class TestAdvancedConfig:
"""测试高级配置"""
def test_default_config(self):
"""测试默认配置"""
config = AdvancedConfig()
assert config.debug_mode is False
assert config.log_level == "INFO"
assert config.max_log_size == 10
def test_invalid_log_level(self):
"""测试无效的日志级别"""
config = AdvancedConfig(log_level="INVALID")
with pytest.raises(ConfigError, match="log_level"):
config.validate()
class TestSettings:
"""测试主配置类"""
def test_default_settings(self):
"""测试默认配置"""
settings = Settings()
assert isinstance(settings.ai, AIConfig)
assert isinstance(settings.ocr, OCRConfig)
assert isinstance(settings.cloud_storage, CloudStorageConfig)
assert isinstance(settings.ui, UIConfig)
assert isinstance(settings.advanced, AdvancedConfig)
def test_validate_all(self):
"""测试验证所有配置"""
settings = Settings()
settings.validate() # 默认配置应该验证通过
def test_to_dict(self):
"""测试转换为字典"""
settings = Settings()
data = settings.to_dict()
assert 'ai' in data
assert 'ocr' in data
assert 'cloud_storage' in data
assert 'ui' in data
assert 'advanced' in data
def test_from_dict(self):
"""测试从字典创建"""
data = {
'ai': {'provider': 'openai', 'api_key': 'sk-test', 'model': 'gpt-4'},
'ocr': {'mode': 'local', 'use_gpu': True},
'cloud_storage': {'type': 'none'},
'ui': {'theme': 'dark', 'language': 'en_US'},
'advanced': {'debug_mode': True}
}
settings = Settings.from_dict(data)
assert settings.ai.provider == AIProvider.OPENAI
assert settings.ai.api_key == 'sk-test'
assert settings.ai.model == 'gpt-4'
assert settings.ocr.use_gpu is True
assert settings.ui.theme == Theme.DARK
assert settings.ui.language == 'en_US'
assert settings.advanced.debug_mode is True
class TestSettingsManager:
"""测试配置管理器"""
@pytest.fixture
def temp_config_dir(self):
"""创建临时配置目录"""
temp_dir = Path(tempfile.mkdtemp())
yield temp_dir
shutil.rmtree(temp_dir)
@pytest.fixture
def config_file(self, temp_config_dir):
"""创建临时配置文件路径"""
return temp_config_dir / 'test_config.yaml'
def test_create_default_config(self, config_file):
"""测试创建默认配置文件"""
manager = SettingsManager(config_file)
settings = manager.load()
assert isinstance(settings, Settings)
assert config_file.exists()
# 读取文件内容验证
with open(config_file, 'r', encoding='utf-8') as f:
content = f.read()
assert 'ai:' in content
assert 'ocr:' in content
def test_save_and_load(self, config_file):
"""测试保存和加载"""
manager = SettingsManager(config_file)
# 创建自定义配置
settings = Settings()
settings.ai.provider = AIProvider.OPENAI
settings.ai.api_key = "sk-test-key"
settings.ui.theme = Theme.DARK
settings.ui.window_width = 1400
# 保存
manager.save(settings)
# 重新加载
manager2 = SettingsManager(config_file)
loaded_settings = manager2.load()
assert loaded_settings.ai.provider == AIProvider.OPENAI
assert loaded_settings.ai.api_key == "sk-test-key"
assert loaded_settings.ui.theme == Theme.DARK
assert loaded_settings.ui.window_width == 1400
def test_reset_config(self, config_file):
"""测试重置配置"""
manager = SettingsManager(config_file)
# 修改配置
settings = manager.settings
settings.ai.provider = AIProvider.OPENAI
settings.ai.api_key = "sk-test"
manager.save()
# 重置
manager.reset()
assert manager.settings.ai.provider == AIProvider.ANTHROPIC
def test_get_nested_value(self, config_file):
"""测试获取嵌套配置值"""
manager = SettingsManager(config_file)
assert manager.get('ai.provider') == AIProvider.ANTHROPIC
assert manager.get('ui.theme') == Theme.AUTO
assert manager.get('ui.hotkeys.screenshot') == "Ctrl+Shift+A"
assert manager.get('nonexistent.key', 'default') == 'default'
def test_set_nested_value(self, config_file):
"""测试设置嵌套配置值"""
manager = SettingsManager(config_file)
manager.set('ai.provider', AIProvider.OPENAI)
manager.set('ai.temperature', 1.5)
manager.set('ui.theme', Theme.DARK)
manager.set('ui.window_width', 1600)
assert manager.settings.ai.provider == AIProvider.OPENAI
assert manager.settings.ai.temperature == 1.5
assert manager.settings.ui.theme == Theme.DARK
assert manager.settings.ui.window_width == 1600
# 重新加载验证持久化
manager2 = SettingsManager(config_file)
assert manager2.settings.ai.provider == AIProvider.OPENAI
assert manager2.settings.ui.window_width == 1600
def test_set_invalid_path(self, config_file):
"""测试设置无效路径"""
manager = SettingsManager(config_file)
with pytest.raises(ConfigError, match="配置路径无效"):
manager.set('invalid.path.value', 'test')
def test_lazy_loading(self, config_file):
"""测试懒加载"""
manager = SettingsManager(config_file)
# 首次访问应该触发加载
assert manager._settings is None
_ = manager.settings
assert manager._settings is not None
# 后续访问应使用缓存
_ = manager.settings
assert manager._settings is not None
def test_get_settings_singleton(temp_config_dir):
"""测试全局配置单例"""
import tempfile
import shutil
config_path = temp_config_dir / 'global_config.yaml'
# 首次调用
manager1 = get_config(config_path)
# 加载配置
_ = manager1.settings
# 第二次调用应返回同一实例
manager2 = get_config()
assert manager1 is manager2
# 清理全局单例以避免影响其他测试
from src.config import settings
settings._global_settings_manager = None