summaryrefslogtreecommitdiff
path: root/backend/tests/test_wacc.py
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-06-29 01:37:14 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-06-29 01:37:14 -0700
commitd1ab727b9c4fa872e24a634f9deeee0f488975d6 (patch)
tree5ec6f44d7fa53b2e1d5bdad4be8cb6bfb82f928e /backend/tests/test_wacc.py
parent48b2b5c2aca5888e7c1e688b5f834df55bb31d2f (diff)
feat: add WACC service and tests
Diffstat (limited to 'backend/tests/test_wacc.py')
-rw-r--r--backend/tests/test_wacc.py102
1 files changed, 102 insertions, 0 deletions
diff --git a/backend/tests/test_wacc.py b/backend/tests/test_wacc.py
new file mode 100644
index 0000000..a7dffcd
--- /dev/null
+++ b/backend/tests/test_wacc.py
@@ -0,0 +1,102 @@
+import pandas as pd
+import pytest
+
+from app import main
+from app.services import data_service
+
+
+def quarterly_frame(rows: dict[str, list[float]]) -> pd.DataFrame:
+ columns = pd.to_datetime(["2025-12-31", "2025-09-30", "2025-06-30", "2025-03-31"])
+ return pd.DataFrame(rows, index=columns).T
+
+
+def test_ticker_wacc_computes_capm_wacc_when_data_is_available(monkeypatch: pytest.MonkeyPatch) -> None:
+ # Given: WACC inputs matching the reference Excel sheet.
+ data_service.WACC_CACHE.clear()
+ monkeypatch.setattr(
+ data_service,
+ "get_company_info",
+ lambda symbol: {"beta": 0.98, "marketCap": 45_500_000_000.0},
+ )
+ monkeypatch.setattr(data_service, "get_fast_info", lambda symbol: {})
+ monkeypatch.setattr(
+ data_service,
+ "get_balance_sheet",
+ lambda symbol, quarterly=False: quarterly_frame(
+ {
+ "Total Debt": [724_000_000.0] * 4,
+ "Cash And Cash Equivalents": [795_000_000.0] * 4,
+ }
+ ),
+ )
+ monkeypatch.setattr(
+ data_service,
+ "get_income_statement",
+ lambda symbol, quarterly=False: quarterly_frame(
+ {
+ "Interest Expense": [8_145_000.0] * 4,
+ "Tax Provision": [25_000_000.0] * 4,
+ "Pretax Income": [100_000_000.0] * 4,
+ }
+ ),
+ )
+
+ # When: the public route function is called.
+ result = main.ticker_wacc("ref")
+
+ # Then: it returns the CAPM WACC and all major inputs without live yfinance calls.
+ assert result["symbol"] == "REF"
+ assert result["available"] is True
+ assert result["wacc"] == pytest.approx(0.0979)
+ assert result["cost_of_equity"] == pytest.approx(0.0979)
+ assert result["cost_of_debt"] == pytest.approx(0.045)
+ assert result["tax_rate"] == pytest.approx(0.25)
+ assert result["currency"] == "USD"
+ assert result["currency_warning"] is None
+ assert result["market_cap"] == 45_500_000_000.0
+ assert result["total_debt"] == 724_000_000.0
+ assert result["cash"] == 795_000_000.0
+
+
+def test_ticker_wacc_returns_unavailable_when_market_cap_is_missing(monkeypatch: pytest.MonkeyPatch) -> None:
+ # Given: yfinance helpers return no usable capitalization data.
+ data_service.WACC_CACHE.clear()
+ monkeypatch.setattr(data_service, "get_company_info", lambda symbol: {})
+ monkeypatch.setattr(data_service, "get_fast_info", lambda symbol: {})
+ monkeypatch.setattr(data_service, "get_balance_sheet", lambda symbol, quarterly=False: pd.DataFrame())
+ monkeypatch.setattr(data_service, "get_income_statement", lambda symbol, quarterly=False: pd.DataFrame())
+
+ # When: the public route function is called for an invalid symbol.
+ result = main.ticker_wacc("missing")
+
+ # Then: the API responds gracefully with fallback assumptions and no WACC.
+ assert result["symbol"] == "MISSING"
+ assert result["available"] is False
+ assert result["wacc"] is None
+ assert result["risk_free_rate"] == 0.044
+ assert result["beta"] == 1.0
+ assert result["equity_risk_premium"] == 0.055
+ assert result["cost_of_debt"] == 0.05
+ assert result["tax_rate"] == 0.21
+ assert result["currency"] == "USD"
+ assert result["currency_warning"] is None
+ assert result["market_cap"] is None
+
+
+def test_wacc_currency_warning_when_mismatch(monkeypatch: pytest.MonkeyPatch) -> None:
+ data_service.WACC_CACHE.clear()
+ monkeypatch.setattr(
+ data_service,
+ "get_company_info",
+ lambda symbol: {"financialCurrency": "CAD", "currency": "USD", "marketCap": 45_500_000_000.0, "beta": 0.98},
+ )
+ monkeypatch.setattr(data_service, "get_fast_info", lambda symbol: {"currency": "USD"})
+ monkeypatch.setattr(data_service, "get_balance_sheet", lambda symbol, quarterly=False: pd.DataFrame())
+ monkeypatch.setattr(data_service, "get_income_statement", lambda symbol, quarterly=False: pd.DataFrame())
+
+ result = main.ticker_wacc("CCJ")
+
+ assert result["currency"] == "CAD"
+ assert isinstance(result["currency_warning"], str)
+ assert "USD" in result["currency_warning"]
+ assert "CAD" in result["currency_warning"]