| from backend.red_flags import ( |
| evaluate_red_flags, |
| compute_risk_score, |
| overall_confidence, |
| get_value, |
| FLAG_SEVERITY, |
| ) |
|
|
|
|
| class FakeGraph: |
| def __init__(self, data): |
| self._data = data |
|
|
| def get_company_metrics(self, company): |
| return self._data.get(company, {}) |
|
|
|
|
| FAKE_DATA = { |
| "HDFC Bank": { |
| "2023": { |
| "deposits": {"value": 1_900_000_00_00_000, "confidence": "high"}, |
| "gross_npa_pct": 1.3, "net_npa_pct": 0.4, |
| "casa_ratio": 44.0, "capital_adequacy": 18.9, |
| }, |
| "2024": { |
| "profit_after_tax": {"value": 608_120_00_00_000, "confidence": "high"}, |
| "deposits": {"value": 1_500_000_00_00_000, "confidence": "high"}, |
| "gross_npa_pct": 6.2, "net_npa_pct": 0.33, |
| "casa_ratio": 28.0, "capital_adequacy": 19.3, |
| }, |
| }, |
| "Infosys": { |
| "2023": {"revenue": {"value": 1_500_000_000_000, "confidence": "high"}}, |
| "2024": { |
| "revenue": {"value": 1_300_000_000_000, "confidence": "high"}, |
| "net_income": {"value": -50_000_000, "confidence": "medium"}, |
| "attrition": 27.5, |
| }, |
| }, |
| } |
|
|
|
|
| def test_get_value_normalizes_both_shapes(): |
| assert get_value({"value": 5.0, "confidence": "high"}) == (5.0, "high") |
| assert get_value(3.2) == (3.2, "medium") |
| assert get_value(None) == (None, None) |
|
|
|
|
| def test_bank_flags_trigger(): |
| result = evaluate_red_flags(FakeGraph(FAKE_DATA), "HDFC Bank", "2024", sector="BANK") |
| flag_names = {f["flag"] for f in result["flags_triggered"]} |
| assert "HIGH_GROSS_NPA" in flag_names |
| assert "LOW_CASA" in flag_names |
| assert "DEPOSIT_DECLINE_YOY" in flag_names |
| assert result["risk_score"] > 0 |
|
|
|
|
| def test_it_flags_trigger(): |
| result = evaluate_red_flags(FakeGraph(FAKE_DATA), "Infosys", "2024", sector="IT") |
| flag_names = {f["flag"] for f in result["flags_triggered"]} |
| assert "HIGH_ATTRITION" in flag_names |
| assert "REVENUE_DECLINE_YOY" in flag_names |
| assert "NEGATIVE_NET_INCOME" in flag_names |
|
|
|
|
| def test_missing_filing_returns_error_not_crash(): |
| result = evaluate_red_flags(FakeGraph(FAKE_DATA), "Nobody", "2024", sector="BANK") |
| assert result["risk_score"] is None |
| assert "error" in result |
|
|
|
|
| def test_risk_score_capped_at_100(): |
| flags = [{"flag": "HIGH_GROSS_NPA"}] * 10 |
| assert compute_risk_score(flags) == 100 |
|
|
|
|
| def test_overall_confidence_is_weakest_link(): |
| flags = [ |
| {"flag": "A", "confidence": "high"}, |
| {"flag": "B", "confidence": "low"}, |
| ] |
| assert overall_confidence(flags) == "low" |
| assert overall_confidence([]) == "high" |
|
|
|
|
| def test_severity_table_has_entries_for_core_flags(): |
| for flag in ("HIGH_GROSS_NPA", "NEGATIVE_PAT", "HIGH_ATTRITION", "HIGH_DEBT_EQUITY"): |
| assert flag in FLAG_SEVERITY |
|
|