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"]