diff --git a/policy_eval.py/tests/test_core.py b/policy_eval.py/tests/test_core.py new file mode 100644 index 0000000..ff574dd --- /dev/null +++ b/policy_eval.py/tests/test_core.py @@ -0,0 +1,70 @@ +import json +import os +import tempfile +import pytest +import pandas as pd +from pathlib import Path + +import src.policy_eval as policy_eval + +@pytest.fixture +def policy_constants_sample(): + return {"version": "1.0.0", "constant_value": 42.0} + +@pytest.fixture +def changed_policy_constants(): + return {"version": "1.0.1", "constant_value": 43.0} + +@pytest.fixture +def audit_set_tmp(tmp_path): + audit_dir = tmp_path / "audit" + audit_dir.mkdir() + csv_path = audit_dir / "data.csv" + df = pd.DataFrame({"id": [1,2], "value": [10,20]}) + df.to_csv(csv_path, index=False) + return str(audit_dir) + +def test_check_policy_changes_no_change(policy_constants_sample): + # When the same constants are checked twice, should detect no change + assert policy_eval.check_policy_changes(policy_constants_sample) == False + # Second run with same should still result False (deterministic behavior) + assert policy_eval.check_policy_changes(policy_constants_sample) == False + +def test_check_policy_changes_detects_change(policy_constants_sample, changed_policy_constants): + # First baseline call + _ = policy_eval.check_policy_changes(policy_constants_sample) + result = policy_eval.check_policy_changes(changed_policy_constants) + assert result is True + +@pytest.mark.parametrize("variant", ["small", "medium"]) +def test_run_backtest_creates_outputs(audit_set_tmp, variant): + results = policy_eval.run_backtest(audit_set_tmp) + assert isinstance(results, dict) + summary_path = results.get("delta_summary") + cases_path = results.get("delta_cases") + + assert summary_path and os.path.isfile(summary_path) + assert cases_path and os.path.isfile(cases_path) + + with open(summary_path) as f: + summary = json.load(f) + assert isinstance(summary, dict) + + df_cases = pd.read_csv(cases_path) + expected_cols = ["reason", "old_decision", "new_decision", "policy_hash"] + for col in expected_cols: + assert col in df_cases.columns + + # determinism: calling again produces same summary + second_results = policy_eval.run_backtest(audit_set_tmp) + with open(second_results["delta_summary"]) as f2: + summary2 = json.load(f2) + assert summary == summary2 + +def test_run_backtest_with_empty_audit(tmp_path): + empty_dir = tmp_path / "empty" + empty_dir.mkdir() + result = policy_eval.run_backtest(str(empty_dir)) + assert isinstance(result["delta_summary"], str) + assert os.path.exists(result["delta_summary"]) + assert os.path.exists(result["delta_cases"]) \ No newline at end of file