"""Integration tests using the synthetic MME fixture. Tests the full pipeline: read MME -> transform -> criteria -> protocol scoring. """ from pathlib import Path import numpy as np import pytest from impakt.criteria import chest_deflection, clip_3ms, femur_load, hic15, nij, tibia_index from impakt.io.mme import MMEReader from impakt.protocol import euro_ncap, iihs, us_ncap from impakt.transform.cfc import cfc_filter FIXTURE_DIR = Path(__file__).parent / "fixtures" / "sample_mme" @pytest.fixture(scope="module") def test_data(): """Load the synthetic MME fixture.""" reader = MMEReader() assert reader.supports(FIXTURE_DIR), f"MME reader should support {FIXTURE_DIR}" return reader.read(FIXTURE_DIR) class TestMMEFixtureLoading: def test_metadata(self, test_data): assert test_data.test_id == "IMPAKT_SYNTH_001" assert test_data.metadata.vehicle.make == "Synthetic" assert test_data.metadata.vehicle.model == "TestCar" assert test_data.metadata.dummy.dummy_type == "Hybrid III 50th Percentile Male" assert test_data.metadata.impact.test_type == "Full Frontal Rigid Barrier" assert test_data.metadata.impact.speed_kmh == 56.3 def test_channel_count(self, test_data): assert len(test_data) == 26 def test_head_channels_found(self, test_data): head_accel = test_data.find("11HEAD0000AC*") assert len(head_accel) == 3 # X, Y, Z def test_channel_properties(self, test_data): ch = test_data.get("11HEAD0000ACXA") assert ch.unit == "g" assert ch.sample_rate == 20000.0 assert ch.n_samples == 4200 assert ch.cfc_class == 1000 def test_auto_grouping(self, test_data): groups = test_data.groups() # Should have groups for: head accel, head ang vel, chest accel, pelvis accel group_keys = list(groups.keys()) head_groups = [k for k in group_keys if "HEAD" in k and "AC" in k] assert len(head_groups) == 1 def test_channel_tree(self, test_data): tree = test_data.channel_tree() assert "Driver (1st Row Left)" in tree assert "Vehicle Structure" in tree class TestTransformPipeline: def test_cfc_filter_on_fixture(self, test_data): ch = test_data.get("11HEAD0000ACXA") filtered = cfc_filter(ch, 600) assert filtered.cfc_class == 600 assert filtered.peak <= ch.peak # Filter reduces peak assert filtered.peak > 30.0 # But retains signal def test_resultant_from_group(self, test_data): group = test_data.group("HEAD0000AC") resultant = group.resultant() assert resultant.code.direction == "R" # Resultant should be >= any individual component assert resultant.peak >= test_data.get("11HEAD0000ACXA").peak class TestInjuryCriteriaPipeline: def test_hic15(self, test_data): group = test_data.group("HEAD0000AC") result = hic15(group) assert result.criterion == "HIC15" assert result.value > 0 assert result.body_region == "Head" # With a ~45g half-sine pulse, HIC15 should be meaningful assert result.value > 50 assert result.value < 5000 def test_3ms_clip(self, test_data): group = test_data.group("CHST0000AC") result = clip_3ms(group) assert result.criterion == "3ms Clip" assert result.value > 0 assert result.value < 100 # Reasonable for ~38g chest pulse def test_nij(self, test_data): fz = test_data.get("11NECKUP00FOZA") my = test_data.get("11NECKUP00MOYA") result = nij(fz_channel=fz, my_channel=my, dummy=test_data.metadata.dummy) assert result.criterion == "Nij" assert result.value > 0 assert result.value < 5.0 # Should be reasonable def test_chest_deflection(self, test_data): ch = test_data.get("11CHST0000DCXA") result = chest_deflection(channel=ch) assert result.criterion == "Chest Deflection" assert result.unit == "mm" assert 30.0 < result.value < 45.0 # ~36mm peak in fixture def test_femur_load(self, test_data): ch_left = test_data.get("11FEMRLE00FOZA") result = femur_load(channel=ch_left, side="left") assert result.criterion == "Femur Load Left" assert result.unit == "kN" assert 3.0 < result.value < 7.0 # ~4.8kN peak in fixture def test_tibia_index(self, test_data): fz = test_data.get("11TIBILEUOFOZA") mx = test_data.get("11TIBILEUOMOXA") my = test_data.get("11TIBILEUOMOYA") result = tibia_index(fz_channel=fz, mx_channel=mx, my_channel=my) assert result.value > 0 class TestProtocolScoringPipeline: @pytest.fixture def all_criteria(self, test_data): """Compute all criteria from the fixture data.""" head_group = test_data.group("HEAD0000AC") chest_group = test_data.group("CHST0000AC") results = {} results["HIC15"] = hic15(head_group) results["3ms Clip"] = clip_3ms(chest_group) results["Nij"] = nij( fz_channel=test_data.get("11NECKUP00FOZA"), my_channel=test_data.get("11NECKUP00MOYA"), dummy=test_data.metadata.dummy, ) results["Chest Deflection"] = chest_deflection(channel=test_data.get("11CHST0000DCXA")) results["Femur Load Left"] = femur_load( channel=test_data.get("11FEMRLE00FOZA"), side="left" ) results["Femur Load Right"] = femur_load( channel=test_data.get("11FEMRRI00FOZA"), side="right" ) results["Tibia Index"] = tibia_index( fz_channel=test_data.get("11TIBILEUOFOZA"), mx_channel=test_data.get("11TIBILEUOMOXA"), my_channel=test_data.get("11TIBILEUOMOYA"), ) return results def test_euro_ncap_scoring(self, all_criteria): result = euro_ncap.evaluate(all_criteria) assert result.protocol == "Euro NCAP" assert result.stars is not None assert 0 <= result.stars <= 5 assert len(result.region_scores) > 0 # Check that all region scores have colors for rs in result.region_scores: assert rs.color is not None def test_us_ncap_scoring(self, all_criteria): result = us_ncap.evaluate(all_criteria) assert result.protocol == "US NCAP" assert result.stars is not None assert 1 <= result.stars <= 5 def test_iihs_scoring(self, all_criteria): result = iihs.evaluate(all_criteria) assert result.protocol == "IIHS" assert result.overall_rating in ("GOOD", "ACCEPTABLE", "MARGINAL", "POOR") assert len(result.region_scores) > 0 def test_protocol_summary_printable(self, all_criteria): for scorer in [euro_ncap, us_ncap, iihs]: result = scorer.evaluate(all_criteria) summary = result.summary() assert len(summary) > 0 assert result.protocol in summary