233 lines
7.9 KiB
Python
233 lines
7.9 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
validate_tests.py - Validiert ILS-Test Ergebnisse gegen Referenzdateien.
|
|
|
|
Aufruf:
|
|
python validate_tests.py <results_dir> <references_dir>
|
|
|
|
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 <results_dir> <references_dir>")
|
|
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()
|