diff --git a/frozen_runs_analysis/tests/test_core.py b/frozen_runs_analysis/tests/test_core.py new file mode 100644 index 0000000..d6edecc --- /dev/null +++ b/frozen_runs_analysis/tests/test_core.py @@ -0,0 +1,64 @@ +import pytest +import pandas as pd +from typing import List, Dict +from frozen_runs_analysis import core + +class DummyRunData: + def __init__(self, run_id: str, status: str, sanity_checks: Dict[str, float], config_hash: str): + self.run_id = run_id + self.status = status + self.sanity_checks = sanity_checks + self.config_hash = config_hash + +@pytest.fixture +def sample_runs() -> List[DummyRunData]: + return [ + DummyRunData(run_id="#24", status="pinned", sanity_checks={"missing_pairs": 1, "clock_switch": 0}, config_hash="abc123"), + DummyRunData(run_id="#25", status="unpinned", sanity_checks={"missing_pairs": 2, "clock_switch": 1}, config_hash="abc123"), + DummyRunData(run_id="#26", status="pinned", sanity_checks={"missing_pairs": 0, "clock_switch": 0}, config_hash="def456"), + DummyRunData(run_id="#27", status="unpinned", sanity_checks={"missing_pairs": 3, "clock_switch": 2}, config_hash="abc123"), + ] + +@pytest.fixture +def sample_dataframe(sample_runs): + df = pd.DataFrame([ + {"run_id": r.run_id, "status": r.status, "missing_pairs": r.sanity_checks["missing_pairs"], "clock_switch": r.sanity_checks["clock_switch"], "config_hash": r.config_hash} + for r in sample_runs + ]) + return df + +@pytest.mark.parametrize("input_data_type", [list, pd.DataFrame]) +def test_analyse_frozen_runs_output_type(sample_runs, sample_dataframe, input_data_type): + data = sample_runs if input_data_type is list else sample_dataframe + result = core.analyse_frozen_runs(data) + assert isinstance(result, dict) + assert "flip_flop_frequency" in result + assert "hash_stability" in result + assert "p95_sanity_missing_pairs" in result + + +@pytest.mark.parametrize("edge_case_runs", [ + [], # Empty list + [DummyRunData(run_id="#1", status="pinned", sanity_checks={}, config_hash="xyz")], # Minimal fields +]) +def test_analyse_frozen_runs_edge_cases(edge_case_runs): + result = core.analyse_frozen_runs(edge_case_runs) + assert isinstance(result, dict) + assert set(result.keys()) >= {"flip_flop_frequency", "hash_stability", "p95_sanity_missing_pairs"} + + +def test_analyse_frozen_runs_reproducibility(sample_runs): + result1 = core.analyse_frozen_runs(sample_runs) + result2 = core.analyse_frozen_runs(sample_runs) + assert result1 == result2, "Analyseergebnisse müssen deterministisch und reproduzierbar sein" + + +def test_analyse_frozen_runs_statistical_sanity(sample_runs): + result = core.analyse_frozen_runs(sample_runs) + flip_flop = result.get("flip_flop_frequency", None) + assert 0 <= flip_flop <= 1, "Flip-Flop-Frequenz muss zwischen 0 und 1 liegen" + p95_missing = result.get("p95_sanity_missing_pairs", 0) + assert isinstance(p95_missing, (int, float)) and p95_missing >= 0 + hash_stability = result.get("hash_stability", {}) + assert isinstance(hash_stability, dict) + assert all(isinstance(k, str) and isinstance(v, int) for k, v in hash_stability.items()) \ No newline at end of file