amplegest / tests /test_financials.py
Viney's picture
fix: preserve None for masked fields in financials chart series instead of coercing to 0
273c984
Raw
History Blame Contribute Delete
10.2 kB
"""Tests for dashboard/financials.py — fiscal calendar robustness.
Each company has a different fiscal year end month:
AMD — December (fy_end_month=12)
MSFT — June (fy_end_month=6)
AAPL — September (fy_end_month=9) ← what the old hardcoded table assumed
NVDA — January (fy_end_month=1)
"""
from __future__ import annotations
from unittest.mock import patch
import pytest
# ---------------------------------------------------------------------------
# _quarter_label — pure-function tests (no Streamlit, no network)
# ---------------------------------------------------------------------------
class TestQuarterLabelAMD:
"""AMD fiscal year ends December."""
def test_q1_fy24(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-03-31", fy_end_month=12) == "Q1 FY24 · MAR"
def test_q2_fy24(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-06-30", fy_end_month=12) == "Q2 FY24 · JUN"
def test_q3_fy24(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-09-30", fy_end_month=12) == "Q3 FY24 · SEP"
def test_q4_fy24(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-12-31", fy_end_month=12) == "Q4 FY24 · DEC"
class TestQuarterLabelMSFT:
"""MSFT fiscal year ends June."""
def test_q1_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-09-30", fy_end_month=6) == "Q1 FY25 · SEP"
def test_q2_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-12-31", fy_end_month=6) == "Q2 FY25 · DEC"
def test_q3_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2025-03-31", fy_end_month=6) == "Q3 FY25 · MAR"
def test_q4_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2025-06-30", fy_end_month=6) == "Q4 FY25 · JUN"
class TestQuarterLabelAAPL:
"""AAPL fiscal year ends September — must match existing correct behavior."""
def test_q1_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-12-31", fy_end_month=9) == "Q1 FY25 · DEC"
def test_q2_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2025-03-31", fy_end_month=9) == "Q2 FY25 · MAR"
def test_q3_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2025-06-30", fy_end_month=9) == "Q3 FY25 · JUN"
def test_q4_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2025-09-30", fy_end_month=9) == "Q4 FY25 · SEP"
class TestQuarterLabelNVDA:
"""NVDA fiscal year ends January."""
def test_q1_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-04-30", fy_end_month=1) == "Q1 FY25 · APR"
def test_q2_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-07-31", fy_end_month=1) == "Q2 FY25 · JUL"
def test_q3_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2024-10-31", fy_end_month=1) == "Q3 FY25 · OCT"
def test_q4_fy25(self):
from dashboard.financials import _quarter_label
assert _quarter_label("2025-01-31", fy_end_month=1) == "Q4 FY25 · JAN"
class TestQuarterLabelEdgeCases:
def test_invalid_date_returns_raw_string(self):
"""Bad date string must not crash — returns original string."""
from dashboard.financials import _quarter_label
assert _quarter_label("not-a-date", fy_end_month=12) == "not-a-date"
def test_none_fy_end_month_returns_raw_date(self):
"""When fy_end_month is None (unknown), return the date string unchanged."""
from dashboard.financials import _quarter_label
result = _quarter_label("2024-06-30", fy_end_month=None)
assert result == "2024-06-30"
class TestFinancialDataQuality:
@staticmethod
def _row(period, filing_date, form_type, status="VERIFIED", warnings=None):
return {
"period": period,
"filing_date": filing_date,
"form_type": form_type,
"period_basis": "annual" if form_type == "10-K" else "quarter",
"revenue": 10_000_000_000.0,
"revenue_yoy_pct": 12.5,
"eps": 2.5,
"gross_margin": 0.6,
"operating_margin": 0.4,
"free_cash_flow": 3_000_000_000.0,
"data_quality_status": status,
"quality_warnings": warnings or [],
}
def test_display_rows_masks_check_required_fields_and_hides_legacy(self):
from dashboard.financials import _display_rows
rows = [
self._row(
"Q22025", "2025-08-01", "10-Q", "CHECK_REQUIRED",
["free_cash_flow:fallback_non_sec"],
),
self._row("Q12025", "2025-05-01", "10-Q"),
self._row("FY2024", "2024-11-01", "10-K", "LEGACY_UNVERIFIED"),
]
display_rows = _display_rows(rows)
assert [row["period"] for row in display_rows] == ["Q22025", "Q12025"]
partial = display_rows[0]
assert partial["free_cash_flow"] is None
assert partial["revenue"] == 10_000_000_000.0
assert partial["eps"] == 2.5
assert partial["_masked_fields"] == ["free_cash_flow"]
def test_display_row_masks_revenue_and_derived_yoy(self):
from dashboard.financials import _display_row
row = self._row(
"Q22025", "2025-08-01", "10-Q", "CHECK_REQUIRED",
["revenue:fallback_non_sec"],
)
displayed = _display_row(row)
assert displayed is not None
assert displayed["revenue"] is None
assert displayed["revenue_yoy_pct"] is None
assert displayed["eps"] == 2.5
assert displayed["_masked_fields"] == ["revenue", "revenue_yoy_pct"]
def test_display_row_hides_legacy_unverified(self):
from dashboard.financials import _display_row
legacy = self._row(
"FY2024", "2024-11-01", "10-K", "LEGACY_UNVERIFIED"
)
assert _display_row(legacy) is None
def test_comparable_prior_does_not_compare_annual_with_quarter(self):
from dashboard.financials import _comparable_prior
latest = self._row("FY2025", "2025-11-01", "10-K")
recent_quarter = self._row("Q32025", "2025-08-01", "10-Q")
prior_annual = self._row("FY2024", "2024-11-01", "10-K")
assert _comparable_prior(
[latest, recent_quarter, prior_annual], latest
)["period"] == "FY2024"
def test_comparable_prior_accepts_sanitized_check_required_lineage(self):
from dashboard.financials import _comparable_prior, _display_rows
latest = self._row("Q22025", "2025-08-01", "10-Q")
partial_prior = self._row(
"Q12025", "2025-05-01", "10-Q", "CHECK_REQUIRED",
["free_cash_flow:fallback_non_sec"],
)
rows = _display_rows([latest, partial_prior])
prior = _comparable_prior(rows, rows[0])
assert prior["period"] == "Q12025"
assert prior["free_cash_flow"] is None
assert prior["revenue"] == 10_000_000_000.0
def test_comparable_prior_requires_exact_adjacent_fiscal_period(self):
from dashboard.financials import _comparable_prior
latest = self._row("Q32025", "2025-11-01", "10-Q")
non_adjacent = self._row("Q12025", "2025-05-01", "10-Q")
assert _comparable_prior([latest, non_adjacent], latest) == {}
def test_masked_message_only_receives_fully_hidden_rows(self):
from dashboard.financials import _display_row, _masked_quality_message
partial = self._row(
"Q22025", "2025-08-01", "10-Q", "CHECK_REQUIRED",
["revenue:duration_mismatch"],
)
legacy = self._row(
"FY2024", "2024-11-01", "10-K", "LEGACY_UNVERIFIED"
)
masked_rows = [row for row in [partial, legacy] if _display_row(row) is None]
message = _masked_quality_message(masked_rows)
assert "FY2024: LEGACY_UNVERIFIED" in message
assert "Q22025" not in message
assert "revenue:duration_mismatch" not in message
assert "no citable SEC lineage" in message
assert "not VERIFIED" not in message
@patch("dashboard.financials.st.plotly_chart")
def test_chart_margins_preserves_masked_gross_margin_as_none(
self, mock_plotly_chart
):
from dashboard.financials import _chart_margins, _display_row
row = self._row(
"Q22025", "2025-08-01", "10-Q", "CHECK_REQUIRED",
["gross_margin:fallback_non_sec"],
)
displayed = _display_row(row)
assert displayed is not None
assert displayed["gross_margin"] is None
assert displayed["revenue"] == 10_000_000_000.0
assert displayed["eps"] == 2.5
_chart_margins(["Q2 FY25"], [displayed])
margins_figure = mock_plotly_chart.call_args_list[0].args[0]
assert list(margins_figure.data[0].y) == [None]
@patch("dashboard.financials.st.plotly_chart")
def test_chart_cash_preserves_masked_free_cash_flow_as_none(
self, mock_plotly_chart
):
from dashboard.financials import _chart_cash, _display_row
row = self._row(
"Q22025", "2025-08-01", "10-Q", "CHECK_REQUIRED",
["free_cash_flow:fallback_non_sec"],
)
displayed = _display_row(row)
assert displayed is not None
assert displayed["free_cash_flow"] is None
assert displayed["revenue"] == 10_000_000_000.0
assert displayed["eps"] == 2.5
_chart_cash(["Q2 FY25"], [displayed])
cash_figure = mock_plotly_chart.call_args_list[0].args[0]
assert list(cash_figure.data[0].y) == [None]