#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ validate_tests.py - Validiert ILS-Test Ergebnisse gegen Referenzdateien. Aufruf: python validate_tests.py Prueft: 1. export_raw.json: Anzahl und Typ der Bloecke 2. ILStest_export.csv: Zeilenanzahl und Inhalte gegen Referenz 3. ILStest.dxf: Existenz und KR_-Block-Anzahl """ import json import sys import os import csv def load_json(path): with open(path, "r", encoding="utf-8") as f: return json.load(f) def load_csv_lines(path): """Laedt CSV und gibt Liste von Dicts zurueck (ohne Header).""" with open(path, "r", encoding="utf-8") as f: return f.read().strip().split("\n") def validate_raw_json(results_dir): """Prueft export_raw.json auf erwartete Kreisel-Bloecke.""" raw_path = os.path.join(results_dir, "export_raw.json") if not os.path.exists(raw_path): return False, "export_raw.json nicht gefunden" blocks = load_json(raw_path) kr_blocks = [b for b in blocks if b["block_name"].startswith("KR_")] errors = [] if len(kr_blocks) != 5: errors.append(f"Erwartet 5 KR_-Bloecke, gefunden: {len(kr_blocks)}") # Pruefen ob alle Attribute haben empty_attribs = [b for b in kr_blocks if not b.get("attribs")] if empty_attribs: errors.append(f"{len(empty_attribs)} Kreisel ohne Attribute: " + ", ".join(b["block_name"] for b in empty_attribs)) # Pruefen ob erwartete Namen vorhanden expected_names = { "TEST_H_ObenUnten", "TEST_H_UntenOben", "TEST_V_LinksRechts", "TEST_V_RechtsLinks", "TEST_Insert" } found_names = set() for b in kr_blocks: attribs = b.get("attribs", {}) name = attribs.get("NAME", "") if name: found_names.add(name) missing = expected_names - found_names if missing: errors.append(f"Fehlende Kreisel-Namen: {missing}") # Pruefen der spezifischen Werte for b in kr_blocks: attribs = b.get("attribs", {}) name = attribs.get("NAME", "") if name == "TEST_Insert": if attribs.get("ABSTAND") != "6000": errors.append(f"TEST_Insert: ABSTAND={attribs.get('ABSTAND')}, erwartet 6000") if attribs.get("KREISELART") != "PIN": errors.append(f"TEST_Insert: KREISELART={attribs.get('KREISELART')}, erwartet PIN") if abs(b.get("rotation", 0) - 10.0) > 0.1: errors.append(f"TEST_Insert: rotation={b.get('rotation')}, erwartet 10") if abs(b.get("z", 0) - 2000.0) > 0.1: errors.append(f"TEST_Insert: z={b.get('z')}, erwartet 2000") if name == "TEST_H_ObenUnten": if attribs.get("KREISELART") != "STANDARD": errors.append(f"TEST_H_ObenUnten: KREISELART={attribs.get('KREISELART')}, erwartet STANDARD") if abs(b.get("rotation", 0) - 270.0) > 0.1: errors.append(f"TEST_H_ObenUnten: rotation={b.get('rotation')}, erwartet 270") if name == "TEST_H_UntenOben": if attribs.get("KREISELART") != "PIN": errors.append(f"TEST_H_UntenOben: KREISELART={attribs.get('KREISELART')}, erwartet PIN") if name == "TEST_V_LinksRechts": if attribs.get("KREISELART") != "PIN": errors.append(f"TEST_V_LinksRechts: KREISELART={attribs.get('KREISELART')}, erwartet PIN") if abs(b.get("rotation", 0) - 0.0) > 0.1: errors.append(f"TEST_V_LinksRechts: rotation={b.get('rotation')}, erwartet 0") if name == "TEST_V_RechtsLinks": if attribs.get("KREISELART") != "STANDARD": errors.append(f"TEST_V_RechtsLinks: KREISELART={attribs.get('KREISELART')}, erwartet STANDARD") if errors: return False, "export_raw.json Fehler:\n " + "\n ".join(errors) return True, f"export_raw.json OK: {len(kr_blocks)} Kreisel mit Attributen" def validate_csv(results_dir, references_dir): """Prueft CSV gegen Referenz (Zeilenanzahl, Kreisel-Anzahl).""" csv_path = os.path.join(results_dir, "ILStest_export.csv") ref_path = os.path.join(references_dir, "ILStest_export_ref.csv") if not os.path.exists(csv_path): return False, "ILStest_export.csv nicht gefunden" csv_lines = load_csv_lines(csv_path) kreisel_lines = [l for l in csv_lines[1:] if "ILS 2.0 Kreisel" in l] errors = [] if len(kreisel_lines) != 5: errors.append(f"Erwartet 5 Kreisel-Zeilen in CSV, gefunden: {len(kreisel_lines)}") # Gegen Referenz vergleichen (falls vorhanden) if os.path.exists(ref_path): ref_lines = load_csv_lines(ref_path) ref_kreisel = [l for l in ref_lines[1:] if "ILS 2.0 Kreisel" in l] if len(kreisel_lines) != len(ref_kreisel): errors.append(f"CSV hat {len(kreisel_lines)} Kreisel, Referenz hat {len(ref_kreisel)}") # Vergleiche Merkmale (ohne TeileId, da UUID) for i, (act, ref) in enumerate(zip(kreisel_lines, ref_kreisel)): # Merkmale extrahieren (letztes Feld) act_parts = act.split(";") ref_parts = ref.split(";") if len(act_parts) >= 8 and len(ref_parts) >= 8: act_merkmale = act_parts[-1] ref_merkmale = ref_parts[-1] if act_merkmale != ref_merkmale: errors.append(f"Zeile {i+1} Merkmale unterschiedlich:\n" f" IST: {act_merkmale}\n" f" SOLL: {ref_merkmale}") else: errors.append(f"Referenz-CSV nicht gefunden: {ref_path} (erster Lauf?)") if errors: return False, "CSV Fehler:\n " + "\n ".join(errors) return True, f"CSV OK: {len(kreisel_lines)} Kreisel-Zeilen" def validate_dxf(test_dir): """Prueft ob ILStest.dxf existiert und KR_-Bloecke enthaelt.""" dxf_path = os.path.join(test_dir, "ILStest.dxf") if not os.path.exists(dxf_path): return False, "ILStest.dxf nicht gefunden" # Einfache Textsuche nach KR_-Blocknamen im DXF with open(dxf_path, "r", encoding="utf-8", errors="ignore") as f: content = f.read() # Zaehle KR_-Blockreferenzen im ENTITIES-Bereich entities_start = content.find("ENTITIES") if entities_start < 0: return False, "Kein ENTITIES-Bereich in DXF" entities_section = content[entities_start:] kr_count = 0 pos = 0 while True: pos = entities_section.find("\nKR_", pos) if pos < 0: break kr_count += 1 pos += 1 if kr_count < 5: return False, f"Nur {kr_count} KR_-Referenzen in ENTITIES (erwartet mind. 5)" return True, f"DXF OK: {kr_count} KR_-Referenzen gefunden" def main(): if len(sys.argv) < 3: print("Aufruf: python validate_tests.py ") print(" results_dir = Ordner mit Testergebnissen (z.B. results/)") print(" references_dir = Ordner mit Referenzdateien (z.B. tests/references/)") sys.exit(1) results_dir = sys.argv[1] references_dir = sys.argv[2] test_dir = os.path.dirname(os.path.abspath(__file__)) print("=" * 60) print("ILS Test Validierung") print("=" * 60) all_ok = True # Test 1: export_raw.json ok, msg = validate_raw_json(results_dir) status = "PASS" if ok else "FAIL" print(f"\n[{status}] {msg}") if not ok: all_ok = False # Test 2: CSV Export ok, msg = validate_csv(results_dir, references_dir) status = "PASS" if ok else "FAIL" print(f"\n[{status}] {msg}") if not ok: all_ok = False # Test 3: DXF Datei ok, msg = validate_dxf(test_dir) status = "PASS" if ok else "FAIL" print(f"\n[{status}] {msg}") if not ok: all_ok = False print("\n" + "=" * 60) if all_ok: print("ERGEBNIS: ALLE TESTS BESTANDEN") else: print("ERGEBNIS: TESTS FEHLGESCHLAGEN") print("=" * 60) sys.exit(0 if all_ok else 1) if __name__ == "__main__": main()