diff --git a/tests/test_foerderer.py b/tests/test_foerderer.py index 0cf5470..f39bfb8 100644 --- a/tests/test_foerderer.py +++ b/tests/test_foerderer.py @@ -7,7 +7,10 @@ Prueft: 1. Status-Werte und Vollstaendigkeit (foerderer_results.json) 2. Mathematische Invarianten (Laengen, Winkel, Richtung) 3. Geometrisch unmoegliche Faelle - 4. CSV-Export-Struktur (foerderer_tests_export.csv, aus TEST_EXPORT_ALL) + 4. CSV-Export-Struktur (foerderer_tests_export.csv, aus TEST_EXPORT_ALL) - + seit csv:sep-proxies-erzeugen (Commit e2f0384) enthaelt die CSV neben + den Vario-Zeilen auch eine Zeile je verpacktem Separator-Sensor; siehe + NEBEN_TEILEARTEN und TestFoerdererExportCSV._vario_rows/_separator_rows. 5. Sivas-Export-Struktur (foerderer_tests_sivas.csv, aus TEST_EXPORT_ALL) """ @@ -17,6 +20,15 @@ import os import pytest +# TeileArt-Werte, die einen SENSOR beschreiben statt einer Vario-Strecke - +# csv:sep-proxies-erzeugen (export.lsp, Commit e2f0384) erfasst seither auch +# Separator_SP-Symbole, die als Sub-INSERT in der VF_n-Blockdefinition +# verpackt sind, und exportiert je Fund eine eigene Zeile. Foerderer kennt +# nur diese eine Sensorart (kein Scanner); die vollstaendige Liste steht in +# test_export_ids.py:SENSOR_TEILEARTEN. +NEBEN_TEILEARTEN = {"ILS 2.0 Separator"} + + # --------------------------------------------------------------------------- # Hilfsfunktionen # --------------------------------------------------------------------------- @@ -211,6 +223,16 @@ class TestFoerdererExportCSV: return None return row[i] + def _vario_rows(self): + """Nur die eigentlichen Foerderer-Zeilen, ohne die mitexportierten + Separator-Sensoren (siehe NEBEN_TEILEARTEN).""" + return [row for row in self.rows + if self._cell(row, "TeileArt") not in NEBEN_TEILEARTEN] + + def _separator_rows(self): + return [row for row in self.rows + if self._cell(row, "TeileArt") == "ILS 2.0 Separator"] + def test_header_felder(self): """CSV-Header muss die erwarteten Spalten enthalten (Reihenfolge/Zusatz- spalten wie Insertpoint/K1-K4/Warnungen egal - per Name geprueft).""" @@ -227,9 +249,10 @@ class TestFoerdererExportCSV: assert len(self.rows) > 0, "foerderer_tests_export.csv enthaelt keine Daten" def test_vario_teileart(self): - """Alle Eintraege muessen TeileArt 'ILS 2.0 Strecke' haben (VarioFoerderer + """Jede Vario-Zeile (ohne die mitexportierten Separator-Sensoren, siehe + NEBEN_TEILEARTEN) muss TeileArt 'ILS 2.0 Strecke' haben (VarioFoerderer ist ein Streckentyp, siehe export_csv.py:process_blocks).""" - for i, row in enumerate(self.rows): + for i, row in enumerate(self._vario_rows()): teileart = self._cell(row, "TeileArt") if teileart is None: continue @@ -237,6 +260,19 @@ class TestFoerdererExportCSV: f"Zeile {i + 2}: TeileArt='{teileart}', erwartet 'ILS 2.0 Strecke'" ) + def test_teileart_bekannt(self): + """Jede Zeile ist entweder eine Vario-Strecke oder eine der bekannten + Neben-TeileArten - keine unerwartete dritte Art (die die beiden obigen + Filter sonst stillschweigend durchliesse).""" + bekannt = {"ILS 2.0 Strecke"} | NEBEN_TEILEARTEN + for i, row in enumerate(self.rows): + teileart = self._cell(row, "TeileArt") + if teileart is None: + continue + assert teileart.strip('"') in bekannt, ( + f"Zeile {i + 2}: unbekannte TeileArt '{teileart}'" + ) + def test_anzahl_spalte_ist_eins(self): """Anzahl-Spalte muss fuer alle Zeilen '1' sein.""" for i, row in enumerate(self.rows): @@ -259,10 +295,27 @@ class TestFoerdererExportCSV: pytest.fail(f"Zeile {i + 2}: Merkmale ist kein valides JSON: {e}") def test_merkmale_felder(self): - """Merkmale muessen alle Pflichtfelder enthalten.""" + """Merkmale der Vario-Zeilen muessen alle Pflichtfelder enthalten. Die + mitexportierten Separator-Sensoren haben ein eigenes, kleineres Schema + (siehe test_separator_merkmale_felder) und sind hier ausgenommen.""" required = {"Typ", "Winkel", "DeltaH_mm", "DeltaL_mm", "L_VF_m", "Hoehe_Von_mm", "Hoehe_Bis_mm"} - for i, row in enumerate(self.rows): + for i, row in enumerate(self._vario_rows()): + zelle = self._cell(row, "Merkmale") + if zelle is None: + continue + merkmale = json.loads(zelle) + missing = required - set(merkmale.keys()) + assert not missing, ( + f"Zeile {i + 2}: Fehlende Merkmale-Felder: {missing}" + ) + + def test_separator_merkmale_felder(self): + """Merkmale der mitexportierten Separator-Sensoren muessen die + Zuordnung zu ihrem Vario-Wrapper tragen (siehe + test_separator_zuordnung_konsistent) sowie ARTINR.""" + required = {"Zuordnung", "ARTINR"} + for i, row in enumerate(self._separator_rows()): zelle = self._cell(row, "Merkmale") if zelle is None: continue @@ -273,14 +326,51 @@ class TestFoerdererExportCSV: ) def test_anzahl_csv_zeilen_entspricht_gebaut(self): - """CSV-Zeilenanzahl muss Anzahl GEBAUT-Testfaellen entsprechen.""" + """Anzahl der Vario-Zeilen (ohne die mitexportierten Separatoren) muss + der Anzahl GEBAUT-Testfaellen entsprechen.""" results = _load_foerderer_results() anzahl_gebaut = sum(1 for r in results if r["status"] == "GEBAUT") - assert len(self.rows) == anzahl_gebaut, ( - f"CSV hat {len(self.rows)} Zeilen, " + vario_rows = self._vario_rows() + assert len(vario_rows) == anzahl_gebaut, ( + f"CSV hat {len(vario_rows)} Vario-Zeilen, " f"erwartet {anzahl_gebaut} (Anzahl GEBAUT-Faelle)" ) + def test_separator_zuordnung_konsistent(self): + """Jeder Separator zeigt (ueber Merkmale.Zuordnung) auf die TeileId + eines Vario-Eintrags DERSELBEN Datei, und je Vario-Zeile stimmt die + Anzahl seiner Separatoren mit ihrem eigenen Merkmal Anzahl_Separator + ueberein. Das ist der eigentliche Beweis, dass + csv:sep-proxies-erzeugen die verpackten Sensoren dem richtigen + Wrapper zuordnet - test_export_ids.py::test_sensor_zuordnung_existiert + prueft nur, dass die Zuordnung ueberhaupt auf eine bekannte ID zeigt.""" + vario_rows = self._vario_rows() + vario_ids = {self._cell(row, "TeileId") for row in vario_rows} + + separator_je_id = {} + for row in self._separator_rows(): + zelle = self._cell(row, "Merkmale") + if zelle is None: + continue + zuordnung = json.loads(zelle).get("Zuordnung") + assert zuordnung in vario_ids, ( + f'Separator {self._cell(row, "TeileId")}: Zuordnung ' + f"'{zuordnung}' zeigt auf keine Vario-Zeile dieser Datei" + ) + separator_je_id[zuordnung] = separator_je_id.get(zuordnung, 0) + 1 + + for row in vario_rows: + tid = self._cell(row, "TeileId") + zelle = self._cell(row, "Merkmale") + if zelle is None: + continue + soll = int(json.loads(zelle).get("Anzahl_Separator", 0)) + ist = separator_je_id.get(tid, 0) + assert soll == ist, ( + f"TeileId {tid}: Anzahl_Separator={soll}, aber {ist} " + f"Separator-Zeile(n) mit Zuordnung darauf gefunden" + ) + # --------------------------------------------------------------------------- # Klasse 4: Sivas-Export-Pruefung (foerderer_tests_sivas.csv)