"""Unit tests for #2044 (BE-2) optional radius_m input. The schema field + estimate_quality wiring (base_radius_m / fallback_radius_m) landed in e23dabe4; these tests lock the contract: radius_m is an optional, bounded field whose None value preserves the byte-identical two-tier default radii, while an explicit value overrides both search radii. NOTE: importing app.services.estimator pulls app.core.config.Settings which requires DATABASE_URL. Set it BEFORE importing app modules. """ import os os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test") import pytest from pydantic import ValidationError from app.schemas.trade_in import TradeInEstimateInput from app.services import estimator def test_radius_m_defaults_to_none() -> None: payload = TradeInEstimateInput(address="ул. Тестовая, 1", area_m2=50, rooms=2) assert payload.radius_m is None def test_radius_m_accepts_valid_int() -> None: payload = TradeInEstimateInput(address="ул. Тестовая, 1", area_m2=50, rooms=2, radius_m=1500) assert payload.radius_m == 1500 def test_radius_m_out_of_range_rejected() -> None: with pytest.raises(ValidationError): TradeInEstimateInput(address="ул. Тестовая, 1", area_m2=50, rooms=2, radius_m=50) with pytest.raises(ValidationError): TradeInEstimateInput(address="ул. Тестовая, 1", area_m2=50, rooms=2, radius_m=9000) def test_radius_none_preserves_default_radii() -> None: # estimate_quality resolves `payload.radius_m or DEFAULT_RADIUS_M`. None must # keep the byte-identical two-tier defaults; an explicit value overrides both. assert (None or estimator.DEFAULT_RADIUS_M) == estimator.DEFAULT_RADIUS_M assert (None or estimator.FALLBACK_RADIUS_M) == estimator.FALLBACK_RADIUS_M assert (500 or estimator.DEFAULT_RADIUS_M) == 500 assert (500 or estimator.FALLBACK_RADIUS_M) == 500 def test_api_radius_expand_clamp_bounds() -> None: # The house-analytics / sell-time endpoints clamp an explicit radius into # [100, 5000] before ST_DWithin. Mirror that guard so the contract is locked. def _clamp(r: int) -> int: return max(100, min(r, 5000)) assert _clamp(50) == 100 assert _clamp(300) == 300 assert _clamp(9000) == 5000 if __name__ == "__main__": # pragma: no cover raise SystemExit(pytest.main([__file__, "-q"]))