Spaces:
Build error
Build error
| """ | |
| Rule engine tests (backend/src/rules). | |
| These are pure unit tests: no DB, no network. | |
| """ | |
| from src.rules import ( | |
| get_registry, | |
| MetricData, | |
| UserContext, | |
| Severity, | |
| LDLHighRule, | |
| HDLLowRule, | |
| HbA1cHighRule, | |
| VitaminDLowRule, | |
| BPHighRule, | |
| SleepLowRule, | |
| MissingTestsRule, | |
| ) | |
| def test_user_context_accepts_age_and_gender(): | |
| ctx = UserContext(user_id="u", metrics={}, age=40, gender="male") | |
| assert ctx.age == 40 | |
| assert ctx.gender == "male" | |
| def test_registry_is_singleton(): | |
| assert get_registry() is get_registry() | |
| def test_registry_evaluate_all_returns_rule_results(): | |
| registry = get_registry() | |
| ctx = UserContext( | |
| user_id="u", | |
| metrics={ | |
| "ldl": MetricData(name="ldl", value=200, unit="mg/dL"), | |
| "hba1c": MetricData(name="hba1c", value=7.0, unit="%"), | |
| }, | |
| ) | |
| results = registry.evaluate_all(ctx) | |
| assert results, "Expected at least one rule to trigger" | |
| assert all(r.id and r.title for r in results) | |
| def test_ldl_rule_severity_thresholds(): | |
| rule = LDLHighRule() | |
| # Below trigger threshold | |
| ctx = UserContext(user_id="u", metrics={"ldl": MetricData(name="ldl", value=120, unit="mg/dL")}) | |
| assert rule.evaluate(ctx) is None | |
| # Borderline high => INFO (130-159) | |
| ctx = UserContext(user_id="u", metrics={"ldl": MetricData(name="ldl", value=140, unit="mg/dL")}) | |
| assert rule.evaluate(ctx).severity == Severity.INFO | |
| # High => WARNING (>=160) | |
| ctx = UserContext(user_id="u", metrics={"ldl": MetricData(name="ldl", value=170, unit="mg/dL")}) | |
| assert rule.evaluate(ctx).severity == Severity.WARNING | |
| # Very high => URGENT (>=190) | |
| ctx = UserContext(user_id="u", metrics={"ldl": MetricData(name="ldl", value=200, unit="mg/dL")}) | |
| assert rule.evaluate(ctx).severity == Severity.URGENT | |
| def test_hdl_low_rule_triggers_and_sets_reference_min(): | |
| rule = HDLLowRule() | |
| ctx = UserContext(user_id="u", metrics={"hdl": MetricData(name="hdl", value=30, unit="mg/dL")}) | |
| res = rule.evaluate(ctx) | |
| assert res is not None | |
| assert res.reference_min == 40 | |
| def test_hba1c_rule_warning_and_urgent(): | |
| rule = HbA1cHighRule() | |
| ctx = UserContext(user_id="u", metrics={"hba1c": MetricData(name="hba1c", value=6.0, unit="%")}) | |
| assert rule.evaluate(ctx).severity == Severity.WARNING | |
| ctx = UserContext(user_id="u", metrics={"hba1c": MetricData(name="hba1c", value=7.0, unit="%")}) | |
| assert rule.evaluate(ctx).severity == Severity.URGENT | |
| def test_vitamin_d_rule_triggers_below_30(): | |
| rule = VitaminDLowRule() | |
| ctx = UserContext(user_id="u", metrics={"vitamin_d": MetricData(name="vitamin_d", value=18, unit="ng/mL")}) | |
| assert rule.evaluate(ctx) is not None | |
| def test_bp_high_rule_stage1_and_crisis(): | |
| rule = BPHighRule() | |
| ctx = UserContext( | |
| user_id="u", | |
| metrics={ | |
| "systolic_bp": MetricData(name="systolic_bp", value=135, unit="mmHg"), | |
| "diastolic_bp": MetricData(name="diastolic_bp", value=85, unit="mmHg"), | |
| }, | |
| ) | |
| assert rule.evaluate(ctx) is not None | |
| ctx = UserContext( | |
| user_id="u", | |
| metrics={ | |
| "systolic_bp": MetricData(name="systolic_bp", value=185, unit="mmHg"), | |
| "diastolic_bp": MetricData(name="diastolic_bp", value=125, unit="mmHg"), | |
| }, | |
| ) | |
| assert rule.evaluate(ctx).severity == Severity.URGENT | |
| def test_sleep_low_rule_triggers_below_7_hours(): | |
| rule = SleepLowRule() | |
| ctx = UserContext(user_id="u", metrics={"sleep_hours": MetricData(name="sleep_hours", value=5.5, unit="hours")}) | |
| assert rule.evaluate(ctx) is not None | |
| def test_missing_tests_rule_triggers_when_no_metrics(): | |
| rule = MissingTestsRule() | |
| ctx = UserContext(user_id="u", metrics={}) | |
| assert rule.evaluate(ctx) is not None | |