summaryrefslogtreecommitdiff
path: root/backend/tests/test_wacc.py
blob: a7dffcd55abd072d67b91deaabf7b4c90346f098 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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"]