import json import os import tempfile from datetime import datetime from pathlib import Path import pytest # Wir importieren aus dem Projektpaket artifact_001.core import importlib.util def load_log_measurement(): # Dynamisches Laden der log_measurement Funktion aus src/artifact_001/core.py # Dies ist CI-safe, da ansonsten ImportError entstehen könnte, falls sys.path anders konfiguriert ist. pkg_path = Path(__file__).parent.parent / 'src' / 'artifact_001' / 'core.py' spec = importlib.util.spec_from_file_location('artifact_001.core', pkg_path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod.log_measurement @pytest.fixture def sample_measurement(): return { 'timestamp': datetime(2024, 6, 10, 7, 5, 0), 'measured_p': 0.134, 'freeze_ok': False, 'setup_fingerprint': 'setupA', 'policy_hash': 'ph123' } @pytest.fixture(autouse=True) def temp_output_dir(monkeypatch, tmp_path): output_path = tmp_path / 'measurement_log.json' os.makedirs(tmp_path, exist_ok=True) # Patch the output path in core.py to use this temp file. monkeypatch.setenv('AUX3_OUTPUT_PATH', str(output_path)) yield output_path @pytest.mark.parametrize('invalid_case', [ {'measured_p': 'no_float'}, # falscher Typ {'freeze_ok': 'not_bool'}, # falscher Typ {'timestamp': 'invalid-date'}, # ungültiges Datum ]) def test_log_measurement_invalid_input(invalid_case, sample_measurement, temp_output_dir): log_measurement = load_log_measurement() bad_input = sample_measurement.copy() bad_input.update(invalid_case) with pytest.raises(Exception): log_measurement(**bad_input) def test_log_measurement_creates_valid_json(sample_measurement, temp_output_dir): log_measurement = load_log_measurement() fpath = temp_output_dir # Sicherstellen, dass Datei leer ist if fpath.exists(): fpath.unlink() # Aufruf der Funktion log_measurement(**sample_measurement) assert fpath.exists(), 'JSON-Logdatei sollte erstellt werden.' content = json.loads(fpath.read_text(encoding='utf-8')) assert isinstance(content, list), 'JSON-Datei sollte eine Liste enthalten.' assert len(content) == 1, 'Ein Messpunkt sollte geloggt sein.' entry = content[0] # Strukturprüfung basierend auf MeasurementLog data_model expected_fields = ['timestamp', 'measured_p', 'freeze_ok', 'setup_fingerprint', 'policy_hash'] for field in expected_fields: assert field in entry, f'Feld {field} sollte vorhanden sein.' # Typ-Assertions (Nominal Case) datetime.fromisoformat(entry['timestamp']) assert isinstance(entry['measured_p'], float) assert isinstance(entry['freeze_ok'], bool) assert isinstance(entry['setup_fingerprint'], str) assert isinstance(entry['policy_hash'], str) def test_log_measurement_appends_to_existing(temp_output_dir, sample_measurement): log_measurement = load_log_measurement() fpath = temp_output_dir # Erstes Logging log_measurement(**sample_measurement) # Zweites Logging – sollte anhängen modified = sample_measurement.copy() modified['measured_p'] = 0.555 log_measurement(**modified) content = json.loads(fpath.read_text(encoding='utf-8')) assert len(content) == 2, 'Zwei Messpunkte sollten geloggt sein.' # Letzter Eintrag überprüfen assert pytest.approx(content[-1]['measured_p'], 1e-6) == 0.555