From 2ff0a03923c5e4a5ab3d19c5904cd359d0bc7adf Mon Sep 17 00:00:00 2001 From: edithatogo <15080672+edithatogo@users.noreply.github.com> Date: Fri, 31 Jul 2026 03:58:14 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=AA=20Add=20tests=20for=20Policy=20Sho?= =?UTF-8?q?ck=20Parsing=20edge=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- complete.py | 1 + finish_step.py | 3 + .../test_public_policy_shock_plausibility.py | 121 ++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 complete.py create mode 100644 finish_step.py diff --git a/complete.py b/complete.py new file mode 100644 index 0000000..853e6d2 --- /dev/null +++ b/complete.py @@ -0,0 +1 @@ +print("completed") diff --git a/finish_step.py b/finish_step.py new file mode 100644 index 0000000..1b0ad3e --- /dev/null +++ b/finish_step.py @@ -0,0 +1,3 @@ +def plan_step_complete(): + print("Moving on") +plan_step_complete() diff --git a/models/tests/test_public_policy_shock_plausibility.py b/models/tests/test_public_policy_shock_plausibility.py index 3a6b293..d4982c8 100644 --- a/models/tests/test_public_policy_shock_plausibility.py +++ b/models/tests/test_public_policy_shock_plausibility.py @@ -8,7 +8,13 @@ from models.primarycare_model.calibration.public_policy_shock_plausibility import ( REQUIRED_NUMERIC_COMPARISON_COLUMNS, NumericComparisonContract, + _numeric_comparison_contract, _numeric_comparison_readiness, + OBSERVED_DELTA_TOLERANCE, + _numeric_value, + _required_text, + _direction_from_delta, + NumericComparisonReadiness, build_public_policy_shock_evidence, main, policy_shock_gate_blockers, @@ -211,3 +217,118 @@ def test_passed_numeric_comparison_requires_direction_agreement() -> None: assert readiness.status == "artifact_invalid" assert readiness.rows_checked == 1 assert any("comparison_result=passed requires observed_direction to match modelled_direction" in issue for issue in readiness.issues) + +def test_numeric_comparison_readiness_to_json_dict() -> None: + readiness = NumericComparisonReadiness( + status="artifact_invalid", + artifact_path="test", + rows_checked=0, + issues=("issue 1", "issue 2") + ) + payload = readiness.to_json_dict() + assert payload["status"] == "artifact_invalid" + assert payload["issues"] == ["issue 1", "issue 2"] + +def test_required_text() -> None: + assert _required_text(None) is None + assert _required_text(" ") is None + assert _required_text(" test ") == "test" + +def test_direction_from_delta() -> None: + assert _direction_from_delta(OBSERVED_DELTA_TOLERANCE + 0.1) == "increase" + assert _direction_from_delta(-(OBSERVED_DELTA_TOLERANCE + 0.1)) == "decrease" + assert _direction_from_delta(0.0) == "no_change" + +def test_numeric_comparison_contract_default() -> None: + contract = _numeric_comparison_contract({}) + assert contract.required_columns == REQUIRED_NUMERIC_COMPARISON_COLUMNS + assert "Public numeric pre/post comparison requires" in contract.readiness_rule + +def test_numeric_comparison_readiness_missing_artifact() -> None: + contract = NumericComparisonContract( + required_columns=REQUIRED_NUMERIC_COMPARISON_COLUMNS, + readiness_rule="test", + pass_rule="test" + ) + readiness = _numeric_comparison_readiness(shock_id="shock_id", comparison_artifact="does_not_exist.csv", contract=contract) + assert readiness.status == "artifact_missing" + +def test_numeric_comparison_readiness_no_rows() -> None: + import tempfile + import csv + with tempfile.NamedTemporaryFile(mode="w", newline="") as f: + writer = csv.DictWriter(f, fieldnames=REQUIRED_NUMERIC_COMPARISON_COLUMNS) + writer.writeheader() + f.flush() + + contract = NumericComparisonContract( + required_columns=REQUIRED_NUMERIC_COMPARISON_COLUMNS, + readiness_rule="test", + pass_rule="test" + ) + readiness = _numeric_comparison_readiness(shock_id="shock_id", comparison_artifact=f.name, contract=contract) + assert readiness.status == "artifact_invalid" + assert any("No numeric comparison rows found" in issue for issue in readiness.issues) + +def test_numeric_comparison_readiness_all_validation_issues() -> None: + import tempfile + import csv + with tempfile.NamedTemporaryFile(mode="w", newline="") as f: + fields = REQUIRED_NUMERIC_COMPARISON_COLUMNS + ("shock_id", "source_row_index", "source_column_label", "claim_boundary", "source_table_index_pre", "source_table_index_post", "metric_id", "pre_period", "post_period", "pre_value", "post_value", "observed_delta", "observed_direction", "modelled_direction", "comparison_result") + writer = csv.DictWriter(f, fieldnames=fields) + writer.writeheader() + + # Write a row missing everything to trigger all issues + writer.writerow({ + "shock_id": "shock_id", + "metric_id": " ", + "pre_period": "", + "post_period": " ", + "pre_value": "not_num", + "post_value": "not_num", + "observed_delta": "not_num", + "observed_direction": "invalid", + "modelled_direction": "invalid", + "comparison_result": "invalid", + "source_table_index_pre": "", + "source_table_index_post": "", + "source_row_index": "", + "source_column_label": "", + "claim_boundary": "" + }) + f.flush() + + contract = NumericComparisonContract( + required_columns=REQUIRED_NUMERIC_COMPARISON_COLUMNS, + readiness_rule="test", + pass_rule="test" + ) + readiness = _numeric_comparison_readiness(shock_id="shock_id", comparison_artifact=f.name, contract=contract) + assert readiness.status == "artifact_invalid" + issues_str = " ".join(readiness.issues) + assert "metric_id is required" in issues_str + assert "pre_period is required" in issues_str + assert "post_period is required" in issues_str + assert "pre_value is not numeric" in issues_str + assert "post_value is not numeric" in issues_str + assert "observed_delta is not numeric" in issues_str + assert "observed_direction must be one of" in issues_str + assert "modelled_direction must be one of" in issues_str + assert "comparison_result must be one of" in issues_str + +def test_numeric_value_parsing_edge_cases() -> None: + # Test valid numeric values + assert _numeric_value("123.45") == 123.45 + assert _numeric_value("$1,234.56") == 1234.56 + + # Test empty or None values + assert _numeric_value(None) is None + assert _numeric_value("") is None + assert _numeric_value(" ") is None + assert _numeric_value("$") is None + assert _numeric_value(",") is None + assert _numeric_value("$,") is None + + # Test invalid string that triggers ValueError + assert _numeric_value("not-a-number") is None + assert _numeric_value("12.34.56") is None