"""Critical tests for configuration validation.""" import pytest from alfred.settings import ConfigurationError, Settings class TestConfigValidation: """Critical tests for config validation.""" def test_invalid_temperature_raises_error(self): """Verify invalid temperature is rejected.""" with pytest.raises(ConfigurationError, match="Temperature"): Settings(llm_temperature=3.0) # > 2.0 with pytest.raises(ConfigurationError, match="Temperature"): Settings(llm_temperature=-0.1) # < 0.0 def test_valid_temperature_accepted(self): """Verify valid temperature is accepted.""" # Should not raise Settings(llm_temperature=0.0) Settings(llm_temperature=1.0) Settings(llm_temperature=2.0) def test_invalid_max_iterations_raises_error(self): """Verify invalid max_iterations is rejected.""" with pytest.raises(ConfigurationError, match="max_tool_iterations"): Settings(max_tool_iterations=0) # < 1 with pytest.raises(ConfigurationError, match="max_tool_iterations"): Settings(max_tool_iterations=100) # > 20 def test_valid_max_iterations_accepted(self): """Verify valid max_iterations is accepted.""" # Should not raise Settings(max_tool_iterations=1) Settings(max_tool_iterations=10) Settings(max_tool_iterations=20) def test_invalid_timeout_raises_error(self): """Verify invalid timeout is rejected.""" with pytest.raises(ConfigurationError, match="request_timeout"): Settings(request_timeout=0) # < 1 with pytest.raises(ConfigurationError, match="request_timeout"): Settings(request_timeout=500) # > 300 def test_valid_timeout_accepted(self): """Verify valid timeout is accepted.""" # Should not raise Settings(request_timeout=1) Settings(request_timeout=30) Settings(request_timeout=300) def test_invalid_deepseek_url_raises_error(self): """Verify invalid DeepSeek URL is rejected.""" with pytest.raises(ConfigurationError, match="Invalid deepseek_base_url"): Settings(deepseek_base_url="not-a-url") with pytest.raises(ConfigurationError, match="Invalid deepseek_base_url"): Settings(deepseek_base_url="ftp://invalid.com") def test_valid_deepseek_url_accepted(self): """Verify valid DeepSeek URL is accepted.""" # Should not raise Settings(deepseek_base_url="https://api.deepseek.com") Settings(deepseek_base_url="http://localhost:8000") def test_invalid_tmdb_url_raises_error(self): """Verify invalid TMDB URL is rejected.""" with pytest.raises(ConfigurationError, match="Invalid tmdb_base_url"): Settings(tmdb_base_url="not-a-url") def test_valid_tmdb_url_accepted(self): """Verify valid TMDB URL is accepted.""" # Should not raise Settings(tmdb_base_url="https://api.themoviedb.org/3") Settings(tmdb_base_url="http://localhost:3000") class TestConfigChecks: """Tests for configuration check methods.""" def test_is_deepseek_configured_with_key(self): """Verify is_deepseek_configured returns True with API key.""" settings = Settings( deepseek_api_key="test-key", deepseek_base_url="https://api.test.com" ) assert settings.is_deepseek_configured() is True def test_is_deepseek_configured_without_key(self): """Verify is_deepseek_configured returns False without API key.""" settings = Settings( deepseek_api_key="", deepseek_base_url="https://api.test.com" ) assert settings.is_deepseek_configured() is False def test_is_deepseek_configured_without_url(self): """Verify is_deepseek_configured returns False without URL.""" # This will fail validation, so we can't test it directly # The validation happens in __post_init__ pass def test_is_tmdb_configured_with_key(self): """Verify is_tmdb_configured returns True with API key.""" settings = Settings( tmdb_api_key="test-key", tmdb_base_url="https://api.test.com" ) assert settings.is_tmdb_configured() is True def test_is_tmdb_configured_without_key(self): """Verify is_tmdb_configured returns False without API key.""" settings = Settings(tmdb_api_key="", tmdb_base_url="https://api.test.com") assert settings.is_tmdb_configured() is False class TestConfigDefaults: """Tests for configuration defaults.""" def test_default_temperature(self): """Verify default temperature is reasonable.""" settings = Settings() assert 0.0 <= settings.llm_temperature <= 2.0 def test_default_max_iterations(self): """Verify default max_iterations is reasonable.""" settings = Settings() assert 1 <= settings.max_tool_iterations <= 20 def test_default_timeout(self): """Verify default timeout is reasonable.""" settings = Settings() assert 1 <= settings.request_timeout <= 300 def test_default_urls_are_valid(self): """Verify default URLs are valid.""" settings = Settings() assert settings.deepseek_base_url.startswith(("http://", "https://")) assert settings.tmdb_base_url.startswith(("http://", "https://")) class TestConfigEnvironmentVariables: """Tests for environment variable loading.""" def test_loads_temperature_from_env(self, monkeypatch): """Verify temperature is loaded from environment.""" monkeypatch.setenv("LLM_TEMPERATURE", "0.5") settings = Settings() assert settings.llm_temperature == 0.5 def test_loads_max_iterations_from_env(self, monkeypatch): """Verify max_iterations is loaded from environment.""" monkeypatch.setenv("MAX_TOOL_ITERATIONS", "10") settings = Settings() assert settings.max_tool_iterations == 10 def test_loads_timeout_from_env(self, monkeypatch): """Verify timeout is loaded from environment.""" monkeypatch.setenv("REQUEST_TIMEOUT", "60") settings = Settings() assert settings.request_timeout == 60 def test_loads_deepseek_url_from_env(self, monkeypatch): """Verify DeepSeek URL is loaded from environment.""" monkeypatch.setenv("DEEPSEEK_BASE_URL", "https://custom.api.com") settings = Settings() assert settings.deepseek_base_url == "https://custom.api.com" def test_invalid_env_value_raises_error(self, monkeypatch): """Verify invalid environment value raises error.""" monkeypatch.setenv("LLM_TEMPERATURE", "invalid") with pytest.raises(ValueError): Settings()