portfolio-optimization-python / tests /test_solver_config.py
blackopsrepl's picture
.
d9f5c15
"""
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