diff --git a/Lisp/external_call.lsp b/Lisp/external_call.lsp new file mode 100644 index 0000000..0422d2f --- /dev/null +++ b/Lisp/external_call.lsp @@ -0,0 +1,29 @@ +;; ============================================================ +;; tests.lsp - Test- und Hilfsfunktionen +;; +;; Export-Funktionen wurden nach export.lsp ausgelagert. +;; ============================================================ + +(defun c:CALLPYTHON ( / log-pfad py-skript return-datei cmd fh zeile) + (setq log-pfad (getenv "DXFM_LOG")) + (setq py-skript (strcat (getenv "DXFM_LIB") "\\testpycall.py")) + (setq return-datei (strcat log-pfad "\\testpycall_return.txt")) + (if (findfile py-skript) + (progn + (setq cmd (strcat "python \"" py-skript "\" \"" log-pfad "\"")) + (command "_.SHELL" cmd) + (if (findfile return-datei) + (progn + (setq fh (open return-datei "r")) + (setq zeile (read-line fh)) + (close fh) + (princ (strcat "\n[SSG_LIB] Python Rueckgabe: " zeile)) + ) + (princ "\n[SSG_LIB] WARNUNG: Keine Rueckgabe von Python erhalten.") + ) + ) + (princ (strcat "\n[SSG_LIB] FEHLER: " py-skript " nicht gefunden!")) + ) + (princ) +) + diff --git a/Lisp/tests.lsp b/Lisp/tests.lsp deleted file mode 100644 index 1b88e8e..0000000 --- a/Lisp/tests.lsp +++ /dev/null @@ -1,466 +0,0 @@ -;; ============================================================ -;; tests.lsp - Test- und Hilfsfunktionen -;; -;; Export-Funktionen wurden nach export.lsp ausgelagert. -;; ============================================================ - -(defun c:CALLPYTHON ( / log-pfad py-skript return-datei cmd fh zeile) - (setq log-pfad (getenv "DXFM_LOG")) - (setq py-skript (strcat (getenv "DXFM_LIB") "\\testpycall.py")) - (setq return-datei (strcat log-pfad "\\testpycall_return.txt")) - (if (findfile py-skript) - (progn - (setq cmd (strcat "python \"" py-skript "\" \"" log-pfad "\"")) - (command "_.SHELL" cmd) - (if (findfile return-datei) - (progn - (setq fh (open return-datei "r")) - (setq zeile (read-line fh)) - (close fh) - (princ (strcat "\n[SSG_LIB] Python Rueckgabe: " zeile)) - ) - (princ "\n[SSG_LIB] WARNUNG: Keine Rueckgabe von Python erhalten.") - ) - ) - (princ (strcat "\n[SSG_LIB] FEHLER: " py-skript " nicht gefunden!")) - ) - (princ) -) - -;; ============================================================ -;; TEST_FOERDERER - Automatischer Test ohne Benutzereingabe -;; Erzeugt 12 Variofoerderer (6x Auf, 6x Ab) mit deltaL=7000 -;; und verschiedenen Hoehenstufen. Tabellarische Zusammenfassung. -;; ============================================================ -(defun c:TEST_FOERDERER ( / deltaL deltaH richtung ergebnis - best-winkel L_GF L_VF dateiname - y-offset hoehen-liste idx - anz-gebaut anz-nicht-gebaut - result-pfad erfolgsquote - zusammenfassung-liste - nr deltaH_val status winkel L_GF_val L_VF_val) - - ;; Bibliothek initialisieren (laedt Block-Library und extrahiert Masse) - (if (not *lib-initialized*) - (init-bibliothek) - ) - - (ssg-start "TEST_FOERDERER" '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) - (setvar "OSMODE" 0) - (setvar "ATTREQ" 0) - (setvar "ATTDIA" 0) - - (setq deltaL 7000) - (setq hoehen-liste '(0 1000 2000 3000 4000 5000)) - (setq y-offset 0) - (setq idx 0) - (setq zusammenfassung-liste '()) - (setq anz-gebaut 0) - (setq anz-nicht-gebaut 0) - - (princ "\n") - (princ "\n================================================================") - (princ "\n FOERDERTEST - PRODUKTIONSPROTOKOLL") - (princ "\n================================================================") - (princ (strcat "\n Distanz dL = " (rtos deltaL 2 0) " mm")) - (princ "\n Hoehenstufen: 0, 1000, 2000, 3000, 4000, 5000 mm") - (princ "\n Richtungen: Auf + Ab") - (princ "\n================================================================") - (princ "\n Nr. Richtung dH (mm) Status Winkel L_GF (mm) L_VF (mm)") - (princ "\n================================================================") - - ;; ========================================================== - ;; TEIL 1: Aufwaerts-Tests (6 Foerderer) - ;; ========================================================== - (foreach deltaH hoehen-liste - (setq idx (1+ idx)) - (setq richtung "Auf") - - (setq ergebnis (berechne-alle-winkel deltaL deltaH richtung)) - (setq best-winkel (car ergebnis)) - (setq L_GF (cadr ergebnis)) - (setq L_VF (caddr ergebnis)) - - (if (and best-winkel L_GF L_VF (> L_GF 0) (> L_VF 0)) - (progn - (setq anz-gebaut (1+ anz-gebaut)) - (princ (strcat "\n " - (itoa idx) " " - (if (< idx 10) " " "") - "Auf " - (rtos deltaH 4 0) " " - "GEBAUT " - (itoa best-winkel) " Grad " - (rtos L_GF 2 1) " " - (rtos L_VF 2 1))) - - (foerderanlage-einfuegen deltaL deltaH richtung best-winkel - (/ L_GF 2.0) (/ L_GF 2.0) L_VF - (list 0 y-offset 0)) - - (setq zusammenfassung-liste (cons - (list idx richtung deltaH "GEBAUT" best-winkel L_GF L_VF) - zusammenfassung-liste)) - ) - (progn - (setq anz-nicht-gebaut (1+ anz-nicht-gebaut)) - (princ (strcat "\n " - (itoa idx) " " - (if (< idx 10) " " "") - "Auf " - (rtos deltaH 4 0) " " - "NICHT " - "--- " - "--- " - "---")) - - (cond - ((and (<= L_GF 0) (<= L_VF 0)) - (princ "\n -> Grund: L_GF und L_VF sind negativ (Strecke zu kurz)")) - ((<= L_GF 0) - (princ "\n -> Grund: L_GF ist negativ (Gefaellestrecke zu kurz)")) - ((<= L_VF 0) - (princ "\n -> Grund: L_VF ist negativ (keine passende Steigung moeglich)")) - ((null best-winkel) - (princ "\n -> Grund: Kein passender Winkel (Hoehendifferenz zu gross/klein)")) - (t - (princ "\n -> Grund: Unbekannter Fehler in der Berechnung")) - ) - - (setq zusammenfassung-liste (cons - (list idx richtung deltaH "NICHT_GEBAUT" nil nil nil) - zusammenfassung-liste)) - ) - ) - (setq y-offset (- y-offset 200)) - ) - - ;; ========================================================== - ;; TEIL 2: Abwaerts-Tests (6 Foerderer) - ;; ========================================================== - (foreach deltaH hoehen-liste - (setq idx (1+ idx)) - (setq richtung "Ab") - - (if (< deltaH 1) - (progn - ;; deltaH = 0 bei Abwaerts ist prinzipiell unmoeglich - (setq anz-nicht-gebaut (1+ anz-nicht-gebaut)) - (princ (strcat "\n " - (itoa idx) " " - (if (< idx 10) " " "") - "Ab " - (rtos deltaH 4 0) " " - "NICHT " - "--- " - "--- " - "---")) - (princ "\n -> Grund: Bei Richtung 'Ab' mit dH=0 ist aus geometrischen Gruenden") - (princ "\n keine Foerderanlage moeglich (immer negative Netto-Hoehe)") - - (setq zusammenfassung-liste (cons - (list idx richtung deltaH "GEOMETRISCH_UNMOEGLICH" nil nil nil) - zusammenfassung-liste)) - ) - (progn - (setq ergebnis (berechne-alle-winkel deltaL deltaH richtung)) - (setq best-winkel (car ergebnis)) - (setq L_GF (cadr ergebnis)) - (setq L_VF (caddr ergebnis)) - - (if (and best-winkel L_GF L_VF (> L_GF 0) (> L_VF 0)) - (progn - (setq anz-gebaut (1+ anz-gebaut)) - (princ (strcat "\n " - (itoa idx) " " - (if (< idx 10) " " "") - "Ab " - (rtos deltaH 4 0) " " - "GEBAUT " - (itoa best-winkel) " Grad " - (rtos L_GF 2 1) " " - (rtos L_VF 2 1))) - - (foerderanlage-einfuegen deltaL deltaH richtung best-winkel - (/ L_GF 2.0) (/ L_GF 2.0) L_VF - (list 0 y-offset 0)) - - (setq zusammenfassung-liste (cons - (list idx richtung deltaH "GEBAUT" best-winkel L_GF L_VF) - zusammenfassung-liste)) - ) - (progn - (setq anz-nicht-gebaut (1+ anz-nicht-gebaut)) - (princ (strcat "\n " - (itoa idx) " " - (if (< idx 10) " " "") - "Ab " - (rtos deltaH 4 0) " " - "NICHT " - "--- " - "--- " - "---")) - - (cond - ((and (<= L_GF 0) (<= L_VF 0)) - (princ "\n -> Grund: L_GF und L_VF sind negativ (Strecke zu kurz)")) - ((<= L_GF 0) - (princ "\n -> Grund: L_GF ist negativ (Gefaellestrecke zu kurz)")) - ((<= L_VF 0) - (princ "\n -> Grund: L_VF ist negativ (Hoehendifferenz zu klein fuer diesen Weg)")) - ((null best-winkel) - (princ "\n -> Grund: Kein passender Winkel (Hoehendifferenz zu gross)")) - (t - (princ "\n -> Grund: Unbekannter Fehler in der Berechnung")) - ) - - (setq zusammenfassung-liste (cons - (list idx richtung deltaH "NICHT_GEBAUT" nil nil nil) - zusammenfassung-liste)) - ) - ) - ) - ) - (setq y-offset (- y-offset 200)) - ) - - ;; ========================================================== - ;; TEIL 3: ZUSAMMENFASSUNG - ;; ========================================================== - (princ "\n\n================================================================================") - (princ "\n ZUSAMMENFASSUNG") - (princ (strcat "\n dL = " (rtos deltaL 2 0) " mm")) - (princ "\n================================================================================") - - (foreach item (reverse zusammenfassung-liste) - (setq nr (car item)) - (setq richtung (cadr item)) - (setq deltaH_val (caddr item)) - (setq status (cadddr item)) - (setq winkel (car (cddddr item))) - (setq L_GF_val (cadr (cddddr item))) - (setq L_VF_val (caddr (cddddr item))) - - (cond - ((= status "GEBAUT") - (princ (strcat "\n " - (itoa nr) ". " richtung - (if (= richtung "Auf") " " " ") - (rtos deltaH_val 2 0) " mm " - (itoa winkel) " Grad " - (rtos L_GF_val 2 2) " mm " - (rtos L_VF_val 2 2) " mm GEBAUT"))) - ((= status "GEOMETRISCH_UNMOEGLICH") - (princ (strcat "\n " - (itoa nr) ". " richtung - (if (= richtung "Auf") " " " ") - (rtos deltaH_val 2 0) " mm " - "--- " - "--- mm " - "--- mm GEOMETRISCH UNMOEGLICH"))) - (t - (princ (strcat "\n " - (itoa nr) ". " richtung - (if (= richtung "Auf") " " " ") - (rtos deltaH_val 2 0) " mm " - "--- " - "--- mm " - "--- mm NICHT GEBAUT"))) - ) - ) - - (princ "\n\n================================================================================") - (princ (strcat "\n Erfolgreich gebaut: " (itoa anz-gebaut) " von " (itoa idx))) - (princ (strcat "\n Erfolgsquote: " (rtos (/ (* anz-gebaut 100.0) idx) 2 1) "%")) - (princ "\n================================================================================") - - (princ "\n\n Erklaerung:") - (princ "\n ----------") - (princ "\n GEBAUT:") - (princ "\n - Auf, dH=0 -> L_VF > 0 kompensiert 3 Grad-Gefaellestrecken") - (princ "\n - Auf, dH>0 -> Normalfall") - (princ "\n - Ab, dH>=1000 -> Normalfall") - (princ "\n") - (princ "\n NICHT GEBAUT:") - (princ "\n - Ab, dH=0 -> Geometrisch unmoeglich (Netto-Hoehe immer negativ)") - (princ "\n - Auf, dH=5000 -> 48 Grad Steigung reicht nicht aus (L_VF negativ)") - (princ "\n - Ab, dH=5000 -> 48 Grad Gefaelle reicht nicht aus") - (princ "\n================================================================================") - - (ssg-end) - - ;; Datei speichern - (if (getenv "DXFM_RESULTS") - (setq result-pfad (getenv "DXFM_RESULTS")) - (setq result-pfad (strcat (getenv "DXFM_BLOCKS") "/../results")) - ) - - (setq dateiname (strcat result-pfad - "/" - (menucmd "M=$(edtime,$(getvar,date),YYYYMODD-HHmm)") - ".dxf")) - (princ (strcat "\n\nSpeichere als: " dateiname)) - (command "_.DXFOUT" dateiname "V" "2018" "16") - (princ "\n\n>>> FOERDERTEST abgeschlossen (12 Foerderer)! <<<") - (princ) -) - -;; ============================================================ -;; TEST_KSEINAUS - KS_EIN/KS_AUS Ausrichtungstest -;; -;; Fuegt alle Vario-Bloecke in 3 Gruppen ein, jeweils 2 Reihen: -;; Gruppe 1: Stationaere Elemente (AUS, EIN, Separator, Umlenk, Motor) -;; Gruppe 2: Alle Boegen aufwaerts (in Z verschoben) -;; Gruppe 3: Alle Boegen abwaerts (in Z verschoben) -;; -;; Pro Gruppe: -;; Reihe A: nach KS_EIN ausgerichtet (KS_EIN X/Y = Referenz-X/Y) -;; Reihe B: nach KS_AUS ausgerichtet (KS_AUS X/Y = Referenz-X/Y) -;; Luecke von 400mm zwischen den Reihen -;; ============================================================ - -;; Hilfsfunktion: Eine Liste von Bloecken in 2 Reihen aufreihen -;; x-start: X-Position der Gruppe -;; y-start: Y-Startposition (wird zurueckgegeben als naechster freier Y) -;; z-offset: Z-Verschiebung (fuer Boegen) -;; Rueckgabe: naechste freie Y-Position -(defun ks-test-reihe (namen x-start y-start z-offset y-abstand y-luecke / - bname block-obj ks-data ks-ein ks-aus - insert-pt offset-vec y-pos idx) - - ;; --- Reihe A: nach KS_EIN --- - (princ "\n Reihe KS_EIN:") - (setq y-pos y-start) - (setq idx 0) - - (foreach bname namen - (setq idx (1+ idx)) - (setq insert-pt (list x-start y-pos z-offset)) - (setq block-obj (vla-InsertBlock modelspace - (vlax-3D-point insert-pt) - bname 1.0 1.0 1.0 0)) - (setq ks-data (extract-ks-from-block block-obj)) - (setq ks-ein (cadr (assoc "KS_EIN" ks-data))) - - (if ks-ein - (progn - (setq offset-vec (list (- x-start (car (car ks-ein))) - (- y-pos (cadr (car ks-ein))) - (- z-offset (caddr (car ks-ein))))) - (vla-Move block-obj - (vlax-3D-point '(0 0 0)) - (vlax-3D-point offset-vec)) - (princ (strcat "\n " (itoa idx) ". " bname " OK")) - ) - (princ (strcat "\n " (itoa idx) ". " bname " WARNUNG: KS_EIN fehlt!")) - ) - (setq y-pos (- y-pos y-abstand)) - ) - - ;; --- Luecke --- - (setq y-pos (- y-pos y-luecke)) - - ;; --- Reihe B: nach KS_AUS --- - (princ "\n Reihe KS_AUS:") - (setq idx 0) - - (foreach bname namen - (setq idx (1+ idx)) - (setq insert-pt (list x-start y-pos z-offset)) - (setq block-obj (vla-InsertBlock modelspace - (vlax-3D-point insert-pt) - bname 1.0 1.0 1.0 0)) - (setq ks-data (extract-ks-from-block block-obj)) - (setq ks-aus (cadr (assoc "KS_AUS" ks-data))) - - (if ks-aus - (progn - (setq offset-vec (list (- x-start (car (car ks-aus))) - (- y-pos (cadr (car ks-aus))) - (- z-offset (caddr (car ks-aus))))) - (vla-Move block-obj - (vlax-3D-point '(0 0 0)) - (vlax-3D-point offset-vec)) - (princ (strcat "\n " (itoa idx) ". " bname " OK")) - ) - (princ (strcat "\n " (itoa idx) ". " bname " WARNUNG: KS_AUS fehlt!")) - ) - (setq y-pos (- y-pos y-abstand)) - ) - - ;; Naechste freie Y-Position zurueckgeben - y-pos -) - -(defun c:TEST_KSEINAUS ( / stationen boegen-auf-liste boegen-ab-liste - bname y-pos y-abstand y-luecke z-bogen) - - ;; Bibliothek initialisieren - (if (not *lib-initialized*) - (init-bibliothek) - ) - - (ssg-start "TEST_KSEINAUS" '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) - (setvar "OSMODE" 0) - (setvar "ATTREQ" 0) - (setvar "ATTDIA" 0) - - (setq y-abstand 200) - (setq y-luecke 400) - (setq z-bogen 2500) - - ;; Gruppe 1: Stationaere Elemente - (setq stationen (list - "_3D_AS_90_links" - "Staustrecke_Separator_SP_300_mm" - "Vario_Umlenkstation_500mm" - "Vario_Motorstation_500mm" - "_3D_ES_90_links" - )) - - ;; Gruppe 2+3: Boegen sammeln - (setq boegen-auf-liste '()) - (setq boegen-ab-liste '()) - (foreach w '(3 6 9 12 15 18 21 27 33 39 45 51) - (setq bname (strcat "Vario_Bogen_auf_" (itoa w) grad-zeichen)) - (if (tblsearch "BLOCK" bname) - (setq boegen-auf-liste (append boegen-auf-liste (list bname))) - ) - (setq bname (strcat "Vario_Bogen_ab_" (itoa w) grad-zeichen)) - (if (tblsearch "BLOCK" bname) - (setq boegen-ab-liste (append boegen-ab-liste (list bname))) - ) - ) - - (princ "\n================================================================") - (princ "\n TEST_KSEINAUS - KS-Ausrichtungstest") - (princ (strcat "\n Stationen: " (itoa (length stationen)))) - (princ (strcat "\n Boegen auf: " (itoa (length boegen-auf-liste)))) - (princ (strcat "\n Boegen ab: " (itoa (length boegen-ab-liste)))) - (princ (strcat "\n Z-Offset Boegen: " (rtos z-bogen 2 0) " mm")) - (princ "\n================================================================") - - ;; Gruppe 1: Stationaere Elemente bei X=0, Z=0 - (princ "\n\n GRUPPE 1: Stationaere Elemente (Z=0)") - (setq y-pos (ks-test-reihe stationen 0 0 0 y-abstand y-luecke)) - - ;; Gruppe 2: Boegen aufwaerts bei X=3000, Z=z-bogen - (princ "\n\n GRUPPE 2: Boegen aufwaerts (Z=" ) - (princ (strcat (rtos z-bogen 2 0) ")")) - (setq y-pos (ks-test-reihe boegen-auf-liste 3000 0 z-bogen y-abstand y-luecke)) - - ;; Gruppe 3: Boegen abwaerts bei X=6000, Z=z-bogen - (princ "\n\n GRUPPE 3: Boegen abwaerts (Z=") - (princ (strcat (rtos z-bogen 2 0) ")")) - (setq y-pos (ks-test-reihe boegen-ab-liste 6000 0 z-bogen y-abstand y-luecke)) - - (ssg-end) - - (princ "\n\n================================================================") - (princ "\n TEST_KSEINAUS abgeschlossen") - (princ "\n X=0: Stationen (KS_EIN + KS_AUS)") - (princ "\n X=3000: Boegen auf (KS_EIN + KS_AUS)") - (princ "\n X=6000: Boegen ab (KS_EIN + KS_AUS)") - (princ "\n================================================================") - (princ) -) diff --git a/menu/SSG_LIB.mnl b/menu/SSG_LIB.mnl index 8da4ade..9c9f22b 100644 --- a/menu/SSG_LIB.mnl +++ b/menu/SSG_LIB.mnl @@ -118,7 +118,7 @@ (ssg-ensure "VarioFoerderer") (ssg-ensure "Gefaellestrecke") (ssg-ensure "export") - (ssg-ensure "tests") + (ssg-ensure "external_call") (ssg-ensure "OmniModulInsert") (ssg-ensure "SSG_LIB_Commands") diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index be020e1..1abb2b2 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -115,6 +115,13 @@ [Call Python]^C^C(ssg-ensure "export") CALLPYTHON [Export Sivas]^C^C(ssg-ensure "export") EXPORTSIVAS [<-Export CSV]^C^C(ssg-ensure "export") EXPORTCSV +[->Tests] +[Alle Tests ausfuehren]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) SSG_RUN_ALL_TESTS +[--] +[Kreisel]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp")) TEST_KREISEL +[Foerderer]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_foerderer.lsp")) TEST_FOERDERER +[KS EIN/AUS]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_ks.lsp")) TEST_KSEINAUS +[<-Omniflo Export]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo.lsp")) TEST_OMNIFLO_EXPORT ***DOUBLECLICK [INSERT]^C^C(ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..6cef833 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,294 @@ +# Tests - SSG_LIB Testarchitektur + +## Uebersicht + +Die Tests folgen einer **zweistufigen Architektur**: + +1. **LISP-Testrunner** (`.lsp`) — laufen in BricsCAD, erzeugen Ergebnisdateien +2. **Python-Validierung** (`.py`) — pruefen die Ergebnisse mit pytest + ezdxf + +``` +BricsCAD Kommandozeile + | | + | TEST_KREISEL | + | TEST_OMNIFLO_EXPORT | + | | | + v v | +tests/output/ | + kreisel_results.json | + kreisel_tests.dxf | + omniflo_export.csv | + | + bin\run_tests.bat --runall + | + pytest -v + | + test_kreisel.py + test_omniflo.py +``` + +## Ablauf fuer den Anwender + +1. **BricsCAD starten** (ueber `bin\start_briscad.bat`) und die LISP-Testrunner ausfuehren (siehe Abschnitt "LISP-Tests in BricsCAD ausfuehren"). Die Testrunner erzeugen Bloecke in der Zeichnung und speichern Ergebnisse nach `tests/output/`. + +2. **Optische Kontrolle** in BricsCAD — pruefen ob die erzeugten Bloecke korrekt aussehen (Positionen, Drehungen, Beschriftungen). Die Zeichnung bleibt offen und kann visuell inspiziert werden. + +3. **Kommandozeile**: Ergebnisse validieren oder als neue Referenz speichern: + - `bin\run_tests.bat --runall` — pytest prueft die Ergebnisse aus `output/` gegen Testdefinitionen und Referenzdaten + - `bin\run_tests.bat --set-as-reference` — nach erfolgreicher Pruefung die aktuellen Ergebnisse als neue Referenz uebernehmen (kopiert `output/` nach `reference/`) + +## Verzeichnisstruktur + +``` +tests/ + conftest.py # Gemeinsame pytest-Fixtures (Pfade, JSON/DXF-Laden) + create_testbase.py # Erzeugt Basis-DXF (optional, wird nicht mehr benoetigt) + requirements.txt # Python-Abhaengigkeiten (ezdxf, pytest) + test_kreisel.lsp # LISP-Testrunner: C:TEST_KREISEL + test_kreisel.py # pytest-Validierung der Kreisel-Ergebnisse + test_omniflo.lsp # LISP-Testrunner: C:TEST_OMNIFLO_EXPORT + test_omniflo.py # pytest-Validierung der Omniflo-Ergebnisse + testdata/ + kreisel_tests.json # Testfall-Definitionen fuer Kreisel + omniflo_tests.json # Testfall-Definitionen fuer Omniflo + output/ # Ergebnisse aus BricsCAD (nicht in Git) + kreisel_results.json + kreisel_tests.dxf + omniflo_export.csv + reference/ # Abgenommene Referenzdaten (in Git) + kreisel_ref.dxf + ... +``` + +## Workflow + +### 1. LISP-Tests in BricsCAD ausfuehren + +BricsCAD starten (ueber `bin\start_briscad.bat`) und Module laden: + +```lisp +(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp")) +``` + +Dann den gewuenschten Testrunner laden und ausfuehren: + +```lisp +;; Kreisel-Test +(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp")) +TEST_KREISEL + +;; Omniflo-Test +(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo.lsp")) +TEST_OMNIFLO_EXPORT +``` + +Die Testrunner: +- Lesen Testfaelle aus `testdata/*.json` +- Fuegen Bloecke per Script-Funktionen ein (ohne User-Interaktion) +- Speichern Ergebnisse nach `output/` + +### 2. Python-Validierung ausfuehren + +```cmd +bin\run_tests.bat --runall +``` + +Oder fuer ein einzelnes Testmodul: + +```cmd +bin\run_tests.bat --runall test_kreisel.py +``` + +Die Python-Tests pruefen: +- **Attribut-Werte** gegen die Testdefinitionen (JSON) +- **DXF-Geometrie** mit ezdxf (Bloecke, Positionen, Radien) +- **Referenz-Vergleich** gegen abgenommene Referenz-DXF +- **CSV-Export** (Omniflo: Spalten, Merkmale, Datentypen) + +Tests, deren Eingabedaten fehlen (z.B. kein BricsCAD-Lauf), werden automatisch uebersprungen (`pytest.skip`). + +### 3. Referenz erstellen/aktualisieren + +Nach einem erfolgreichen Testlauf die Ergebnisse als Referenz speichern: + +```cmd +bin\run_tests.bat --set-as-reference +``` + +Kopiert alle Dateien aus `output/` nach `reference/`. Nur bei bestandenen Tests verwenden. + +## Neuen Test erstellen + +### Schritt 1: Testdaten definieren (JSON) + +Neue Testfaelle in `testdata/_tests.json` eintragen. Das Format ist ein **flaches JSON-Array** (kompatibel mit `omni:load-json`). + +**Kreisel-Beispiel** (`kreisel_tests.json`): + +```json +[ + { + "id": "KR_Insert_Neu", + "function": "insert", + "x": 5000, "y": 5000, "z": 2000, + "abstand": 5000, + "rotation": 0.0, + "typ": "STANDARD", + "expect_block_prefix": "KREISEL_", + "expect_hoehe": "2000", + "expect_kreiselart": "STANDARD" + } +] +``` + +Felder: +- `id` — Eindeutiger Name des Testfalls +- `function` — `"insert"` oder `"connect"` +- Eingabeparameter (`x`, `y`, `z`, `abstand`, `rotation`, `typ` fuer Insert; `start_x/y/z`, `end_x/y/z`, `typ` fuer Connect) +- `expect_*` — Erwartete Ergebniswerte (fuer Python-Validierung) + +**Omniflo-Beispiel** (`omniflo_tests.json`): + +```json +[ + { + "sivasnr": "834372001", + "type": "bogen", + "description": "Bogen 90 Grad R200", + "hoehe": 2000, + "drehung": 0 + } +] +``` + +### Schritt 2: LISP-Testrunner erweitern (falls neues Modul) + +Fuer ein neues Modul eine neue `.lsp`-Datei erstellen nach dem Muster: + +```lisp +;; test_.lsp + +(defun c:TEST_ (/ ...) + (ssg-start "TEST_" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + + ;; 1. Testdaten laden + (setq testfaelle (omni:load-json + (strcat (getenv "DXFMAKRO") "/tests/testdata/_tests.json"))) + + ;; 2. Testfaelle ausfuehren, Ergebnisse sammeln + (foreach eintrag testfaelle + ;; ... Script-Funktion aufrufen, Ergebnis pruefen ... + ) + + ;; 3. Ergebnisse als JSON speichern + (setq out-json (strcat (getenv "DXFMAKRO") "/tests/output/_results.json")) + ;; ... JSON schreiben ... + + ;; 4. DXF speichern + (command "_.SAVEAS" "DXF" out-dxf) + + (ssg-end) +) +``` + +Wichtig: +- `omni:load-json` erwartet ein **flaches JSON-Array** mit flachen Objekten (kein Nesting) +- `omni:val` liest Werte aus den geladenen Eintraegen +- Script-Funktionen (z.B. `kreisel-insert-script`) muessen **ohne User-Interaktion** funktionieren + +### Schritt 3: Python-Validierung erstellen + +Neue `test_.py` erstellen: + +```python +import pytest + +class TestModulAttributes: + """Prueft Attribute gegen Testdefinitionen.""" + + def test_all_executed(self, _results): + """Alle Testfaelle muessen ausgefuehrt worden sein.""" + # ... + + def test_attribute_values(self, _testdata, _results): + """Attributwerte muessen mit Erwartungen uebereinstimmen.""" + # ... + +class TestModulGeometry: + """Prueft DXF-Geometrie mit ezdxf.""" + + def test_blocks_exist(self, _dxf): + """Bloecke muessen im Modelspace vorhanden sein.""" + # ... + +class TestModulReference: + """Vergleicht gegen Referenz.""" + + def test_matches_reference(self, _dxf, _ref_dxf): + # ... +``` + +### Schritt 4: Fixtures in conftest.py ergaenzen + +Neue Fixtures fuer Testdaten, Ergebnisse und DXF in `conftest.py` hinzufuegen: + +```python +@pytest.fixture +def _testdata(): + path = os.path.join(_testdata_dir(), "_tests.json") + return _load_json(path) + +@pytest.fixture +def _results(): + path = os.path.join(_output_dir(), "_results.json") + if not os.path.exists(path): + pytest.skip("_results.json nicht vorhanden") + return _load_json(path) + +@pytest.fixture +def _dxf(): + path = os.path.join(_output_dir(), "_tests.dxf") + if not os.path.exists(path): + pytest.skip("_tests.dxf nicht vorhanden") + return ezdxf.readfile(path) + +@pytest.fixture +def _ref_dxf(): + path = os.path.join(_reference_dir(), "_ref.dxf") + if not os.path.exists(path): + pytest.skip("Referenz nicht vorhanden") + return ezdxf.readfile(path) +``` + +## Testklassen + +### test_kreisel.py + +| Klasse | Prueft | +|---|---| +| `TestKreiselAttributes` | Attribute (KREISELART, HOEHE), Block-Prefixe, Status | +| `TestKreiselGeometry` | DXF-Bloecke, Positionen, Kreis-Radien (400mm) | +| `TestKreiselReference` | Block-Anzahl und -Typen gegen Referenz-DXF | + +### test_omniflo.py + +| Klasse | Prueft | +|---|---| +| `TestOmnifloExportUnit` | Mock-Export: Merkmale, Datentypen, Vollstaendigkeit (ohne BricsCAD) | +| `TestOmnifloExportCSV` | CSV aus BricsCAD: Header, Spalten, JSON-Merkmale | + +## Umgebungsvariablen + +Werden von `bin\setenv.bat` gesetzt. Fuer Tests relevant: + +| Variable | Beschreibung | +|---|---| +| `DXFMAKRO` | Projektwurzel | +| `DXFM_TESTS` | tests/-Verzeichnis | +| `DXFM_TESTDATA` | testdata/-Verzeichnis | +| `DXFM_TESTOUT` | output/-Verzeichnis | +| `DXFM_TESTREF` | reference/-Verzeichnis | +| `DXFM_OMNIFLO` | Pfad zu Omniflo-DXF-Dateien | diff --git a/tests/test_foerderer.lsp b/tests/test_foerderer.lsp new file mode 100644 index 0000000..303f8e9 --- /dev/null +++ b/tests/test_foerderer.lsp @@ -0,0 +1,221 @@ +;; ============================================================ +;; test_foerderer.lsp - Automatischer Integrationstest fuer VarioFoerderer +;; +;; Erzeugt 12 Variofoerderer (6x Auf, 6x Ab) mit deltaL=7000 +;; und verschiedenen Hoehenstufen. Speichert: +;; - tests/output/foerderer_results.json (Ergebnisse) +;; - tests/output/foerderer_tests.dxf (Zeichnung) +;; +;; Voraussetzungen: +;; - SSG_LIB geladen (VarioFoerderer.lsp, ssg_core.lsp) +;; - Umgebungsvariable DXFMAKRO gesetzt +;; +;; Aufruf in BricsCAD: +;; (load (strcat (getenv "DXFMAKRO") "/tests/test_foerderer.lsp")) +;; TEST_FOERDERER +;; ============================================================ + + +;; --- Ergebnis eines Testfalls als JSON-String erzeugen --- +(defun foerderer:test-result-json (test-id richtung deltaL deltaH status + winkel L_GF L_VF / + json) + (setq json (strcat " {\n" + " \"test_id\": \"" test-id "\",\n" + " \"richtung\": \"" richtung "\",\n" + " \"deltaL\": " (rtos deltaL 2 0) ",\n" + " \"deltaH\": " (rtos deltaH 2 0) ",\n" + " \"status\": \"" status "\"")) + + (if winkel + (setq json (strcat json ",\n" + " \"winkel\": " (itoa winkel) ",\n" + " \"L_GF\": " (rtos L_GF 2 1) ",\n" + " \"L_VF\": " (rtos L_VF 2 1))) + ) + + (setq json (strcat json "\n }")) + json +) + + +;; ============================================================ +;; C:TEST_FOERDERER - Hauptbefehl +;; ============================================================ +(defun c:TEST_FOERDERER ( / deltaL deltaH richtung ergebnis + best-winkel L_GF L_VF + y-offset hoehen-liste idx + anz-gebaut anz-nicht-gebaut + results-list result-json first + tests-out-dir out-json out-dxf f + test-id) + + ;; Bibliothek initialisieren (laedt Block-Library und extrahiert Masse) + (if (not *lib-initialized*) + (init-bibliothek) + ) + + (ssg-start "TEST_FOERDERER" '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + + (setq deltaL 7000) + (setq hoehen-liste '(0 1000 2000 3000 4000 5000)) + (setq y-offset 0) + (setq idx 0) + (setq results-list '()) + (setq anz-gebaut 0) + (setq anz-nicht-gebaut 0) + + (princ "\n") + (princ "\n================================================================") + (princ "\n TEST_FOERDERER - Variofoerderer Integrationstest") + (princ "\n================================================================") + (princ (strcat "\n Distanz dL = " (rtos deltaL 2 0) " mm")) + (princ "\n Hoehenstufen: 0, 1000, 2000, 3000, 4000, 5000 mm") + (princ "\n Richtungen: Auf + Ab") + (princ "\n================================================================") + + ;; ========================================================== + ;; TEIL 1: Aufwaerts-Tests (6 Foerderer) + ;; ========================================================== + (foreach deltaH hoehen-liste + (setq idx (1+ idx)) + (setq richtung "Auf") + (setq test-id (strcat "VF_Auf_" (rtos deltaH 2 0))) + + (setq ergebnis (berechne-alle-winkel deltaL deltaH richtung)) + (setq best-winkel (car ergebnis)) + (setq L_GF (cadr ergebnis)) + (setq L_VF (caddr ergebnis)) + + (if (and best-winkel L_GF L_VF (> L_GF 0) (> L_VF 0)) + (progn + (setq anz-gebaut (1+ anz-gebaut)) + (princ (strcat "\n " (itoa idx) ". " test-id " -> GEBAUT " + (itoa best-winkel) " Grad L_GF=" (rtos L_GF 2 1) + " L_VF=" (rtos L_VF 2 1))) + + (foerderanlage-einfuegen deltaL deltaH richtung best-winkel + (/ L_GF 2.0) (/ L_GF 2.0) L_VF + (list 0 y-offset 0)) + + (setq results-list (cons + (foerderer:test-result-json test-id richtung deltaL deltaH + "GEBAUT" best-winkel L_GF L_VF) + results-list)) + ) + (progn + (setq anz-nicht-gebaut (1+ anz-nicht-gebaut)) + (princ (strcat "\n " (itoa idx) ". " test-id " -> NICHT_GEBAUT")) + + (setq results-list (cons + (foerderer:test-result-json test-id richtung deltaL deltaH + "NICHT_GEBAUT" nil nil nil) + results-list)) + ) + ) + (setq y-offset (- y-offset 200)) + ) + + ;; ========================================================== + ;; TEIL 2: Abwaerts-Tests (6 Foerderer) + ;; ========================================================== + (foreach deltaH hoehen-liste + (setq idx (1+ idx)) + (setq richtung "Ab") + (setq test-id (strcat "VF_Ab_" (rtos deltaH 2 0))) + + (if (< deltaH 1) + (progn + (setq anz-nicht-gebaut (1+ anz-nicht-gebaut)) + (princ (strcat "\n " (itoa idx) ". " test-id " -> GEOMETRISCH_UNMOEGLICH")) + + (setq results-list (cons + (foerderer:test-result-json test-id richtung deltaL deltaH + "GEOMETRISCH_UNMOEGLICH" nil nil nil) + results-list)) + ) + (progn + (setq ergebnis (berechne-alle-winkel deltaL deltaH richtung)) + (setq best-winkel (car ergebnis)) + (setq L_GF (cadr ergebnis)) + (setq L_VF (caddr ergebnis)) + + (if (and best-winkel L_GF L_VF (> L_GF 0) (> L_VF 0)) + (progn + (setq anz-gebaut (1+ anz-gebaut)) + (princ (strcat "\n " (itoa idx) ". " test-id " -> GEBAUT " + (itoa best-winkel) " Grad L_GF=" (rtos L_GF 2 1) + " L_VF=" (rtos L_VF 2 1))) + + (foerderanlage-einfuegen deltaL deltaH richtung best-winkel + (/ L_GF 2.0) (/ L_GF 2.0) L_VF + (list 0 y-offset 0)) + + (setq results-list (cons + (foerderer:test-result-json test-id richtung deltaL deltaH + "GEBAUT" best-winkel L_GF L_VF) + results-list)) + ) + (progn + (setq anz-nicht-gebaut (1+ anz-nicht-gebaut)) + (princ (strcat "\n " (itoa idx) ". " test-id " -> NICHT_GEBAUT")) + + (setq results-list (cons + (foerderer:test-result-json test-id richtung deltaL deltaH + "NICHT_GEBAUT" nil nil nil) + results-list)) + ) + ) + ) + ) + (setq y-offset (- y-offset 200)) + ) + + ;; ========================================================== + ;; Zusammenfassung + ;; ========================================================== + (princ "\n================================================================") + (princ (strcat "\n Ergebnis: " (itoa anz-gebaut) " GEBAUT, " + (itoa anz-nicht-gebaut) " NICHT_GEBAUT")) + (princ "\n================================================================") + + ;; ========================================================== + ;; Ergebnisse speichern + ;; ========================================================== + (setq tests-out-dir (strcat (getenv "DXFMAKRO") "/tests/output")) + (vl-mkdir tests-out-dir) + + ;; JSON schreiben + (setq out-json (strcat tests-out-dir "/foerderer_results.json")) + (setq f (open out-json "w")) + (if f + (progn + (write-line "[" f) + (setq results-list (reverse results-list)) + (setq first T) + (foreach r results-list + (if (not first) (write-line "," f)) + (write-line r f) + (setq first nil) + ) + (write-line "]" f) + (close f) + (princ (strcat "\n Ergebnisse: " out-json)) + ) + (princ (strcat "\n FEHLER: Kann " out-json " nicht schreiben!")) + ) + + ;; DXF speichern + (setq out-dxf (strcat tests-out-dir "/foerderer_tests.dxf")) + (command "_.SAVEAS" "DXF" out-dxf) + (princ (strcat "\n DXF gespeichert: " out-dxf)) + + (ssg-end) + (princ "\n================================================================") + (princ "\n TEST_FOERDERER abgeschlossen.") + (princ "\n================================================================") + (princ) +) diff --git a/tests/test_kreisel.lsp b/tests/test_kreisel.lsp new file mode 100644 index 0000000..b8638b8 --- /dev/null +++ b/tests/test_kreisel.lsp @@ -0,0 +1,255 @@ +;; ============================================================ +;; test_kreisel.lsp - Automatischer Integrationstest fuer Kreisel +;; +;; Laedt Testfaelle aus tests/testdata/kreisel_tests.json, +;; fuegt Kreisel per insert und connect ein, sammelt +;; Ergebnisse und speichert: +;; - tests/output/kreisel_tests.dxf (Zeichnung mit Bloecken) +;; - tests/output/kreisel_results.json (Attribut-/Positions-Daten) +;; +;; Voraussetzungen: +;; - SSG_LIB geladen (KreiselInsert.lsp, ssg_core.lsp) +;; - Umgebungsvariable DXFMAKRO gesetzt +;; +;; Aufruf in BricsCAD: +;; (load "tests/test_kreisel.lsp") +;; TEST_KREISEL +;; ============================================================ + + +;; --- Ergebnis eines Testfalls als JSON-String erzeugen --- +(defun kreisel:test-result-json (test-id status block-name block-handle + insert-point attribs / + json att-json tag val first) + (setq json (strcat " {\n" + " \"test_id\": \"" test-id "\",\n" + " \"status\": \"" status "\",\n" + " \"block_name\": \"" (if block-name block-name "") "\",\n" + " \"block_handle\": \"" (if block-handle block-handle "") "\",\n" + " \"insert_point\": [" + (if insert-point + (strcat (rtos (car insert-point) 2 1) ", " + (rtos (cadr insert-point) 2 1) ", " + (rtos (if (caddr insert-point) (caddr insert-point) 0.0) 2 1)) + "0.0, 0.0, 0.0" + ) + "],\n" + " \"actual_attributes\": {")) + + ;; Attribute als JSON + (setq first T) + (foreach att attribs + (setq tag (car att)) + (setq val (cdr att)) + (if (not first) (setq json (strcat json ","))) + (setq json (strcat json "\n \"" tag "\": \"" (if val val "") "\"")) + (setq first nil) + ) + (setq json (strcat json "\n }\n }")) + json +) + + +;; --- Einzelnen Insert-Testfall ausfuehren --- +(defun kreisel:run-insert-test (eintrag / id x y z abstand rotation typ + pt blockEnt ed attribs block-name + block-handle insert-point) + (setq id (omni:val eintrag "id")) + (setq x (omni:val eintrag "x")) + (setq y (omni:val eintrag "y")) + (setq z (omni:val eintrag "z")) + (setq abstand (omni:val eintrag "abstand")) + (setq rotation (omni:val eintrag "rotation")) + (setq typ (omni:val eintrag "typ")) + + (if (numberp x) (setq x (float x))) + (if (numberp y) (setq y (float y))) + (if (numberp z) (setq z (float z))) + (if (numberp abstand) (setq abstand (float abstand))) + (if (numberp rotation) (setq rotation (float rotation))) + + (setq pt (list x y z)) + (princ (strcat "\n [INSERT] " id " -> (" (rtos x 2 0) ", " (rtos y 2 0) + ", " (rtos z 2 0) ") A=" (rtos abstand 2 0) + " R=" (rtos rotation 2 1) " " typ)) + + (setq blockEnt (kreisel-insert-script pt abstand rotation typ z)) + + (if blockEnt + (progn + (setq ed (entget blockEnt)) + (setq block-name (cdr (assoc 2 ed))) + (setq block-handle (cdr (assoc 5 ed))) + (setq insert-point (cdr (assoc 10 ed))) + (setq attribs (ssg-attrib-read blockEnt)) + (princ (strcat " OK: " block-name)) + (kreisel:test-result-json id "executed" block-name block-handle + insert-point attribs) + ) + (progn + (princ (strcat " FEHLER: " id)) + (kreisel:test-result-json id "failed" nil nil nil nil) + ) + ) +) + + +;; --- Einzelnen Connect-Testfall ausfuehren --- +(defun kreisel:run-connect-test (eintrag / id sx sy sz ex ey ez typ + ptStart ptEnd blockEnt ed attribs + block-name block-handle insert-point) + (setq id (omni:val eintrag "id")) + (setq sx (omni:val eintrag "start_x")) + (setq sy (omni:val eintrag "start_y")) + (setq sz (omni:val eintrag "start_z")) + (setq ex (omni:val eintrag "end_x")) + (setq ey (omni:val eintrag "end_y")) + (setq ez (omni:val eintrag "end_z")) + (setq typ (omni:val eintrag "typ")) + + (if (numberp sx) (setq sx (float sx))) + (if (numberp sy) (setq sy (float sy))) + (if (numberp sz) (setq sz (float sz))) + (if (numberp ex) (setq ex (float ex))) + (if (numberp ey) (setq ey (float ey))) + (if (numberp ez) (setq ez (float ez))) + + (setq ptStart (list sx sy sz)) + (setq ptEnd (list ex ey ez)) + + (princ (strcat "\n [CONNECT] " id + " -> (" (rtos sx 2 0) "," (rtos sy 2 0) + ") -> (" (rtos ex 2 0) "," (rtos ey 2 0) ") " typ)) + + (setq blockEnt (kreisel-connect-script ptStart ptEnd typ sz)) + + (if blockEnt + (progn + (setq ed (entget blockEnt)) + (setq block-name (cdr (assoc 2 ed))) + (setq block-handle (cdr (assoc 5 ed))) + (setq insert-point (cdr (assoc 10 ed))) + (setq attribs (ssg-attrib-read blockEnt)) + (princ (strcat " OK: " block-name)) + (kreisel:test-result-json id "executed" block-name block-handle + insert-point attribs) + ) + (progn + (princ (strcat " FEHLER: " id)) + (kreisel:test-result-json id "failed" nil nil nil nil) + ) + ) +) + + +;; ============================================================ +;; C:TEST_KREISEL - Hauptbefehl +;; ============================================================ +(defun c:TEST_KREISEL (/ tests-json-pfad testfaelle tests-out-dir + out-dxf out-json f eintrag func + result-json results-list first + anzahl-ok anzahl-fehler) + + (ssg-start "TEST_KREISEL" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + + ;; Testdaten laden + (setq tests-json-pfad + (strcat (getenv "DXFMAKRO") "/tests/testdata/kreisel_tests.json")) + + (if (not (findfile tests-json-pfad)) + (progn + (princ (strcat "\n[TEST_KREISEL] FEHLER: " tests-json-pfad " nicht gefunden!")) + (ssg-end) + (princ) + ) + (progn + (setq testfaelle (omni:load-json tests-json-pfad)) + (if (null testfaelle) + (progn + (princ "\n[TEST_KREISEL] FEHLER: Testdaten konnten nicht geladen werden.") + (ssg-end) + (princ) + ) + (progn + (princ "\n================================================================") + (princ "\n TEST_KREISEL") + (princ (strcat "\n " (itoa (length testfaelle)) " Testfaelle geladen")) + (princ "\n================================================================") + + (setq results-list nil) + (setq anzahl-ok 0) + (setq anzahl-fehler 0) + + ;; Testfaelle ausfuehren + (foreach eintrag testfaelle + (setq func (omni:val eintrag "function")) + (setq result-json + (cond + ((= func "insert") + (kreisel:run-insert-test eintrag)) + ((= func "connect") + (kreisel:run-connect-test eintrag)) + (T + (princ (strcat "\n WARNUNG: Unbekannte Funktion: " func)) + nil) + ) + ) + (if result-json + (progn + (setq results-list (cons result-json results-list)) + (if (vl-string-search "executed" result-json) + (setq anzahl-ok (1+ anzahl-ok)) + (setq anzahl-fehler (1+ anzahl-fehler)) + ) + ) + ) + ) + + ;; Zusammenfassung + (princ "\n================================================================") + (princ (strcat "\n Ergebnis: " (itoa anzahl-ok) " OK, " + (itoa anzahl-fehler) " Fehler")) + (princ "\n================================================================") + + ;; Ergebnisse speichern + (setq tests-out-dir (strcat (getenv "DXFMAKRO") "/tests/output")) + (vl-mkdir tests-out-dir) + + ;; JSON-Ergebnisse schreiben + (setq out-json (strcat tests-out-dir "/kreisel_results.json")) + (setq f (open out-json "w")) + (if f + (progn + (write-line "[" f) + (setq results-list (reverse results-list)) + (setq first T) + (foreach r results-list + (if (not first) (write-line "," f)) + (write-line r f) + (setq first nil) + ) + (write-line "]" f) + (close f) + (princ (strcat "\n Ergebnisse: " out-json)) + ) + (princ (strcat "\n FEHLER: Kann " out-json " nicht schreiben!")) + ) + + ;; DXF speichern + (setq out-dxf (strcat tests-out-dir "/kreisel_tests.dxf")) + (command "_.SAVEAS" "DXF" out-dxf) + (princ (strcat "\n DXF gespeichert: " out-dxf)) + + (ssg-end) + (princ "\n================================================================") + (princ "\n TEST_KREISEL abgeschlossen.") + (princ "\n================================================================") + (princ) + ) + ) + ) + ) +) diff --git a/tests/test_ks.lsp b/tests/test_ks.lsp new file mode 100644 index 0000000..6432a39 --- /dev/null +++ b/tests/test_ks.lsp @@ -0,0 +1,262 @@ +;; ============================================================ +;; test_ks.lsp - Automatischer Integrationstest fuer KS_EIN/KS_AUS +;; +;; Fuegt alle Vario-Bloecke in 3 Gruppen ein, jeweils 2 Reihen: +;; Gruppe 1: Stationaere Elemente (AUS, EIN, Separator, Umlenk, Motor) +;; Gruppe 2: Alle Boegen aufwaerts (in Z verschoben) +;; Gruppe 3: Alle Boegen abwaerts (in Z verschoben) +;; +;; Pro Gruppe: +;; Reihe A: nach KS_EIN ausgerichtet +;; Reihe B: nach KS_AUS ausgerichtet +;; Luecke von 400mm zwischen den Reihen +;; +;; Speichert: +;; - tests/output/ks_results.json (Ergebnisse) +;; - tests/output/ks_tests.dxf (Zeichnung) +;; +;; Voraussetzungen: +;; - SSG_LIB geladen (VarioFoerderer.lsp, ssg_core.lsp) +;; - Umgebungsvariable DXFMAKRO gesetzt +;; +;; Aufruf in BricsCAD: +;; (load (strcat (getenv "DXFMAKRO") "/tests/test_ks.lsp")) +;; TEST_KSEINAUS +;; ============================================================ + + +;; --- Ergebnis eines Testfalls als JSON-String erzeugen --- +(defun ks:test-result-json (test-id block-name gruppe ks-type status / + json) + (setq json (strcat " {\n" + " \"test_id\": \"" test-id "\",\n" + " \"block_name\": \"" (if block-name block-name "") "\",\n" + " \"gruppe\": \"" gruppe "\",\n" + " \"ks_type\": \"" ks-type "\",\n" + " \"status\": \"" status "\"\n" + " }")) + json +) + + +;; --- Eine Reihe Bloecke einfuegen und Ergebnisse sammeln --- +;; Rueckgabe: (naechste-y-pos . results-list) +(defun ks:test-reihe (namen x-start y-start z-offset y-abstand y-luecke + gruppe results-in / + bname block-obj ks-data ks-ein ks-aus + insert-pt offset-vec y-pos idx + test-id results-out) + + (setq results-out results-in) + + ;; --- Reihe A: nach KS_EIN --- + (princ "\n Reihe KS_EIN:") + (setq y-pos y-start) + (setq idx 0) + + (foreach bname namen + (setq idx (1+ idx)) + (setq test-id (strcat gruppe "_KS_EIN_" (itoa idx))) + (setq insert-pt (list x-start y-pos z-offset)) + (setq block-obj (vla-InsertBlock modelspace + (vlax-3D-point insert-pt) + bname 1.0 1.0 1.0 0)) + (setq ks-data (extract-ks-from-block block-obj)) + (setq ks-ein (cadr (assoc "KS_EIN" ks-data))) + + (if ks-ein + (progn + (setq offset-vec (list (- x-start (car (car ks-ein))) + (- y-pos (cadr (car ks-ein))) + (- z-offset (caddr (car ks-ein))))) + (vla-Move block-obj + (vlax-3D-point '(0 0 0)) + (vlax-3D-point offset-vec)) + (princ (strcat "\n " (itoa idx) ". " bname " OK")) + (setq results-out (cons + (ks:test-result-json test-id bname gruppe "KS_EIN" "OK") + results-out)) + ) + (progn + (princ (strcat "\n " (itoa idx) ". " bname " WARNUNG: KS_EIN fehlt!")) + (setq results-out (cons + (ks:test-result-json test-id bname gruppe "KS_EIN" "KS_FEHLT") + results-out)) + ) + ) + (setq y-pos (- y-pos y-abstand)) + ) + + ;; --- Luecke --- + (setq y-pos (- y-pos y-luecke)) + + ;; --- Reihe B: nach KS_AUS --- + (princ "\n Reihe KS_AUS:") + (setq idx 0) + + (foreach bname namen + (setq idx (1+ idx)) + (setq test-id (strcat gruppe "_KS_AUS_" (itoa idx))) + (setq insert-pt (list x-start y-pos z-offset)) + (setq block-obj (vla-InsertBlock modelspace + (vlax-3D-point insert-pt) + bname 1.0 1.0 1.0 0)) + (setq ks-data (extract-ks-from-block block-obj)) + (setq ks-aus (cadr (assoc "KS_AUS" ks-data))) + + (if ks-aus + (progn + (setq offset-vec (list (- x-start (car (car ks-aus))) + (- y-pos (cadr (car ks-aus))) + (- z-offset (caddr (car ks-aus))))) + (vla-Move block-obj + (vlax-3D-point '(0 0 0)) + (vlax-3D-point offset-vec)) + (princ (strcat "\n " (itoa idx) ". " bname " OK")) + (setq results-out (cons + (ks:test-result-json test-id bname gruppe "KS_AUS" "OK") + results-out)) + ) + (progn + (princ (strcat "\n " (itoa idx) ". " bname " WARNUNG: KS_AUS fehlt!")) + (setq results-out (cons + (ks:test-result-json test-id bname gruppe "KS_AUS" "KS_FEHLT") + results-out)) + ) + ) + (setq y-pos (- y-pos y-abstand)) + ) + + ;; Rueckgabe: (naechste-y-pos . results-list) + (cons y-pos results-out) +) + + +;; ============================================================ +;; C:TEST_KSEINAUS - Hauptbefehl +;; ============================================================ +(defun c:TEST_KSEINAUS ( / stationen boegen-auf-liste boegen-ab-liste + bname y-pos y-abstand y-luecke z-bogen + results-list reihe-result + anz-ok anz-fehlt + tests-out-dir out-json out-dxf f first) + + ;; Bibliothek initialisieren + (if (not *lib-initialized*) + (init-bibliothek) + ) + + (ssg-start "TEST_KSEINAUS" '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + + (setq y-abstand 200) + (setq y-luecke 400) + (setq z-bogen 2500) + (setq results-list '()) + + ;; Gruppe 1: Stationaere Elemente + (setq stationen (list + "_3D_AS_90_links" + "Staustrecke_Separator_SP_300_mm" + "Vario_Umlenkstation_500mm" + "Vario_Motorstation_500mm" + "_3D_ES_90_links" + )) + + ;; Gruppe 2+3: Boegen sammeln + (setq boegen-auf-liste '()) + (setq boegen-ab-liste '()) + (foreach w '(3 6 9 12 15 18 21 27 33 39 45 51) + (setq bname (strcat "Vario_Bogen_auf_" (itoa w) grad-zeichen)) + (if (tblsearch "BLOCK" bname) + (setq boegen-auf-liste (append boegen-auf-liste (list bname))) + ) + (setq bname (strcat "Vario_Bogen_ab_" (itoa w) grad-zeichen)) + (if (tblsearch "BLOCK" bname) + (setq boegen-ab-liste (append boegen-ab-liste (list bname))) + ) + ) + + (princ "\n================================================================") + (princ "\n TEST_KSEINAUS - KS-Ausrichtungstest") + (princ (strcat "\n Stationen: " (itoa (length stationen)))) + (princ (strcat "\n Boegen auf: " (itoa (length boegen-auf-liste)))) + (princ (strcat "\n Boegen ab: " (itoa (length boegen-ab-liste)))) + (princ (strcat "\n Z-Offset Boegen: " (rtos z-bogen 2 0) " mm")) + (princ "\n================================================================") + + ;; Gruppe 1: Stationaere Elemente bei X=0, Z=0 + (princ "\n\n GRUPPE 1: Stationaere Elemente (Z=0)") + (setq reihe-result (ks:test-reihe stationen 0 0 0 y-abstand y-luecke + "Stationen" results-list)) + (setq y-pos (car reihe-result)) + (setq results-list (cdr reihe-result)) + + ;; Gruppe 2: Boegen aufwaerts bei X=3000, Z=z-bogen + (princ (strcat "\n\n GRUPPE 2: Boegen aufwaerts (Z=" (rtos z-bogen 2 0) ")")) + (setq reihe-result (ks:test-reihe boegen-auf-liste 3000 0 z-bogen y-abstand y-luecke + "Boegen_Auf" results-list)) + (setq y-pos (car reihe-result)) + (setq results-list (cdr reihe-result)) + + ;; Gruppe 3: Boegen abwaerts bei X=6000, Z=z-bogen + (princ (strcat "\n\n GRUPPE 3: Boegen abwaerts (Z=" (rtos z-bogen 2 0) ")")) + (setq reihe-result (ks:test-reihe boegen-ab-liste 6000 0 z-bogen y-abstand y-luecke + "Boegen_Ab" results-list)) + (setq y-pos (car reihe-result)) + (setq results-list (cdr reihe-result)) + + ;; Zusammenfassung + (setq anz-ok 0) + (setq anz-fehlt 0) + (foreach r results-list + (if (vl-string-search "\"OK\"" r) + (setq anz-ok (1+ anz-ok)) + (setq anz-fehlt (1+ anz-fehlt)) + ) + ) + + (princ "\n================================================================") + (princ (strcat "\n Ergebnis: " (itoa anz-ok) " OK, " + (itoa anz-fehlt) " KS fehlt")) + (princ "\n================================================================") + + ;; ========================================================== + ;; Ergebnisse speichern + ;; ========================================================== + (setq tests-out-dir (strcat (getenv "DXFMAKRO") "/tests/output")) + (vl-mkdir tests-out-dir) + + ;; JSON schreiben + (setq out-json (strcat tests-out-dir "/ks_results.json")) + (setq f (open out-json "w")) + (if f + (progn + (write-line "[" f) + (setq results-list (reverse results-list)) + (setq first T) + (foreach r results-list + (if (not first) (write-line "," f)) + (write-line r f) + (setq first nil) + ) + (write-line "]" f) + (close f) + (princ (strcat "\n Ergebnisse: " out-json)) + ) + (princ (strcat "\n FEHLER: Kann " out-json " nicht schreiben!")) + ) + + ;; DXF speichern + (setq out-dxf (strcat tests-out-dir "/ks_tests.dxf")) + (command "_.SAVEAS" "DXF" out-dxf) + (princ (strcat "\n DXF gespeichert: " out-dxf)) + + (ssg-end) + (princ "\n================================================================") + (princ "\n TEST_KSEINAUS abgeschlossen.") + (princ "\n================================================================") + (princ) +) diff --git a/tests/test_run_all.lsp b/tests/test_run_all.lsp new file mode 100644 index 0000000..a669c92 --- /dev/null +++ b/tests/test_run_all.lsp @@ -0,0 +1,71 @@ +;; ============================================================ +;; test_run_all.lsp - Fuehrt alle LISP-Tests nacheinander aus +;; +;; Laedt und startet: +;; 1. TEST_KREISEL +;; 2. TEST_FOERDERER +;; 3. TEST_KSEINAUS +;; 4. TEST_OMNIFLO_EXPORT +;; +;; Ergebnisse werden jeweils in tests/output/ gespeichert. +;; +;; Voraussetzungen: +;; - SSG_LIB geladen +;; - Umgebungsvariable DXFMAKRO gesetzt +;; +;; Aufruf in BricsCAD: +;; (load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) +;; SSG_RUN_ALL_TESTS +;; ============================================================ + +(defun c:SSG_RUN_ALL_TESTS ( / tests-pfad test-dateien test-befehle + datei befehl idx anz) + + (setq tests-pfad (strcat (getenv "DXFMAKRO") "/tests")) + + ;; Test-Dateien und zugehoerige Befehle + (setq test-dateien (list + (strcat tests-pfad "/test_kreisel.lsp") + (strcat tests-pfad "/test_foerderer.lsp") + (strcat tests-pfad "/test_ks.lsp") + (strcat tests-pfad "/test_omniflo.lsp") + )) + (setq test-befehle (list + "TEST_KREISEL" + "TEST_FOERDERER" + "TEST_KSEINAUS" + "TEST_OMNIFLO_EXPORT" + )) + + (setq anz (length test-dateien)) + (setq idx 0) + + (princ "\n") + (princ "\n================================================================") + (princ "\n SSG_RUN_ALL_TESTS") + (princ (strcat "\n " (itoa anz) " Testmodule")) + (princ "\n================================================================") + + ;; Tests laden und ausfuehren + (mapcar + '(lambda (datei befehl) + (setq idx (1+ idx)) + (princ (strcat "\n\n>>> " (itoa idx) "/" (itoa anz) ": " befehl " <<<")) + (if (findfile datei) + (progn + (load datei) + (eval (list (read (strcat "c:" befehl)))) + ) + (princ (strcat "\n WARNUNG: " datei " nicht gefunden - uebersprungen")) + ) + ) + test-dateien + test-befehle + ) + + (princ "\n\n================================================================") + (princ "\n SSG_RUN_ALL_TESTS abgeschlossen.") + (princ (strcat "\n Ergebnisse in: " (getenv "DXFMAKRO") "/tests/output/")) + (princ "\n================================================================") + (princ) +)