""" Tests for configuration management Ensures configuration loading, validation, and environment handling work correctly. """ import os import pytest from unittest.mock import patch from config import BotConfig class TestBotConfig: """Test configuration loading and validation.""" def test_config_loads_required_fields(self): """Test that config loads all required fields from environment.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }): config = BotConfig() assert config.bot_token == 'test_bot_token' assert config.guild_id == 123456789 assert config.api_token == 'test_api_token' assert config.db_url == 'https://api.example.com' def test_config_has_default_values(self): """Test that config provides sensible defaults.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }, clear=True): # Create config with disabled env file to test true defaults config = BotConfig(_env_file=None) assert config.sba_season == 13 assert config.pd_season == 10 assert config.fa_lock_week == 14 assert config.sba_color == "a6ce39" assert config.log_level == "INFO" assert config.environment == "development" assert config.testing is True def test_config_overrides_defaults_from_env(self): """Test that environment variables override default values.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'SBA_SEASON': '15', 'LOG_LEVEL': 'DEBUG', 'ENVIRONMENT': 'production', 'TESTING': 'true' }): config = BotConfig() assert config.sba_season == 15 assert config.log_level == "DEBUG" assert config.environment == "production" assert config.testing is True def test_config_ignores_extra_env_vars(self): """Test that extra environment variables are ignored.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'RANDOM_EXTRA_VAR': 'should_be_ignored', 'ANOTHER_RANDOM_VAR': 'also_ignored' }): # Should not raise validation error config = BotConfig() assert config.bot_token == 'test_bot_token' # Extra vars should not be accessible assert not hasattr(config, 'random_extra_var') assert not hasattr(config, 'another_random_var') def test_config_converts_string_to_int(self): """Test that guild_id is properly converted from string to int.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '987654321', # String input 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }): config = BotConfig() assert config.guild_id == 987654321 assert isinstance(config.guild_id, int) def test_config_converts_string_to_bool(self): """Test that boolean fields are properly converted.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'TESTING': 'false' }): config = BotConfig() assert config.testing is False assert isinstance(config.testing, bool) with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'TESTING': '1' }): config = BotConfig() assert config.testing is True def test_config_case_insensitive(self): """Test that environment variables are case insensitive.""" with patch.dict(os.environ, { 'bot_token': 'test_bot_token', # lowercase 'GUILD_ID': '123456789', # uppercase 'Api_Token': 'test_api_token', # mixed case 'db_url': 'https://api.example.com' }): config = BotConfig() assert config.bot_token == 'test_bot_token' assert config.api_token == 'test_api_token' assert config.db_url == 'https://api.example.com' def test_is_development_property(self): """Test the is_development property.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'ENVIRONMENT': 'development' }): config = BotConfig() assert config.is_development is True with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'ENVIRONMENT': 'production' }): config = BotConfig() assert config.is_development is False def test_is_testing_property(self): """Test the is_testing property.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'TESTING': 'true' }): config = BotConfig() assert config.is_testing is True with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com', 'TESTING': 'false' }): config = BotConfig() assert config.is_testing is False class TestConfigValidation: """Test configuration validation and error handling.""" def test_missing_required_field_raises_error(self): """Test that missing required fields raise validation errors.""" # Missing BOT_TOKEN with patch.dict(os.environ, { 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }, clear=True): with pytest.raises(Exception): # Pydantic ValidationError BotConfig(_env_file=None) # Missing GUILD_ID with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }, clear=True): with pytest.raises(Exception): # Pydantic ValidationError BotConfig(_env_file=None) def test_invalid_guild_id_raises_error(self): """Test that invalid guild_id values raise validation errors.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': 'not_a_number', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }): with pytest.raises(Exception): # Pydantic ValidationError BotConfig() def test_empty_required_field_is_allowed(self): """Test that empty required fields are allowed (Pydantic default behavior).""" with patch.dict(os.environ, { 'BOT_TOKEN': '', # Empty string 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }): # Should not raise - Pydantic allows empty strings by default config = BotConfig() assert config.bot_token == '' @pytest.fixture def valid_config(): """Provide a valid configuration for testing.""" with patch.dict(os.environ, { 'BOT_TOKEN': 'test_bot_token', 'GUILD_ID': '123456789', 'API_TOKEN': 'test_api_token', 'DB_URL': 'https://api.example.com' }): return BotConfig() def test_config_fixture(valid_config): """Test that the valid_config fixture works correctly.""" assert valid_config.bot_token == 'test_bot_token' assert valid_config.guild_id == 123456789 assert valid_config.api_token == 'test_api_token' assert valid_config.db_url == 'https://api.example.com'