summaryrefslogtreecommitdiff
path: root/backend/tests/test_api.py
diff options
context:
space:
mode:
Diffstat (limited to 'backend/tests/test_api.py')
-rw-r--r--backend/tests/test_api.py109
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