""" Unit tests for league configuration system. Tests: - Config loading and registry - Config immutability - Abstract method implementations - League-specific settings """ import pytest from pydantic import ValidationError from app.config import ( BaseGameConfig, SbaConfig, PdConfig, LEAGUE_CONFIGS, get_league_config ) class TestBaseGameConfig: """Tests for BaseGameConfig abstract class.""" def test_cannot_instantiate_abstract_base(self): """BaseGameConfig cannot be instantiated directly.""" with pytest.raises(TypeError): BaseGameConfig(league_id="test") class TestSbaConfig: """Tests for SBA league configuration.""" def test_sba_config_creation(self): """Can create SBA config instance.""" config = SbaConfig() assert config.league_id == "sba" assert config.version == "1.0.0" def test_sba_basic_rules(self): """SBA uses standard baseball rules.""" config = SbaConfig() assert config.innings == 9 assert config.outs_per_inning == 3 assert config.strikes_for_out == 3 assert config.balls_for_walk == 4 def test_sba_result_chart_name(self): """SBA uses sba_standard_v1 chart.""" config = SbaConfig() assert config.get_result_chart_name() == "sba_standard_v1" def test_sba_supports_manual_selection(self): """SBA supports manual result selection.""" config = SbaConfig() assert config.supports_manual_result_selection() is True def test_sba_api_url(self): """SBA API URL is correct.""" config = SbaConfig() assert config.get_api_base_url() == "https://api.sba.manticorum.com" def test_sba_player_selection_mode(self): """SBA uses manual player selection.""" config = SbaConfig() assert config.player_selection_mode == "manual" def test_sba_config_is_immutable(self): """Config cannot be modified after creation.""" config = SbaConfig() with pytest.raises(ValidationError): config.innings = 7 class TestPdConfig: """Tests for PD league configuration.""" def test_pd_config_creation(self): """Can create PD config instance.""" config = PdConfig() assert config.league_id == "pd" assert config.version == "1.0.0" def test_pd_basic_rules(self): """PD uses standard baseball rules.""" config = PdConfig() assert config.innings == 9 assert config.outs_per_inning == 3 assert config.strikes_for_out == 3 assert config.balls_for_walk == 4 def test_pd_result_chart_name(self): """PD uses pd_standard_v1 chart.""" config = PdConfig() assert config.get_result_chart_name() == "pd_standard_v1" def test_pd_supports_manual_selection(self): """PD supports manual result selection (though auto is also available).""" config = PdConfig() assert config.supports_manual_result_selection() is True def test_pd_api_url(self): """PD API URL is correct.""" config = PdConfig() assert config.get_api_base_url() == "https://pd.manticorum.com/api/" def test_pd_player_selection_mode(self): """PD uses flexible player selection.""" config = PdConfig() assert config.player_selection_mode == "flexible" def test_pd_scouting_model_enabled(self): """PD has scouting model enabled.""" config = PdConfig() assert config.use_scouting_model is True def test_pd_cardset_validation_enabled(self): """PD has cardset validation enabled.""" config = PdConfig() assert config.cardset_validation is True def test_pd_advanced_analytics_enabled(self): """PD has advanced analytics enabled.""" config = PdConfig() assert config.detailed_analytics is True assert config.wpa_calculation is True def test_pd_config_is_immutable(self): """Config cannot be modified after creation.""" config = PdConfig() with pytest.raises(ValidationError): config.use_scouting_model = False class TestLeagueRegistry: """Tests for league config registry and getter.""" def test_registry_contains_both_leagues(self): """Registry has both SBA and PD configs.""" assert "sba" in LEAGUE_CONFIGS assert "pd" in LEAGUE_CONFIGS assert len(LEAGUE_CONFIGS) == 2 def test_registry_configs_are_correct_type(self): """Registry contains correct config types.""" assert isinstance(LEAGUE_CONFIGS["sba"], SbaConfig) assert isinstance(LEAGUE_CONFIGS["pd"], PdConfig) def test_get_sba_config(self): """Can get SBA config via getter.""" config = get_league_config("sba") assert isinstance(config, SbaConfig) assert config.league_id == "sba" def test_get_pd_config(self): """Can get PD config via getter.""" config = get_league_config("pd") assert isinstance(config, PdConfig) assert config.league_id == "pd" def test_get_invalid_league_raises(self): """Getting invalid league raises ValueError.""" with pytest.raises(ValueError) as exc_info: get_league_config("invalid") assert "Unknown league: invalid" in str(exc_info.value) assert "sba" in str(exc_info.value) assert "pd" in str(exc_info.value) def test_registry_returns_same_instance(self): """Registry returns singleton instances.""" config1 = get_league_config("sba") config2 = get_league_config("sba") assert config1 is config2 class TestConfigDifferences: """Tests for differences between league configs.""" def test_different_result_charts(self): """SBA and PD use different result charts.""" sba = get_league_config("sba") pd = get_league_config("pd") assert sba.get_result_chart_name() != pd.get_result_chart_name() def test_different_api_urls(self): """SBA and PD have different API URLs.""" sba = get_league_config("sba") pd = get_league_config("pd") assert sba.get_api_base_url() != pd.get_api_base_url() def test_different_player_selection_modes(self): """SBA and PD have different selection modes.""" sba = get_league_config("sba") pd = get_league_config("pd") assert sba.player_selection_mode == "manual" assert pd.player_selection_mode == "flexible" def test_pd_has_extra_features(self): """PD has features that SBA doesn't.""" pd = get_league_config("pd") sba = get_league_config("sba") # PD-specific attributes assert hasattr(pd, 'use_scouting_model') assert hasattr(pd, 'cardset_validation') assert hasattr(pd, 'detailed_analytics') # SBA doesn't have these (or they're False/None) assert not hasattr(sba, 'use_scouting_model') assert not hasattr(sba, 'cardset_validation')