diff --git a/python_analysis_script/tests/test_core.py b/python_analysis_script/tests/test_core.py new file mode 100644 index 0000000..92ec583 --- /dev/null +++ b/python_analysis_script/tests/test_core.py @@ -0,0 +1,57 @@ +import pytest +import pandas as pd +from pathlib import Path +from datetime import datetime + +import src.python_analysis_script.core as core + + +@pytest.fixture +def sample_csv(tmp_path: Path) -> Path: + data = pd.DataFrame([ + {"timestamp": datetime.now().isoformat(), "margin": 0.15, "flaky_flag": False, "subset_flip_count": 0, "mischfenster_p95": 0.9, "decision": ""}, + {"timestamp": datetime.now().isoformat(), "margin": 0.05, "flaky_flag": False, "subset_flip_count": 1, "mischfenster_p95": 0.8, "decision": ""}, + {"timestamp": datetime.now().isoformat(), "margin": -0.2, "flaky_flag": True, "subset_flip_count": 2, "mischfenster_p95": 0.5, "decision": ""} + ]) + file_path = tmp_path / "sample.csv" + data.to_csv(file_path, index=False) + return file_path + + +def test_analyze_backtest_returns_decisionresult_list(sample_csv: Path): + results = core.analyze_backtest(str(sample_csv)) + assert isinstance(results, list) + assert all(isinstance(r, core.DecisionResult) for r in results) + + +def test_decision_fields_are_valid(sample_csv: Path): + results = core.analyze_backtest(str(sample_csv)) + for res in results: + assert res.decision in {"PASS", "WARN", "FAIL"} + assert isinstance(res.margin, float) + assert isinstance(res.flaky_flag, bool) + assert isinstance(res.subset_flip_count, int) + assert isinstance(res.mischfenster_p95, float) + assert isinstance(res.timestamp, datetime) + + +def test_analyze_backtest_handles_empty_file(tmp_path: Path): + empty_file = tmp_path / "empty.csv" + pd.DataFrame(columns=["timestamp", "margin", "flaky_flag", "subset_flip_count", "mischfenster_p95", "decision"]).to_csv(empty_file, index=False) + results = core.analyze_backtest(str(empty_file)) + assert isinstance(results, list) + assert len(results) == 0 + + +def test_policy_decision_logic_varies_with_margin(sample_csv: Path): + results = core.analyze_backtest(str(sample_csv)) + margins = [r.margin for r in results] + decisions = [r.decision for r in results] + # There should be some differentiation between PASS/WARN/FAIL cases + unique_decisions = set(decisions) + assert len(unique_decisions) >= 2, "Expected mixed PASS/WARN/FAIL decisions based on margin values." + + +def test_input_validation_with_missing_file(): + with pytest.raises((FileNotFoundError, OSError)): + core.analyze_backtest("nonexistent_file.csv")