"""Tests for channel grid component.""" from pathlib import Path import pytest from impakt.io.mme import MMEReader from impakt.web.components.channel_grid import ( _build_channel_rows, build_selected_channels_badges, filter_rows, ) from impakt.web.state import AppState FIXTURE_DATA = Path(__file__).parent.parent / "fixtures" / "sample_mme" MME_DATA = Path(__file__).parent.parent / "mme_data" class TestChannelRows: def test_build_rows_from_synthetic(self): state = AppState() state.load_test(FIXTURE_DATA) rows = _build_channel_rows(state) assert len(rows) == 26 # Each row should have required fields for r in rows: assert "key" in r assert "iso_code" in r assert "unit" in r assert "min" in r assert "max" in r assert "::" in r["key"] @pytest.mark.skipif(not (MME_DATA / "3239").exists(), reason="Real data not available") def test_build_rows_from_real_data(self): state = AppState() state.load_test(MME_DATA / "3239") rows = _build_channel_rows(state) assert len(rows) == 133 def test_multi_test_rows_have_test_id(self): state = AppState() state.load_test(FIXTURE_DATA) if (MME_DATA / "VW1FGS15").exists(): state.load_test(MME_DATA / "VW1FGS15") rows = _build_channel_rows(state) assert len(rows) == 36 # 26 + 10 # Multi-test rows should have test_id filled test_ids = {r["test_id"] for r in rows} assert len(test_ids) == 2 def test_rows_preserve_load_order(self): state = AppState() state.load_test(FIXTURE_DATA) rows = _build_channel_rows(state) # First channel in fixture should be first row # (this depends on how MMEReader yields channels — sorted by name) iso_codes = [r["iso_code"] for r in rows] assert len(iso_codes) == 26 class TestFilterRows: @pytest.fixture def rows(self): state = AppState() state.load_test(FIXTURE_DATA) return _build_channel_rows(state) def test_no_filter_returns_all(self, rows): result = filter_rows(rows) assert len(result) == len(rows) def test_wildcard_filter_head(self, rows): result = filter_rows(rows, pattern="*HEAD*") assert len(result) > 0 assert all("HEAD" in r["iso_code"] for r in result) def test_wildcard_filter_accel(self, rows): result = filter_rows(rows, pattern="*AC*") assert len(result) > 0 assert all("AC" in r["iso_code"] for r in result) def test_partial_text_auto_wrapped(self, rows): """Typing 'HEAD' without wildcards should auto-wrap to *HEAD*.""" result = filter_rows(rows, pattern="HEAD") assert len(result) > 0 assert all("HEAD" in r["iso_code"] for r in result) def test_filter_by_body_facet(self, rows): result = filter_rows(rows, body="Head") assert len(result) > 0 assert all(r["body"] == "Head" for r in result) def test_filter_by_direction_facet(self, rows): result = filter_rows(rows, direction="X") assert len(result) > 0 assert all(r["direction"] == "X" for r in result) def test_combined_filter(self, rows): result = filter_rows(rows, pattern="*AC*", direction="X") assert len(result) > 0 for r in result: assert "AC" in r["iso_code"] assert r["direction"] == "X" def test_no_match_returns_empty(self, rows): result = filter_rows(rows, pattern="NONEXISTENT") assert len(result) == 0 @pytest.mark.skipif(not (MME_DATA / "3239").exists(), reason="Real data not available") def test_wildcard_filter_real_data(self): state = AppState() state.load_test(MME_DATA / "3239") rows = _build_channel_rows(state) # Filter for head channels head = filter_rows(rows, pattern="*HEAD*") assert len(head) > 0 # Filter for barrier load cells barrier = filter_rows(rows, pattern="B0FBAR*") assert len(barrier) > 0 # Filter for femur femur = filter_rows(rows, pattern="*FEMR*") assert len(femur) >= 2 # Left and right class TestSelectedBadges: def test_empty_selection(self): state = AppState() badges = build_selected_channels_badges([], state) assert len(badges) == 1 # "No channels selected" def test_with_selection(self): state = AppState() state.load_test(FIXTURE_DATA) keys = ["IMPAKT_SYNTH_001::11HEAD0000ACXA", "IMPAKT_SYNTH_001::11HEAD0000ACYA"] badges = build_selected_channels_badges(keys, state) assert len(badges) == 2