""" Tests for solver configuration functionality. Tests the create_solver_config factory function and dynamic termination time. """ import pytest from portfolio_optimization.solver import create_solver_config from portfolio_optimization.domain import SolverConfigModel class TestCreateSolverConfig: """Tests for the create_solver_config factory function.""" def test_default_termination(self): """Default solver should terminate after 30 seconds.""" config = create_solver_config() assert config.termination_config.spent_limit.seconds == 30 def test_custom_termination_60s(self): """Custom termination time of 60 seconds should be respected.""" config = create_solver_config(termination_seconds=60) assert config.termination_config.spent_limit.seconds == 60 def test_custom_termination_10s(self): """Minimum termination time of 10 seconds should work.""" config = create_solver_config(termination_seconds=10) assert config.termination_config.spent_limit.seconds == 10 def test_custom_termination_300s(self): """Maximum termination time of 300 seconds (5 min) should work.""" config = create_solver_config(termination_seconds=300) assert config.termination_config.spent_limit.seconds == 300 def test_solver_config_has_correct_solution_class(self): """Solver config should reference PortfolioOptimizationPlan.""" from portfolio_optimization.domain import PortfolioOptimizationPlan config = create_solver_config() assert config.solution_class == PortfolioOptimizationPlan def test_solver_config_has_correct_entity_class(self): """Solver config should include StockSelection entity.""" from portfolio_optimization.domain import StockSelection config = create_solver_config() assert StockSelection in config.entity_class_list class TestSolverConfigModel: """Tests for the SolverConfigModel Pydantic model.""" def test_default_values(self): """SolverConfigModel should have default termination of 30 seconds.""" model = SolverConfigModel() assert model.termination_seconds == 30 def test_custom_termination(self): """SolverConfigModel should accept custom termination.""" model = SolverConfigModel(termination_seconds=60) assert model.termination_seconds == 60 def test_alias_serialization(self): """SolverConfigModel should serialize with camelCase alias.""" model = SolverConfigModel(termination_seconds=45) data = model.model_dump(by_alias=True) assert "terminationSeconds" in data assert data["terminationSeconds"] == 45 def test_alias_deserialization(self): """SolverConfigModel should deserialize from camelCase.""" model = SolverConfigModel.model_validate({"terminationSeconds": 90}) assert model.termination_seconds == 90 def test_minimum_validation(self): """SolverConfigModel should reject termination < 10 seconds.""" with pytest.raises(ValueError): SolverConfigModel(termination_seconds=5) def test_maximum_validation(self): """SolverConfigModel should reject termination > 300 seconds.""" with pytest.raises(ValueError): SolverConfigModel(termination_seconds=400) def test_boundary_min(self): """SolverConfigModel should accept exactly 10 seconds.""" model = SolverConfigModel(termination_seconds=10) assert model.termination_seconds == 10 def test_boundary_max(self): """SolverConfigModel should accept exactly 300 seconds.""" model = SolverConfigModel(termination_seconds=300) assert model.termination_seconds == 300