debug beim Varioförderer dazu. dbgreturn routine gibt den Wert zurück. neues Test Konzept für unsere lisp Funktionen implementiert
This commit is contained in:
@@ -177,6 +177,7 @@ cython_debug/
|
|||||||
# Benutzerdefiniert
|
# Benutzerdefiniert
|
||||||
/work
|
/work
|
||||||
/log
|
/log
|
||||||
|
/tests/output/
|
||||||
|
|
||||||
# BricsCAD kompilierte Menuedateien
|
# BricsCAD kompilierte Menuedateien
|
||||||
*.cui
|
*.cui
|
||||||
|
|||||||
@@ -129,7 +129,6 @@
|
|||||||
(setq result (eval lastNrVar))
|
(setq result (eval lastNrVar))
|
||||||
(dbgp (strcat "Naechste Nummer: " (itoa result)))
|
(dbgp (strcat "Naechste Nummer: " (itoa result)))
|
||||||
(dbgreturn result)
|
(dbgreturn result)
|
||||||
result
|
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Wrapper: Naechste Kreisel-Nummer
|
;; Wrapper: Naechste Kreisel-Nummer
|
||||||
@@ -137,7 +136,6 @@
|
|||||||
(dbgf "kreisel-next-number")
|
(dbgf "kreisel-next-number")
|
||||||
(setq result (component-next-number "KREISEL_*" '#Kreisel_LetzteNr))
|
(setq result (component-next-number "KREISEL_*" '#Kreisel_LetzteNr))
|
||||||
(dbgreturn result)
|
(dbgreturn result)
|
||||||
result
|
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Wrapper: Naechste Eckrad-Nummer
|
;; Wrapper: Naechste Eckrad-Nummer
|
||||||
@@ -145,7 +143,6 @@
|
|||||||
(dbgf "eckrad-next-number")
|
(dbgf "eckrad-next-number")
|
||||||
(setq result (component-next-number "ECKRAD_*" '#Eckrad_LetzteNr))
|
(setq result (component-next-number "ECKRAD_*" '#Eckrad_LetzteNr))
|
||||||
(dbgreturn result)
|
(dbgreturn result)
|
||||||
result
|
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Beschriftungstext erzeugen
|
;; Beschriftungstext erzeugen
|
||||||
|
|||||||
@@ -601,8 +601,8 @@
|
|||||||
|
|
||||||
;; 5. Erster Vertikalbogen
|
;; 5. Erster Vertikalbogen
|
||||||
(if (= richtung "Auf")
|
(if (= richtung "Auf")
|
||||||
(setq bogen-name (strcat "Vario_Bogen_auf_" (itoa best-winkel)))
|
(setq bogen-name (strcat "Vario_Bogen_auf_" (itoa best-winkel) grad-zeichen))
|
||||||
(setq bogen-name (strcat "Vario_Bogen_ab_" (itoa best-winkel)))
|
(setq bogen-name (strcat "Vario_Bogen_ab_" (itoa best-winkel) grad-zeichen))
|
||||||
)
|
)
|
||||||
(princ (strcat "\n\n5/11: " bogen-name))
|
(princ (strcat "\n\n5/11: " bogen-name))
|
||||||
(setq aktueller-punkt (insert-block-by-ks bogen-name aktueller-punkt))
|
(setq aktueller-punkt (insert-block-by-ks bogen-name aktueller-punkt))
|
||||||
@@ -646,8 +646,8 @@
|
|||||||
|
|
||||||
;; 7. Zweiter Vertikalbogen (gegenläufig)
|
;; 7. Zweiter Vertikalbogen (gegenläufig)
|
||||||
(if (= richtung "Auf")
|
(if (= richtung "Auf")
|
||||||
(setq bogen-name (strcat "Vario_Bogen_ab_" (itoa best-winkel)))
|
(setq bogen-name (strcat "Vario_Bogen_ab_" (itoa best-winkel) grad-zeichen))
|
||||||
(setq bogen-name (strcat "Vario_Bogen_auf_" (itoa best-winkel)))
|
(setq bogen-name (strcat "Vario_Bogen_auf_" (itoa best-winkel) grad-zeichen))
|
||||||
)
|
)
|
||||||
(princ (strcat "\n\n7/11: " bogen-name))
|
(princ (strcat "\n\n7/11: " bogen-name))
|
||||||
(setq aktueller-punkt (insert-block-by-ks bogen-name aktueller-punkt))
|
(setq aktueller-punkt (insert-block-by-ks bogen-name aktueller-punkt))
|
||||||
|
|||||||
+1
-1
@@ -229,7 +229,7 @@
|
|||||||
(dbg-flush)
|
(dbg-flush)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(princ)
|
retval
|
||||||
)
|
)
|
||||||
|
|
||||||
;; ------------------------------------------------------------
|
;; ------------------------------------------------------------
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ set "DXFM_BIN=%DXFMAKRO%\bin"
|
|||||||
set "DXFM_LIB=%DXFMAKRO%\lib"
|
set "DXFM_LIB=%DXFMAKRO%\lib"
|
||||||
set "DXFM_DATA=%DXFMAKRO%\data"
|
set "DXFM_DATA=%DXFMAKRO%\data"
|
||||||
set "DXFM_TESTS=%DXFMAKRO%\tests"
|
set "DXFM_TESTS=%DXFMAKRO%\tests"
|
||||||
|
set "DXFM_TESTDATA=%DXFM_TESTS%\testdata"
|
||||||
|
set "DXFM_TESTOUT=%DXFM_TESTS%\output"
|
||||||
|
set "DXFM_TESTREF=%DXFM_TESTS%\reference"
|
||||||
set "DXFM_CFG=%DXFMAKRO%\cfg"
|
set "DXFM_CFG=%DXFMAKRO%\cfg"
|
||||||
set "DXFM_LOG=%DXFMAKRO%\logs"
|
set "DXFM_LOG=%DXFMAKRO%\logs"
|
||||||
set "DXFM_BLOCKS=%DXFMAKRO%\Blocks"
|
set "DXFM_BLOCKS=%DXFMAKRO%\Blocks"
|
||||||
@@ -42,6 +45,9 @@ if not exist "%DXFM_BLOCKS%" mkdir "%DXFM_BLOCKS%"
|
|||||||
if not exist "%DXFM_LISP%" mkdir "%DXFM_LISP%"
|
if not exist "%DXFM_LISP%" mkdir "%DXFM_LISP%"
|
||||||
if not exist "%DXFM_LOG%" mkdir "%DXFM_LOG%"
|
if not exist "%DXFM_LOG%" mkdir "%DXFM_LOG%"
|
||||||
if not exist "%DXFM_RESULTS%" mkdir "%DXFM_RESULTS%"
|
if not exist "%DXFM_RESULTS%" mkdir "%DXFM_RESULTS%"
|
||||||
|
if not exist "%DXFM_TESTDATA%" mkdir "%DXFM_TESTDATA%"
|
||||||
|
if not exist "%DXFM_TESTOUT%" mkdir "%DXFM_TESTOUT%"
|
||||||
|
if not exist "%DXFM_TESTREF%" mkdir "%DXFM_TESTREF%"
|
||||||
|
|
||||||
REM Umgebungsvariablen anzeigen
|
REM Umgebungsvariablen anzeigen
|
||||||
echo.
|
echo.
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
;; ============================================================
|
|
||||||
;; ILS_test.lsp - Automatisierter ILS Kreisel-Test
|
|
||||||
;;
|
|
||||||
;; Oeffnet ILStest.dxf, erzeugt 5 Kreisel per draw-module
|
|
||||||
;; (gleiche Kernfunktion wie KreiselConnect/KreiselInsert),
|
|
||||||
;; exportiert CSV und speichert.
|
|
||||||
;;
|
|
||||||
;; Voraussetzung: SSG_LIB muss geladen sein (ssg_load.lsp).
|
|
||||||
;; ============================================================
|
|
||||||
|
|
||||||
(defun c:ILSTEST ( / test-pfad dxf-pfad abstand z-hoehe)
|
|
||||||
|
|
||||||
(princ "\n========== ILS TEST START ==========")
|
|
||||||
|
|
||||||
(setq test-pfad (getenv "DXFM_TESTS"))
|
|
||||||
(if (null test-pfad)
|
|
||||||
(progn (princ "\nFEHLER: DXFM_TESTS nicht gesetzt!") (exit))
|
|
||||||
)
|
|
||||||
|
|
||||||
;; DXF oeffnen (erzeugt durch create_ILStest_dxf.py)
|
|
||||||
(setq dxf-pfad (strcat test-pfad "/ILStest.dxf"))
|
|
||||||
(if (not (findfile dxf-pfad))
|
|
||||||
(progn (princ (strcat "\nFEHLER: " dxf-pfad " nicht gefunden!")) (exit))
|
|
||||||
)
|
|
||||||
(command "_.OPEN" dxf-pfad)
|
|
||||||
|
|
||||||
;; Konstanten fuer die Geometrie
|
|
||||||
;; Linien: H1 bei Y=0, H2 bei Y=5000, V1 bei X=0, V2 bei X=5000
|
|
||||||
;; Alle auf Z=2500, je 2000mm lang
|
|
||||||
;; Kreiseldurchmesser=800 -> Abstand = Linienabstand - Durchmesser
|
|
||||||
(setq abstand (- 5000.0 *kreisel-durchmesser*)) ;; 4200mm
|
|
||||||
(setq z-hoehe 2500.0)
|
|
||||||
|
|
||||||
(ssg-start "ILS TEST" '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA")))
|
|
||||||
(setvar "OSMODE" 0)
|
|
||||||
(setvar "ATTREQ" 0)
|
|
||||||
(setvar "ATTDIA" 0)
|
|
||||||
|
|
||||||
;; ---- Kreisel 1: Horizontal, oben->unten (90°), STANDARD ----
|
|
||||||
;; AN-Punkt auf H2 (Y=5000), SP-Richtung nach unten (Y=0)
|
|
||||||
;; Rotation 270° = von oben nach unten
|
|
||||||
(princ "\n[TEST] Kreisel 1: Horizontal oben->unten, STANDARD")
|
|
||||||
(draw-module (list 500.0 5000.0 z-hoehe)
|
|
||||||
abstand 270.0
|
|
||||||
(list (cons "KREISELART" "STANDARD")
|
|
||||||
(cons "NAME" "TEST_H_ObenUnten")))
|
|
||||||
|
|
||||||
;; ---- Kreisel 2: Horizontal, unten->oben (270°), PIN ----
|
|
||||||
;; AN-Punkt auf H1 (Y=0), SP-Richtung nach oben (Y=5000)
|
|
||||||
;; Rotation 90° = von unten nach oben
|
|
||||||
(princ "\n[TEST] Kreisel 2: Horizontal unten->oben, PIN")
|
|
||||||
(draw-module (list 1500.0 0.0 z-hoehe)
|
|
||||||
abstand 90.0
|
|
||||||
(list (cons "KREISELART" "PIN")
|
|
||||||
(cons "NAME" "TEST_H_UntenOben")))
|
|
||||||
|
|
||||||
;; ---- Kreisel 3: Vertikal, links->rechts (0°), PIN ----
|
|
||||||
;; AN-Punkt auf V1 (X=0), SP-Richtung nach rechts (X=5000)
|
|
||||||
;; Rotation 0° = von links nach rechts
|
|
||||||
(princ "\n[TEST] Kreisel 3: Vertikal links->rechts, PIN")
|
|
||||||
(draw-module (list 0.0 500.0 z-hoehe)
|
|
||||||
abstand 0.0
|
|
||||||
(list (cons "KREISELART" "PIN")
|
|
||||||
(cons "NAME" "TEST_V_LinksRechts")))
|
|
||||||
|
|
||||||
;; ---- Kreisel 4: Vertikal, rechts->links (180°), STANDARD ----
|
|
||||||
;; AN-Punkt auf V2 (X=5000), SP-Richtung nach links (X=0)
|
|
||||||
;; Rotation 180° = von rechts nach links
|
|
||||||
(princ "\n[TEST] Kreisel 4: Vertikal rechts->links, STANDARD")
|
|
||||||
(draw-module (list 5000.0 1500.0 z-hoehe)
|
|
||||||
abstand 180.0
|
|
||||||
(list (cons "KREISELART" "STANDARD")
|
|
||||||
(cons "NAME" "TEST_V_RechtsLinks")))
|
|
||||||
|
|
||||||
;; ---- Kreisel 5: KreiselInsert-Equivalent ----
|
|
||||||
;; Position 3000/3000/2000, 6000mm lang, PIN, 10 Grad
|
|
||||||
(princ "\n[TEST] Kreisel 5: Insert 3000/3000/2000, 6000mm, PIN, 10°")
|
|
||||||
(draw-module (list 3000.0 3000.0 2000.0)
|
|
||||||
6000.0 10.0
|
|
||||||
(list (cons "KREISELART" "PIN")
|
|
||||||
(cons "NAME" "TEST_Insert")))
|
|
||||||
|
|
||||||
(ssg-end)
|
|
||||||
|
|
||||||
;; Speichern als DXF
|
|
||||||
(command "_.SAVEAS" "DXF" (strcat test-pfad "/ILStest.dxf") "_Y")
|
|
||||||
(princ "\n[TEST] DXF gespeichert.")
|
|
||||||
|
|
||||||
;; Export CSV (nutzt csv:run-export aus tests.lsp)
|
|
||||||
;; Ergebnisse landen in DXFM_RESULTS
|
|
||||||
(princ "\n[TEST] Starte CSV-Export...")
|
|
||||||
(csv:run-export "ILSTEST" "export_csv.py" "ILStest_export.csv")
|
|
||||||
|
|
||||||
(princ "\n========== ILS TEST ENDE ==========")
|
|
||||||
(princ)
|
|
||||||
)
|
|
||||||
|
|
||||||
(princ "\nILS_test.lsp geladen. Befehl: ILSTEST")
|
|
||||||
(princ)
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
(load (strcat (getenv "DXFM_LISP") "/on_start.lsp"))
|
|
||||||
_.OPEN
|
|
||||||
(strcat (getenv "DXFM_TESTS") "/ILStest.dxf")
|
|
||||||
(load (strcat (getenv "DXFM_TESTS") "/ILS_test.lsp"))
|
|
||||||
ILSTEST
|
|
||||||
-3174
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
conftest.py - pytest Fixtures fuer SSG_LIB Tests.
|
||||||
|
|
||||||
|
Stellt gemeinsame Fixtures bereit:
|
||||||
|
- Pfade zu testdata/, output/, reference/
|
||||||
|
- Laden von JSON-Testdefinitionen und -Ergebnissen
|
||||||
|
- Laden von DXF-Dateien mit ezdxf
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
import ezdxf
|
||||||
|
|
||||||
|
|
||||||
|
def _tests_dir():
|
||||||
|
return os.getenv("DXFM_TESTS", os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
|
def _testdata_dir():
|
||||||
|
return os.getenv("DXFM_TESTDATA", os.path.join(_tests_dir(), "testdata"))
|
||||||
|
|
||||||
|
|
||||||
|
def _output_dir():
|
||||||
|
return os.getenv("DXFM_TESTOUT", os.path.join(_tests_dir(), "output"))
|
||||||
|
|
||||||
|
|
||||||
|
def _reference_dir():
|
||||||
|
return os.getenv("DXFM_TESTREF", os.path.join(_tests_dir(), "reference"))
|
||||||
|
|
||||||
|
|
||||||
|
def _load_json(path):
|
||||||
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Kreisel Fixtures ---
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def kreisel_testdata():
|
||||||
|
"""Laedt die Kreisel-Testdefinitionen aus testdata/kreisel_tests.json."""
|
||||||
|
path = os.path.join(_testdata_dir(), "kreisel_tests.json")
|
||||||
|
return _load_json(path)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def kreisel_results():
|
||||||
|
"""Laedt die Kreisel-Ergebnisse aus output/kreisel_results.json."""
|
||||||
|
path = os.path.join(_output_dir(), "kreisel_results.json")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
pytest.skip("kreisel_results.json nicht vorhanden - TESTRUN in BricsCAD ausfuehren")
|
||||||
|
return _load_json(path)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def kreisel_dxf():
|
||||||
|
"""Laedt die erzeugte Kreisel-DXF aus output/kreisel_tests.dxf."""
|
||||||
|
path = os.path.join(_output_dir(), "kreisel_tests.dxf")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
pytest.skip("kreisel_tests.dxf nicht vorhanden - TESTRUN in BricsCAD ausfuehren")
|
||||||
|
return ezdxf.readfile(path)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def kreisel_ref_dxf():
|
||||||
|
"""Laedt die Referenz-DXF aus reference/kreisel_ref.dxf."""
|
||||||
|
path = os.path.join(_reference_dir(), "kreisel_ref.dxf")
|
||||||
|
if not os.path.exists(path):
|
||||||
|
pytest.skip("kreisel_ref.dxf nicht vorhanden - Referenz noch nicht erstellt")
|
||||||
|
return ezdxf.readfile(path)
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
create_ILStest_dxf.py - Erzeugt die Basis-DXF fuer den ILS-Test.
|
|
||||||
|
|
||||||
Erstellt 4 Linien als Grundlage fuer KreiselConnect:
|
|
||||||
- 2 horizontale Linien, 5000mm Abstand, je 2000mm lang, ab (0,0,2500)
|
|
||||||
- 2 vertikale Linien, 5000mm Abstand, je 2000mm lang, ab (0,0,2500)
|
|
||||||
"""
|
|
||||||
|
|
||||||
import ezdxf
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def create_ils_test_dxf(output_path):
|
|
||||||
doc = ezdxf.new("R2018")
|
|
||||||
msp = doc.modelspace()
|
|
||||||
|
|
||||||
z = 2500.0
|
|
||||||
|
|
||||||
# Horizontale Linienpaare (Abstand 5000mm in Y-Richtung)
|
|
||||||
# H1: (0,0,2500) -> (2000,0,2500)
|
|
||||||
msp.add_line((0, 0, z), (2000, 0, z), dxfattribs={"layer": "S_LP", "color": 1})
|
|
||||||
# H2: (0,5000,2500) -> (2000,5000,2500)
|
|
||||||
msp.add_line((0, 5000, z), (2000, 5000, z), dxfattribs={"layer": "S_LP", "color": 1})
|
|
||||||
|
|
||||||
# Vertikale Linienpaare (Abstand 5000mm in X-Richtung)
|
|
||||||
# V1: (0,0,2500) -> (0,2000,2500)
|
|
||||||
msp.add_line((0, 0, z), (0, 2000, z), dxfattribs={"layer": "S_LP", "color": 1})
|
|
||||||
# V2: (5000,0,2500) -> (5000,2000,2500)
|
|
||||||
msp.add_line((5000, 0, z), (5000, 2000, z), dxfattribs={"layer": "S_LP", "color": 1})
|
|
||||||
|
|
||||||
doc.saveas(output_path)
|
|
||||||
print(f"[ILStest] DXF erstellt: {output_path}")
|
|
||||||
return output_path
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
out = sys.argv[1]
|
|
||||||
else:
|
|
||||||
out = os.path.join(os.getenv("DXFM_TESTS", "tests"), "ILStest.dxf")
|
|
||||||
create_ils_test_dxf(out)
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
create_testbase.py - Erzeugt Basis-DXF-Dateien fuer die LISP-Tests.
|
||||||
|
|
||||||
|
Erstellt pro Modul eine leere DXF mit Hilfsgeometrie (z.B. Linien
|
||||||
|
als Andockpunkte fuer Kreisel).
|
||||||
|
|
||||||
|
Aufruf:
|
||||||
|
python tests/create_testbase.py [modul]
|
||||||
|
python tests/create_testbase.py # alle Module
|
||||||
|
python tests/create_testbase.py kreisel # nur Kreisel
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ezdxf
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
TESTDATA_DIR = os.path.join(TESTS_DIR, "testdata")
|
||||||
|
OUTPUT_DIR = os.path.join(TESTS_DIR, "output")
|
||||||
|
|
||||||
|
|
||||||
|
def create_kreisel_testbase():
|
||||||
|
"""Erzeugt Basis-DXF fuer Kreisel-Tests mit Hilfslinien."""
|
||||||
|
doc = ezdxf.new("R2018")
|
||||||
|
msp = doc.modelspace()
|
||||||
|
|
||||||
|
z = 2500.0
|
||||||
|
|
||||||
|
# Horizontale Linienpaare (Abstand 5000mm in Y-Richtung)
|
||||||
|
msp.add_line((0, 0, z), (2000, 0, z),
|
||||||
|
dxfattribs={"layer": "S_LP", "color": 1})
|
||||||
|
msp.add_line((0, 5000, z), (2000, 5000, z),
|
||||||
|
dxfattribs={"layer": "S_LP", "color": 1})
|
||||||
|
|
||||||
|
# Vertikale Linienpaare (Abstand 5000mm in X-Richtung)
|
||||||
|
msp.add_line((0, 0, z), (0, 2000, z),
|
||||||
|
dxfattribs={"layer": "S_LP", "color": 1})
|
||||||
|
msp.add_line((5000, 0, z), (5000, 2000, z),
|
||||||
|
dxfattribs={"layer": "S_LP", "color": 1})
|
||||||
|
|
||||||
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||||
|
out_path = os.path.join(OUTPUT_DIR, "kreisel_testbase.dxf")
|
||||||
|
doc.saveas(out_path)
|
||||||
|
print(f"[testbase] Kreisel-Basis-DXF erstellt: {out_path}")
|
||||||
|
return out_path
|
||||||
|
|
||||||
|
|
||||||
|
MODULES = {
|
||||||
|
"kreisel": create_kreisel_testbase,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
modul = sys.argv[1].lower()
|
||||||
|
if modul not in MODULES:
|
||||||
|
print(f"Unbekanntes Modul: {modul}")
|
||||||
|
print(f"Verfuegbar: {', '.join(MODULES.keys())}")
|
||||||
|
sys.exit(1)
|
||||||
|
MODULES[modul]()
|
||||||
|
else:
|
||||||
|
for name, func in MODULES.items():
|
||||||
|
func()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
Elementnummer;TeileArt;TeileId;NachbarIds;Bezeichnung;Planquadrat;rotation;Merkmale
|
|
||||||
0;"ILS 2.0 Kreisel";"REF_PLACEHOLDER";;"Kreisel :1";"X:500.00 Y:5000.00";;{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "4.2", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.5", "Drehrichtung": "UZS", "Drehung": 270, "Name": "TEST_H_ObenUnten"}
|
|
||||||
1;"ILS 2.0 Kreisel";"REF_PLACEHOLDER";;"Kreisel :2";"X:1500.00 Y:0.00";;{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "4.2", "Anzahl der Separatoren": "2", "Kreiselart": "PIN", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.5", "Drehrichtung": "UZS", "Drehung": 90, "Name": "TEST_H_UntenOben"}
|
|
||||||
2;"ILS 2.0 Kreisel";"REF_PLACEHOLDER";;"Kreisel :3";"X:0.00 Y:500.00";;{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "4.2", "Anzahl der Separatoren": "2", "Kreiselart": "PIN", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.5", "Drehrichtung": "UZS", "Drehung": 0, "Name": "TEST_V_LinksRechts"}
|
|
||||||
3;"ILS 2.0 Kreisel";"REF_PLACEHOLDER";;"Kreisel :4";"X:5000.00 Y:1500.00";;{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "4.2", "Anzahl der Separatoren": "2", "Kreiselart": "STANDARD", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.5", "Drehrichtung": "UZS", "Drehung": 180, "Name": "TEST_V_RechtsLinks"}
|
|
||||||
4;"ILS 2.0 Kreisel";"REF_PLACEHOLDER";;"Kreisel :5";"X:3000.00 Y:3000.00";;{"Abstand (Kreiselachse A - Kreiselachse) in Meter": "6.0", "Anzahl der Separatoren": "2", "Kreiselart": "PIN", "Anzahl der Scanner": "0", "Anzahl der Rampen": "0", "Höhe in m": "2.0", "Drehrichtung": "UZS", "Drehung": 10, "Name": "TEST_Insert"}
|
|
||||||
|
Can't render this file because it contains an unexpected character in line 2 and column 76.
|
@@ -0,0 +1,2 @@
|
|||||||
|
ezdxf>=1.0
|
||||||
|
pytest>=7.0
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_kreisel.py - Validiert ILS Kreisel Testergebnisse.
|
||||||
|
|
||||||
|
Prueft:
|
||||||
|
1. Attributwerte aus results.json gegen Testdefinitionen
|
||||||
|
2. DXF-Geometrie mit ezdxf (Block-Existenz, Radien, Linien)
|
||||||
|
3. Referenz-Vergleich gegen abgenommene DXF
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Attribut-Pruefung (results.json vs. testdata)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
class TestKreiselAttributes:
|
||||||
|
"""Prueft ob Attribute korrekt gesetzt wurden."""
|
||||||
|
|
||||||
|
def test_all_tests_executed(self, kreisel_testdata, kreisel_results):
|
||||||
|
"""Alle definierten Testfaelle muessen ausgefuehrt worden sein."""
|
||||||
|
expected_ids = {t["id"] for t in kreisel_testdata["tests"]}
|
||||||
|
result_ids = {r["test_id"] for r in kreisel_results}
|
||||||
|
missing = expected_ids - result_ids
|
||||||
|
assert not missing, f"Nicht ausgefuehrte Tests: {missing}"
|
||||||
|
|
||||||
|
def test_all_executed_successfully(self, kreisel_results):
|
||||||
|
"""Alle Ergebnisse muessen Status 'executed' haben."""
|
||||||
|
for result in kreisel_results:
|
||||||
|
assert result["status"] == "executed", \
|
||||||
|
f'{result["test_id"]}: Status={result["status"]}'
|
||||||
|
|
||||||
|
def test_attributes_match(self, kreisel_testdata, kreisel_results):
|
||||||
|
"""Erwartete Attribute muessen mit tatsaechlichen uebereinstimmen."""
|
||||||
|
results_by_id = {r["test_id"]: r for r in kreisel_results}
|
||||||
|
for test in kreisel_testdata["tests"]:
|
||||||
|
result = results_by_id.get(test["id"])
|
||||||
|
if not result:
|
||||||
|
continue
|
||||||
|
for attr, expected in test["expect"]["attributes"].items():
|
||||||
|
actual = result["actual_attributes"].get(attr)
|
||||||
|
assert actual == expected, \
|
||||||
|
f'{test["id"]}: {attr} erwartet="{expected}", ist="{actual}"'
|
||||||
|
|
||||||
|
def test_block_prefix(self, kreisel_testdata, kreisel_results):
|
||||||
|
"""Block-Namen muessen mit erwartetem Praefix beginnen."""
|
||||||
|
results_by_id = {r["test_id"]: r for r in kreisel_results}
|
||||||
|
for test in kreisel_testdata["tests"]:
|
||||||
|
result = results_by_id.get(test["id"])
|
||||||
|
if not result:
|
||||||
|
continue
|
||||||
|
prefix = test["expect"]["block_prefix"]
|
||||||
|
assert result["block_name"].startswith(prefix), \
|
||||||
|
f'{test["id"]}: Block "{result["block_name"]}" beginnt nicht mit "{prefix}"'
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# DXF Geometrie-Pruefung (ezdxf)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
class TestKreiselGeometry:
|
||||||
|
"""Prueft DXF-Geometrie mit ezdxf."""
|
||||||
|
|
||||||
|
def test_blocks_in_modelspace(self, kreisel_dxf, kreisel_results):
|
||||||
|
"""Alle erzeugten Bloecke muessen im Modelspace vorhanden sein."""
|
||||||
|
msp = kreisel_dxf.modelspace()
|
||||||
|
inserts = [e for e in msp if e.dxftype() == "INSERT"]
|
||||||
|
insert_handles = {e.dxf.handle for e in inserts}
|
||||||
|
for result in kreisel_results:
|
||||||
|
assert result["block_handle"] in insert_handles, \
|
||||||
|
f'{result["test_id"]}: Block-Handle {result["block_handle"]} nicht im Modelspace'
|
||||||
|
|
||||||
|
def test_kr_block_count(self, kreisel_dxf, kreisel_testdata):
|
||||||
|
"""Anzahl KR_-Bloecke muss Testfall-Anzahl entsprechen."""
|
||||||
|
msp = kreisel_dxf.modelspace()
|
||||||
|
kr_inserts = [e for e in msp if e.dxftype() == "INSERT"
|
||||||
|
and e.dxf.name.startswith("KR_")]
|
||||||
|
expected_count = len(kreisel_testdata["tests"])
|
||||||
|
assert len(kr_inserts) >= expected_count, \
|
||||||
|
f"Erwartet mind. {expected_count} KR_-Bloecke, gefunden: {len(kr_inserts)}"
|
||||||
|
|
||||||
|
def test_circle_radius(self, kreisel_dxf):
|
||||||
|
"""AN8/SP8 Kreise in KR_-Bloecken muessen Radius 400mm haben."""
|
||||||
|
for block in kreisel_dxf.blocks:
|
||||||
|
if not block.name.startswith("KR_"):
|
||||||
|
continue
|
||||||
|
circles = [e for e in block if e.dxftype() == "CIRCLE"]
|
||||||
|
for c in circles:
|
||||||
|
assert abs(c.dxf.radius - 400.0) < 0.1, \
|
||||||
|
f'Block {block.name}: Kreis-Radius={c.dxf.radius}, erwartet=400.0'
|
||||||
|
|
||||||
|
def test_insert_positions(self, kreisel_dxf, kreisel_results):
|
||||||
|
"""Insertionspunkte muessen mit results.json uebereinstimmen."""
|
||||||
|
msp = kreisel_dxf.modelspace()
|
||||||
|
inserts_by_handle = {e.dxf.handle: e for e in msp if e.dxftype() == "INSERT"}
|
||||||
|
for result in kreisel_results:
|
||||||
|
insert = inserts_by_handle.get(result["block_handle"])
|
||||||
|
if not insert:
|
||||||
|
continue
|
||||||
|
expected = result["insert_point"]
|
||||||
|
actual = insert.dxf.insert
|
||||||
|
assert abs(actual.x - expected[0]) < 1.0, \
|
||||||
|
f'{result["test_id"]}: X={actual.x}, erwartet={expected[0]}'
|
||||||
|
assert abs(actual.y - expected[1]) < 1.0, \
|
||||||
|
f'{result["test_id"]}: Y={actual.y}, erwartet={expected[1]}'
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Referenz-Vergleich
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
class TestKreiselReference:
|
||||||
|
"""Vergleicht Ergebnis gegen abgenommene Referenz-DXF."""
|
||||||
|
|
||||||
|
def test_block_count_matches_reference(self, kreisel_dxf, kreisel_ref_dxf):
|
||||||
|
"""Anzahl KR_-Bloecke muss mit Referenz uebereinstimmen."""
|
||||||
|
output_kr = sum(1 for e in kreisel_dxf.modelspace()
|
||||||
|
if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_"))
|
||||||
|
ref_kr = sum(1 for e in kreisel_ref_dxf.modelspace()
|
||||||
|
if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_"))
|
||||||
|
assert output_kr == ref_kr, \
|
||||||
|
f"Block-Anzahl: output={output_kr}, referenz={ref_kr}"
|
||||||
|
|
||||||
|
def test_block_types_match_reference(self, kreisel_dxf, kreisel_ref_dxf):
|
||||||
|
"""Block-Typen muessen mit Referenz uebereinstimmen."""
|
||||||
|
output_names = sorted(e.dxf.name for e in kreisel_dxf.modelspace()
|
||||||
|
if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_"))
|
||||||
|
ref_names = sorted(e.dxf.name for e in kreisel_ref_dxf.modelspace()
|
||||||
|
if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_"))
|
||||||
|
assert output_names == ref_names, \
|
||||||
|
f"Block-Typen unterschiedlich:\n output: {output_names}\n referenz: {ref_names}"
|
||||||
Vendored
+125
@@ -0,0 +1,125 @@
|
|||||||
|
{
|
||||||
|
"module": "Kreisel",
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "ILS Kreisel Testfaelle - alle Richtungen und Kreiselarten",
|
||||||
|
"base_dxf": "kreisel_testbase.dxf",
|
||||||
|
"output_dxf": "kreisel_tests.dxf",
|
||||||
|
"output_results": "kreisel_results.json",
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"id": "KR_Horiz_ObenUnten",
|
||||||
|
"function": "draw-module",
|
||||||
|
"description": "Horizontaler Kreisel, oben nach unten, STANDARD",
|
||||||
|
"params": {
|
||||||
|
"basepoint": [500.0, 5000.0, 2500.0],
|
||||||
|
"abstand": 4200.0,
|
||||||
|
"rotation": 270.0,
|
||||||
|
"attribs": {
|
||||||
|
"KREISELART": "STANDARD",
|
||||||
|
"NAME": "TEST_H_ObenUnten"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expect": {
|
||||||
|
"attributes": {
|
||||||
|
"KREISELART": "STANDARD",
|
||||||
|
"DREHUNG": "270.0",
|
||||||
|
"ABSTAND": "4200"
|
||||||
|
},
|
||||||
|
"block_prefix": "KR_",
|
||||||
|
"min_entities": 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KR_Horiz_UntenOben",
|
||||||
|
"function": "draw-module",
|
||||||
|
"description": "Horizontaler Kreisel, unten nach oben, PIN",
|
||||||
|
"params": {
|
||||||
|
"basepoint": [1500.0, 0.0, 2500.0],
|
||||||
|
"abstand": 4200.0,
|
||||||
|
"rotation": 90.0,
|
||||||
|
"attribs": {
|
||||||
|
"KREISELART": "PIN",
|
||||||
|
"NAME": "TEST_H_UntenOben"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expect": {
|
||||||
|
"attributes": {
|
||||||
|
"KREISELART": "PIN",
|
||||||
|
"DREHUNG": "90.0",
|
||||||
|
"ABSTAND": "4200"
|
||||||
|
},
|
||||||
|
"block_prefix": "KR_",
|
||||||
|
"min_entities": 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KR_Vert_LinksRechts",
|
||||||
|
"function": "draw-module",
|
||||||
|
"description": "Vertikaler Kreisel, links nach rechts, PIN",
|
||||||
|
"params": {
|
||||||
|
"basepoint": [0.0, 500.0, 2500.0],
|
||||||
|
"abstand": 4200.0,
|
||||||
|
"rotation": 0.0,
|
||||||
|
"attribs": {
|
||||||
|
"KREISELART": "PIN",
|
||||||
|
"NAME": "TEST_V_LinksRechts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expect": {
|
||||||
|
"attributes": {
|
||||||
|
"KREISELART": "PIN",
|
||||||
|
"DREHUNG": "0.0",
|
||||||
|
"ABSTAND": "4200"
|
||||||
|
},
|
||||||
|
"block_prefix": "KR_",
|
||||||
|
"min_entities": 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KR_Vert_RechtsLinks",
|
||||||
|
"function": "draw-module",
|
||||||
|
"description": "Vertikaler Kreisel, rechts nach links, STANDARD",
|
||||||
|
"params": {
|
||||||
|
"basepoint": [5000.0, 1500.0, 2500.0],
|
||||||
|
"abstand": 4200.0,
|
||||||
|
"rotation": 180.0,
|
||||||
|
"attribs": {
|
||||||
|
"KREISELART": "STANDARD",
|
||||||
|
"NAME": "TEST_V_RechtsLinks"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expect": {
|
||||||
|
"attributes": {
|
||||||
|
"KREISELART": "STANDARD",
|
||||||
|
"DREHUNG": "180.0",
|
||||||
|
"ABSTAND": "4200"
|
||||||
|
},
|
||||||
|
"block_prefix": "KR_",
|
||||||
|
"min_entities": 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KR_Insert_Schraeg",
|
||||||
|
"function": "draw-module",
|
||||||
|
"description": "Kreisel mit 10 Grad Drehung, 6000mm Abstand, PIN",
|
||||||
|
"params": {
|
||||||
|
"basepoint": [3000.0, 3000.0, 2000.0],
|
||||||
|
"abstand": 6000.0,
|
||||||
|
"rotation": 10.0,
|
||||||
|
"attribs": {
|
||||||
|
"KREISELART": "PIN",
|
||||||
|
"NAME": "TEST_Insert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expect": {
|
||||||
|
"attributes": {
|
||||||
|
"KREISELART": "PIN",
|
||||||
|
"DREHUNG": "10.0",
|
||||||
|
"ABSTAND": "6000"
|
||||||
|
},
|
||||||
|
"block_prefix": "KR_",
|
||||||
|
"min_entities": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,232 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
Reference in New Issue
Block a user