"""Tests for #794 СберИндекс time-adjustment helper — pure, no DB.""" from __future__ import annotations import os import sys from datetime import date from unittest.mock import MagicMock # DATABASE_URL required by pydantic Settings before any app import. os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test") # WeasyPrint stub — not installed in CI без GTK. sys.modules.setdefault("weasyprint", MagicMock()) from app.services.estimator import ( # noqa: E402 SBER_TIME_FACTOR_MAX, SBER_TIME_FACTOR_MIN, _sber_time_factor, ) def test_empty_series_returns_one() -> None: assert _sber_time_factor({}, date(2026, 1, 1)) == 1.0 def test_deal_month_equals_latest_returns_one() -> None: series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0} assert _sber_time_factor(series, date(2026, 4, 1)) == 1.0 def test_deal_month_after_latest_returns_one() -> None: series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0} assert _sber_time_factor(series, date(2026, 6, 1)) == 1.0 def test_normal_factor_calculation() -> None: series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0} factor = _sber_time_factor(series, date(2026, 1, 1)) expected = 100_000.0 / 95_000.0 # ≈ 1.0526 assert abs(factor - expected) < 0.0001 assert SBER_TIME_FACTOR_MIN <= factor <= SBER_TIME_FACTOR_MAX def test_clamp_high() -> None: """Very old deal → factor would be >>1.6 → clamp to SBER_TIME_FACTOR_MAX.""" series = {date(2020, 1, 1): 10_000.0, date(2026, 4, 1): 100_000.0} factor = _sber_time_factor(series, date(2020, 1, 1)) assert factor == SBER_TIME_FACTOR_MAX def test_clamp_low() -> None: """Series shows price drop → factor <<0.7 → clamp to SBER_TIME_FACTOR_MIN.""" series = {date(2020, 1, 1): 200_000.0, date(2026, 4, 1): 50_000.0} factor = _sber_time_factor(series, date(2020, 1, 1)) assert factor == SBER_TIME_FACTOR_MIN def test_missing_month_uses_nearest_earlier() -> None: """deal_month=2026-02 not in series; nearest earlier is 2026-01.""" series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0} # Using 2026-01 as base: factor = 100000/95000 factor_with_missing = _sber_time_factor(series, date(2026, 2, 1)) factor_explicit = _sber_time_factor(series, date(2026, 1, 1)) assert abs(factor_with_missing - factor_explicit) < 0.0001 def test_deal_older_than_series_uses_earliest() -> None: """Deal month before all series data → use earliest available month.""" series = {date(2023, 1, 1): 80_000.0, date(2026, 4, 1): 100_000.0} # deal at 2020-01 is before series start → base = series[2023-01] = 80000 factor = _sber_time_factor(series, date(2020, 1, 1)) expected = min(100_000.0 / 80_000.0, SBER_TIME_FACTOR_MAX) assert abs(factor - expected) < 0.0001 def test_zero_base_returns_one() -> None: """Zero index value in series → guard → return 1.0.""" series = {date(2026, 1, 1): 0.0, date(2026, 4, 1): 100_000.0} assert _sber_time_factor(series, date(2026, 1, 1)) == 1.0