diff --git a/data_analysis/tests/test_core.py b/data_analysis/tests/test_core.py new file mode 100644 index 0000000..80689cf --- /dev/null +++ b/data_analysis/tests/test_core.py @@ -0,0 +1,75 @@ +import pytest +import math +import statistics +from data_analysis import core + + +def _generate_run_data(values): + return [ + { + 'epoch_ms': i * 1000, + 'run_id': f'run_{i}', + 'retry_tail_p99': v, + 'band_width': 100.0 + v + } + for i, v in enumerate(values) + ] + + +def test_analyze_data_stable_case(): + run_data = _generate_run_data([100.0, 101.0, 99.0, 100.5, 100.2]) + result = core.analyze_data(run_data) + assert isinstance(result, dict) + assert 'median' in result and 'iqr' in result and 'stability' in result + + med_expected = statistics.median([100.0, 101.0, 99.0, 100.5, 100.2]) + q75, q25 = np.percentile([100.0, 101.0, 99.0, 100.5, 100.2], [75, 25]) if 'np' in globals() else (101.0, 99.5) + iqr_expected = q75 - q25 if q75 >= q25 else 1.5 # fallback heuristic for small sample + assert math.isclose(result['median'], med_expected, rel_tol=1e-9) + assert result['iqr'] >= 0.0 + assert isinstance(result['stability'], bool) + # Bei stabilen Werten müsste stability True sein + assert result['stability'] is True + + +def test_analyze_data_unstable_case(): + run_data = _generate_run_data([100.0, 110.0, 200.0, 90.0, 50.0]) + result = core.analyze_data(run_data) + assert isinstance(result, dict) + assert 'median' in result and 'iqr' in result and 'stability' in result + assert result['iqr'] > 0.0 + # Erwartung: instabil, da hohe Streuung + assert result['stability'] is False + + +def test_analyze_data_empty_or_invalid(): + # Leerliste -> Fehler oder definierter Rückgabewert + with pytest.raises((ValueError, AssertionError, TypeError)): + core.analyze_data([]) + + # Invalid structure -> Fehler + with pytest.raises((KeyError, TypeError, AssertionError)): + core.analyze_data([{'run_id': 'x'}]) + + +def test_analyze_data_numeric_precision(): + # Kleine Unterschiede sollten stabil sein + run_data = _generate_run_data([100.0001, 100.0002, 100.0003]) + result = core.analyze_data(run_data) + assert math.isclose(result['iqr'], 0.0, abs_tol=0.001) or result['stability'] + + +def test_output_structure_consistency(): + run_data = _generate_run_data([120, 130, 125, 126]) + result = core.analyze_data(run_data) + assert set(result.keys()) == {'median', 'iqr', 'stability'} + assert isinstance(result['median'], (float, int)) + assert isinstance(result['iqr'], (float, int)) + assert isinstance(result['stability'], bool) + + +# Optional defensive import for numpy percentile (graceful skip if not available) +try: + import numpy as np # noqa: E402 +except ImportError: + np = None \ No newline at end of file