diff options
Diffstat (limited to 'backend/tests/test_api.py')
| -rw-r--r-- | backend/tests/test_api.py | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index 8c7edb8..66c021f 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -788,3 +788,112 @@ def test_run_price_to_book_zero_bvps() -> None: book_value_per_share=0.0, target_multiple=3.0 ) assert result == {} + + +def test_get_valuation_happy_path(monkeypatch) -> None: + clear_service_caches() + cf_a = annual_frame({ + "Operating Cash Flow": [100.0, 90.0, 80.0, 70.0], + "Capital Expenditure": [-10.0, -9.0, -8.0, -7.0], + }) + bal_q = quarterly_frame({ + "Total Debt": [50.0, 0.0, 0.0, 0.0], + "Cash And Cash Equivalents": [30.0, 0.0, 0.0, 0.0], + "Stockholders Equity": [400.0, 0.0, 0.0, 0.0], + }) + inc_q = quarterly_frame({ + "EBITDA": [30.0, 28.0, 32.0, 25.0], + "Total Revenue": [100.0, 90.0, 95.0, 85.0], + }) + monkeypatch.setattr(data_service, "get_cash_flow", + lambda sym, quarterly=False: pd.DataFrame() if quarterly else cf_a) + monkeypatch.setattr(data_service, "get_income_statement", + lambda sym, quarterly=False: inc_q) + monkeypatch.setattr(data_service, "get_balance_sheet", + lambda sym, quarterly=False: bal_q) + monkeypatch.setattr(data_service, "get_company_info", + lambda sym: {"currentPrice": 150.0, "enterpriseToEbitda": 15.0, + "enterpriseToRevenue": 5.0, "priceToBook": 3.0}) + monkeypatch.setattr(data_service, "get_shares_outstanding", + lambda sym: 1_000_000_000.0) + + result = data_service.get_valuation("AAPL") + assert result["symbol"] == "AAPL" + assert result["current_price"] == 150.0 + assert result["dcf"]["available"] is True + assert result["dcf"]["intrinsic_value_per_share"] is not None + assert result["dcf"]["wacc"] == 0.10 + assert result["dcf"]["terminal_growth"] == 0.03 + assert result["ev_ebitda"]["available"] is True + assert result["ev_ebitda"]["multiple_used"] == 15.0 + assert result["ev_revenue"]["available"] is True + assert result["price_to_book"]["available"] is True + + +def test_get_valuation_negative_base_fcf(monkeypatch) -> None: + clear_service_caches() + # Most recent year (2024) FCF is negative + cf_a = annual_frame({ + "Operating Cash Flow": [-50.0, 100.0, 90.0, 80.0], + "Capital Expenditure": [-5.0, -5.0, -5.0, -5.0], + }) + monkeypatch.setattr(data_service, "get_cash_flow", + lambda sym, quarterly=False: pd.DataFrame() if quarterly else cf_a) + monkeypatch.setattr(data_service, "get_income_statement", + lambda sym, quarterly=False: pd.DataFrame()) + monkeypatch.setattr(data_service, "get_balance_sheet", + lambda sym, quarterly=False: pd.DataFrame()) + monkeypatch.setattr(data_service, "get_company_info", + lambda sym: {"currentPrice": 100.0}) + monkeypatch.setattr(data_service, "get_shares_outstanding", + lambda sym: 1_000_000_000.0) + + result = data_service.get_valuation("AAPL") + assert result["dcf"]["available"] is True + assert result["dcf"]["error"] is not None + assert "negative" in result["dcf"]["error"].lower() or "zero" in result["dcf"]["error"].lower() + + +def test_get_valuation_no_cf_data(monkeypatch) -> None: + clear_service_caches() + monkeypatch.setattr(data_service, "get_cash_flow", + lambda sym, quarterly=False: pd.DataFrame()) + monkeypatch.setattr(data_service, "get_income_statement", + lambda sym, quarterly=False: pd.DataFrame()) + monkeypatch.setattr(data_service, "get_balance_sheet", + lambda sym, quarterly=False: pd.DataFrame()) + monkeypatch.setattr(data_service, "get_company_info", + lambda sym: {}) + monkeypatch.setattr(data_service, "get_shares_outstanding", + lambda sym: None) + + result = data_service.get_valuation("AAPL") + assert result["dcf"]["available"] is False + assert result["ev_ebitda"]["available"] is False + assert result["ev_revenue"]["available"] is False + assert result["price_to_book"]["available"] is False + + +def test_get_valuation_missing_multiples_data(monkeypatch) -> None: + clear_service_caches() + cf_a = annual_frame({ + "Operating Cash Flow": [100.0, 90.0, 80.0, 70.0], + "Capital Expenditure": [-10.0, -9.0, -8.0, -7.0], + }) + monkeypatch.setattr(data_service, "get_cash_flow", + lambda sym, quarterly=False: pd.DataFrame() if quarterly else cf_a) + monkeypatch.setattr(data_service, "get_income_statement", + lambda sym, quarterly=False: pd.DataFrame()) + monkeypatch.setattr(data_service, "get_balance_sheet", + lambda sym, quarterly=False: pd.DataFrame()) + # no enterpriseToEbitda / enterpriseToRevenue / priceToBook in info + monkeypatch.setattr(data_service, "get_company_info", + lambda sym: {"currentPrice": 150.0}) + monkeypatch.setattr(data_service, "get_shares_outstanding", + lambda sym: 1_000_000_000.0) + + result = data_service.get_valuation("AAPL") + assert result["dcf"]["available"] is True + assert result["ev_ebitda"]["available"] is False + assert result["ev_revenue"]["available"] is False + assert result["price_to_book"]["available"] is False |
