Spaces:
Running on Zero
Running on Zero
| """Tests for config loader.""" | |
| import os | |
| import tempfile | |
| from pathlib import Path | |
| from unittest.mock import patch | |
| import pytest | |
| import yaml | |
| from src.config_loader import ConfigLoader, get_config, reload_config | |
| def temp_config(): | |
| """Create a temporary config file.""" | |
| config_data = { | |
| "llm": { | |
| "model": "test-model", | |
| "temperature": 0.5, | |
| }, | |
| "profile": { | |
| "name": "Test User", | |
| "title": "Test Title", | |
| }, | |
| "logging": { | |
| "level": "INFO", | |
| "format": "%(message)s", | |
| }, | |
| "nested": { | |
| "level1": { | |
| "level2": "deep_value", | |
| } | |
| }, | |
| } | |
| with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: | |
| yaml.dump(config_data, f) | |
| config_path = f.name | |
| yield config_path | |
| # Cleanup | |
| os.unlink(config_path) | |
| # --- ConfigLoader Tests --- | |
| def test_config_loader_initialization(): | |
| """Test that ConfigLoader initializes properly.""" | |
| config = ConfigLoader() | |
| assert config is not None | |
| assert config.config is not None | |
| def test_config_loader_with_custom_path(temp_config): | |
| """Test ConfigLoader with custom config path.""" | |
| config = ConfigLoader(config_path=temp_config) | |
| assert config.get("llm.model") == "test-model" | |
| assert config.get("llm.temperature") == 0.5 | |
| def test_config_loader_missing_config_raises(): | |
| """Test ConfigLoader raises for missing config file.""" | |
| with pytest.raises(FileNotFoundError, match="Configuration file not found"): | |
| ConfigLoader(config_path="/nonexistent/config.yaml") | |
| def test_get_nested_config(): | |
| """Test getting nested configuration values.""" | |
| config = ConfigLoader() | |
| # Test nested access | |
| model = config.get("llm.model") | |
| assert model is not None | |
| # Test default value | |
| nonexistent = config.get("nonexistent.key", "default_value") | |
| assert nonexistent == "default_value" | |
| def test_get_deeply_nested_config(temp_config): | |
| """Test getting deeply nested values.""" | |
| config = ConfigLoader(config_path=temp_config) | |
| value = config.get("nested.level1.level2") | |
| assert value == "deep_value" | |
| def test_get_non_dict_intermediate(temp_config): | |
| """Test get returns default when intermediate key is not a dict.""" | |
| config = ConfigLoader(config_path=temp_config) | |
| # llm.model is a string, not a dict | |
| value = config.get("llm.model.invalid", "default") | |
| assert value == "default" | |
| def test_get_env(): | |
| """Test getting environment variables.""" | |
| config = ConfigLoader() | |
| # Test with existing env var | |
| with patch.dict(os.environ, {"TEST_VAR": "test_value"}): | |
| value = config.get_env("TEST_VAR") | |
| assert value == "test_value" | |
| # Test with default | |
| value = config.get_env("NONEXISTENT_VAR", "default") | |
| assert value == "default" | |
| def test_format_template(): | |
| """Test template formatting with profile info.""" | |
| config = ConfigLoader() | |
| template = "Hello, I'm {name}, a {title}" | |
| formatted = config.format_template(template) | |
| assert "{name}" not in formatted | |
| assert "{title}" not in formatted | |
| def test_format_template_with_custom_config(temp_config): | |
| """Test template formatting with custom config.""" | |
| config = ConfigLoader(config_path=temp_config) | |
| template = "Hello, I'm {name}, a {title}" | |
| formatted = config.format_template(template) | |
| assert "Test User" in formatted | |
| assert "Test Title" in formatted | |
| def test_format_template_missing_profile(): | |
| """Test template formatting with missing profile uses defaults.""" | |
| config_data = {"llm": {"model": "test"}} | |
| with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: | |
| yaml.dump(config_data, f) | |
| config_path = f.name | |
| try: | |
| config = ConfigLoader(config_path=config_path) | |
| template = "Hello, I'm {name}, a {title}" | |
| formatted = config.format_template(template) | |
| assert "the candidate" in formatted | |
| assert "professional" in formatted | |
| finally: | |
| os.unlink(config_path) | |
| def test_config_property(temp_config): | |
| """Test config property returns full config dict.""" | |
| config = ConfigLoader(config_path=temp_config) | |
| full_config = config.config | |
| assert isinstance(full_config, dict) | |
| assert "llm" in full_config | |
| assert "profile" in full_config | |
| def test_load_env_from_file(): | |
| """Test loading environment from .env file.""" | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| env_path = Path(tmpdir) / ".env" | |
| env_path.write_text("TEST_ENV_VAR=loaded_value\n") | |
| config_path = Path(tmpdir) / "config.yaml" | |
| config_path.write_text("llm:\n model: test\n") | |
| # Change to temp directory to test .env loading | |
| original_cwd = os.getcwd() | |
| try: | |
| os.chdir(tmpdir) | |
| # Load the config which should trigger .env loading | |
| ConfigLoader(config_path=str(config_path), env_path=str(env_path)) | |
| # The value should be loaded from .env | |
| value = os.getenv("TEST_ENV_VAR") | |
| assert value == "loaded_value" | |
| finally: | |
| os.chdir(original_cwd) | |
| # Clean up env var | |
| os.environ.pop("TEST_ENV_VAR", None) | |
| def test_load_env_missing_uses_template(): | |
| """Test loading environment falls back to env.template.""" | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| config_path = Path(tmpdir) / "config.yaml" | |
| config_path.write_text("llm:\n model: test\n") | |
| original_cwd = os.getcwd() | |
| try: | |
| os.chdir(tmpdir) | |
| # No .env file, no env.template - should just log warning | |
| config = ConfigLoader( | |
| config_path=str(config_path), | |
| env_path=str(Path(tmpdir) / "nonexistent.env"), | |
| ) | |
| assert config is not None | |
| finally: | |
| os.chdir(original_cwd) | |
| # --- Singleton Function Tests --- | |
| def test_get_config_singleton(): | |
| """Test get_config returns singleton instance.""" | |
| config1 = get_config() | |
| config2 = get_config() | |
| assert config1 is config2 | |
| def test_reload_config(): | |
| """Test reload_config creates new instance.""" | |
| # Get initial config | |
| get_config() | |
| # Reload and verify new instance | |
| config2 = reload_config() | |
| # reload_config creates a new instance | |
| assert config2 is not None | |
| assert isinstance(config2, ConfigLoader) | |