From 3aed8fe1768b402c38e6191b548594ef53bd9f03 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Thu, 28 May 2026 17:34:02 +0200 Subject: [PATCH] =?UTF-8?q?debug=20beim=20Variof=C3=B6rderer=20dazu.=20dbg?= =?UTF-8?q?return=20routine=20gibt=20den=20Wert=20zur=C3=BCck.=20neues=20T?= =?UTF-8?q?est=20Konzept=20f=C3=BCr=20unsere=20lisp=20Funktionen=20impleme?= =?UTF-8?q?ntiert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + Lisp/KreiselInsert.lsp | 3 - Lisp/VarioFoerderer.lsp | 8 +- Lisp/ssg_dbg.lsp | 2 +- bin/setenv.bat | 6 + tests/ILS_test.lsp | 99 - tests/ILS_test.scr | 5 - tests/ILStest.dxf | 3174 ----------------------- tests/conftest.py | 72 + tests/create_ILStest_dxf.py | 44 - tests/create_testbase.py | 71 + tests/references/ILStest_export_ref.csv | 6 - tests/requirements.txt | 2 + tests/test_kreisel.py | 133 + tests/testdata/kreisel_tests.json | 125 + tests/validate_tests.py | 232 -- 16 files changed, 415 insertions(+), 3568 deletions(-) delete mode 100644 tests/ILS_test.lsp delete mode 100644 tests/ILS_test.scr delete mode 100644 tests/ILStest.dxf create mode 100644 tests/conftest.py delete mode 100644 tests/create_ILStest_dxf.py create mode 100644 tests/create_testbase.py delete mode 100644 tests/references/ILStest_export_ref.csv create mode 100644 tests/requirements.txt create mode 100644 tests/test_kreisel.py create mode 100644 tests/testdata/kreisel_tests.json delete mode 100644 tests/validate_tests.py diff --git a/.gitignore b/.gitignore index 6aff53c..f2b1bcd 100644 --- a/.gitignore +++ b/.gitignore @@ -177,6 +177,7 @@ cython_debug/ # Benutzerdefiniert /work /log +/tests/output/ # BricsCAD kompilierte Menuedateien *.cui diff --git a/Lisp/KreiselInsert.lsp b/Lisp/KreiselInsert.lsp index a827ba8..ab57c29 100644 --- a/Lisp/KreiselInsert.lsp +++ b/Lisp/KreiselInsert.lsp @@ -129,7 +129,6 @@ (setq result (eval lastNrVar)) (dbgp (strcat "Naechste Nummer: " (itoa result))) (dbgreturn result) - result ) ;; Wrapper: Naechste Kreisel-Nummer @@ -137,7 +136,6 @@ (dbgf "kreisel-next-number") (setq result (component-next-number "KREISEL_*" '#Kreisel_LetzteNr)) (dbgreturn result) - result ) ;; Wrapper: Naechste Eckrad-Nummer @@ -145,7 +143,6 @@ (dbgf "eckrad-next-number") (setq result (component-next-number "ECKRAD_*" '#Eckrad_LetzteNr)) (dbgreturn result) - result ) ;; Beschriftungstext erzeugen diff --git a/Lisp/VarioFoerderer.lsp b/Lisp/VarioFoerderer.lsp index a426d1a..a1cb886 100644 --- a/Lisp/VarioFoerderer.lsp +++ b/Lisp/VarioFoerderer.lsp @@ -601,8 +601,8 @@ ;; 5. Erster Vertikalbogen (if (= richtung "Auf") - (setq bogen-name (strcat "Vario_Bogen_auf_" (itoa best-winkel))) - (setq bogen-name (strcat "Vario_Bogen_ab_" (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) grad-zeichen)) ) (princ (strcat "\n\n5/11: " bogen-name)) (setq aktueller-punkt (insert-block-by-ks bogen-name aktueller-punkt)) @@ -646,8 +646,8 @@ ;; 7. Zweiter Vertikalbogen (gegenläufig) (if (= richtung "Auf") - (setq bogen-name (strcat "Vario_Bogen_ab_" (itoa best-winkel))) - (setq bogen-name (strcat "Vario_Bogen_auf_" (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) grad-zeichen)) ) (princ (strcat "\n\n7/11: " bogen-name)) (setq aktueller-punkt (insert-block-by-ks bogen-name aktueller-punkt)) diff --git a/Lisp/ssg_dbg.lsp b/Lisp/ssg_dbg.lsp index 5a4e23c..e7d18db 100644 --- a/Lisp/ssg_dbg.lsp +++ b/Lisp/ssg_dbg.lsp @@ -229,7 +229,7 @@ (dbg-flush) ) ) - (princ) + retval ) ;; ------------------------------------------------------------ diff --git a/bin/setenv.bat b/bin/setenv.bat index bc4700f..1c434dd 100644 --- a/bin/setenv.bat +++ b/bin/setenv.bat @@ -16,6 +16,9 @@ set "DXFM_BIN=%DXFMAKRO%\bin" set "DXFM_LIB=%DXFMAKRO%\lib" set "DXFM_DATA=%DXFMAKRO%\data" 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_LOG=%DXFMAKRO%\logs" 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_LOG%" mkdir "%DXFM_LOG%" 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 echo. diff --git a/tests/ILS_test.lsp b/tests/ILS_test.lsp deleted file mode 100644 index e540bcc..0000000 --- a/tests/ILS_test.lsp +++ /dev/null @@ -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) diff --git a/tests/ILS_test.scr b/tests/ILS_test.scr deleted file mode 100644 index 2e7bf73..0000000 --- a/tests/ILS_test.scr +++ /dev/null @@ -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 diff --git a/tests/ILStest.dxf b/tests/ILStest.dxf deleted file mode 100644 index 4fa6746..0000000 --- a/tests/ILStest.dxf +++ /dev/null @@ -1,3174 +0,0 @@ - 0 -SECTION - 2 -HEADER - 9 -$ACADVER - 1 -AC1032 - 9 -$ACADMAINTVER - 90 -4 - 9 -$DWGCODEPAGE - 3 -ANSI_1252 - 9 -$LASTSAVEDBY - 1 -ezdxf - 9 -$REQUIREDVERSIONS -160 -0 - 9 -$INSBASE - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$EXTMIN - 10 -1e+20 - 20 -1e+20 - 30 -1e+20 - 9 -$EXTMAX - 10 --1e+20 - 20 --1e+20 - 30 --1e+20 - 9 -$LIMMIN - 10 -0.0 - 20 -0.0 - 9 -$LIMMAX - 10 -420.0 - 20 -297.0 - 9 -$ORTHOMODE - 70 -0 - 9 -$REGENMODE - 70 -1 - 9 -$FILLMODE - 70 -1 - 9 -$QTEXTMODE - 70 -0 - 9 -$MIRRTEXT - 70 -1 - 9 -$LTSCALE - 40 -1.0 - 9 -$ATTMODE - 70 -1 - 9 -$TEXTSIZE - 40 -2.5 - 9 -$TRACEWID - 40 -1.0 - 9 -$TEXTSTYLE - 7 -Standard - 9 -$CLAYER - 8 -0 - 9 -$CELTYPE - 6 -ByLayer - 9 -$CECOLOR - 62 -256 - 9 -$CELTSCALE - 40 -1.0 - 9 -$DISPSILH - 70 -0 - 9 -$DIMSCALE - 40 -1.0 - 9 -$DIMASZ - 40 -2.5 - 9 -$DIMEXO - 40 -0.625 - 9 -$DIMDLI - 40 -3.75 - 9 -$DIMRND - 40 -0.0 - 9 -$DIMDLE - 40 -0.0 - 9 -$DIMEXE - 40 -1.25 - 9 -$DIMTP - 40 -0.0 - 9 -$DIMTM - 40 -0.0 - 9 -$DIMTXT - 40 -2.5 - 9 -$DIMCEN - 40 -2.5 - 9 -$DIMTSZ - 40 -0.0 - 9 -$DIMTOL - 70 -0 - 9 -$DIMLIM - 70 -0 - 9 -$DIMTIH - 70 -0 - 9 -$DIMTOH - 70 -0 - 9 -$DIMSE1 - 70 -0 - 9 -$DIMSE2 - 70 -0 - 9 -$DIMTAD - 70 -1 - 9 -$DIMZIN - 70 -8 - 9 -$DIMBLK - 1 - - 9 -$DIMASO - 70 -1 - 9 -$DIMSHO - 70 -1 - 9 -$DIMPOST - 1 - - 9 -$DIMAPOST - 1 - - 9 -$DIMALT - 70 -0 - 9 -$DIMALTD - 70 -3 - 9 -$DIMALTF - 40 -0.03937007874 - 9 -$DIMLFAC - 40 -1.0 - 9 -$DIMTOFL - 70 -1 - 9 -$DIMTVP - 40 -0.0 - 9 -$DIMTIX - 70 -0 - 9 -$DIMSOXD - 70 -0 - 9 -$DIMSAH - 70 -0 - 9 -$DIMBLK1 - 1 - - 9 -$DIMBLK2 - 1 - - 9 -$DIMSTYLE - 2 -ISO-25 - 9 -$DIMCLRD - 70 -0 - 9 -$DIMCLRE - 70 -0 - 9 -$DIMCLRT - 70 -0 - 9 -$DIMTFAC - 40 -1.0 - 9 -$DIMGAP - 40 -0.625 - 9 -$DIMJUST - 70 -0 - 9 -$DIMSD1 - 70 -0 - 9 -$DIMSD2 - 70 -0 - 9 -$DIMTOLJ - 70 -0 - 9 -$DIMTZIN - 70 -8 - 9 -$DIMALTZ - 70 -0 - 9 -$DIMALTTZ - 70 -0 - 9 -$DIMUPT - 70 -0 - 9 -$DIMDEC - 70 -2 - 9 -$DIMTDEC - 70 -2 - 9 -$DIMALTU - 70 -2 - 9 -$DIMALTTD - 70 -3 - 9 -$DIMTXSTY - 7 -Standard - 9 -$DIMAUNIT - 70 -0 - 9 -$DIMADEC - 70 -0 - 9 -$DIMALTRND - 40 -0.0 - 9 -$DIMAZIN - 70 -0 - 9 -$DIMDSEP - 70 -44 - 9 -$DIMATFIT - 70 -3 - 9 -$DIMFRAC - 70 -0 - 9 -$DIMLDRBLK - 1 - - 9 -$DIMLUNIT - 70 -2 - 9 -$DIMLWD - 70 --2 - 9 -$DIMLWE - 70 --2 - 9 -$DIMTMOVE - 70 -0 - 9 -$DIMFXL - 40 -1.0 - 9 -$DIMFXLON - 70 -0 - 9 -$DIMJOGANG - 40 -0.785398163397 - 9 -$DIMTFILL - 70 -0 - 9 -$DIMTFILLCLR - 70 -0 - 9 -$DIMARCSYM - 70 -0 - 9 -$DIMLTYPE - 6 - - 9 -$DIMLTEX1 - 6 - - 9 -$DIMLTEX2 - 6 - - 9 -$DIMTXTDIRECTION - 70 -0 - 9 -$LUNITS - 70 -2 - 9 -$LUPREC - 70 -4 - 9 -$SKETCHINC - 40 -1.0 - 9 -$FILLETRAD - 40 -10.0 - 9 -$AUNITS - 70 -0 - 9 -$AUPREC - 70 -2 - 9 -$MENU - 1 -. - 9 -$ELEVATION - 40 -0.0 - 9 -$PELEVATION - 40 -0.0 - 9 -$THICKNESS - 40 -0.0 - 9 -$LIMCHECK - 70 -0 - 9 -$CHAMFERA - 40 -0.0 - 9 -$CHAMFERB - 40 -0.0 - 9 -$CHAMFERC - 40 -0.0 - 9 -$CHAMFERD - 40 -0.0 - 9 -$SKPOLY - 70 -0 - 9 -$TDCREATE - 40 -2461181.0330439815 - 9 -$TDUCREATE - 40 -2458532.153996898 - 9 -$TDUPDATE - 40 -2461181.0330439815 - 9 -$TDUUPDATE - 40 -2458532.1544311 - 9 -$TDINDWG - 40 -0.0 - 9 -$TDUSRTIMER - 40 -0.0 - 9 -$USRTIMER - 70 -1 - 9 -$ANGBASE - 50 -0.0 - 9 -$ANGDIR - 70 -0 - 9 -$PDMODE - 70 -0 - 9 -$PDSIZE - 40 -0.0 - 9 -$PLINEWID - 40 -0.0 - 9 -$SPLFRAME - 70 -0 - 9 -$SPLINETYPE - 70 -6 - 9 -$SPLINESEGS - 70 -8 - 9 -$HANDSEED - 5 -36 - 9 -$SURFTAB1 - 70 -6 - 9 -$SURFTAB2 - 70 -6 - 9 -$SURFTYPE - 70 -6 - 9 -$SURFU - 70 -6 - 9 -$SURFV - 70 -6 - 9 -$UCSBASE - 2 - - 9 -$UCSNAME - 2 - - 9 -$UCSORG - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$UCSXDIR - 10 -1.0 - 20 -0.0 - 30 -0.0 - 9 -$UCSYDIR - 10 -0.0 - 20 -1.0 - 30 -0.0 - 9 -$UCSORTHOREF - 2 - - 9 -$UCSORTHOVIEW - 70 -0 - 9 -$UCSORGTOP - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$UCSORGBOTTOM - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$UCSORGLEFT - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$UCSORGRIGHT - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$UCSORGFRONT - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$UCSORGBACK - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSBASE - 2 - - 9 -$PUCSNAME - 2 - - 9 -$PUCSORG - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSXDIR - 10 -1.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSYDIR - 10 -0.0 - 20 -1.0 - 30 -0.0 - 9 -$PUCSORTHOREF - 2 - - 9 -$PUCSORTHOVIEW - 70 -0 - 9 -$PUCSORGTOP - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSORGBOTTOM - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSORGLEFT - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSORGRIGHT - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSORGFRONT - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PUCSORGBACK - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$USERI1 - 70 -0 - 9 -$USERI2 - 70 -0 - 9 -$USERI3 - 70 -0 - 9 -$USERI4 - 70 -0 - 9 -$USERI5 - 70 -0 - 9 -$USERR1 - 40 -0.0 - 9 -$USERR2 - 40 -0.0 - 9 -$USERR3 - 40 -0.0 - 9 -$USERR4 - 40 -0.0 - 9 -$USERR5 - 40 -0.0 - 9 -$WORLDVIEW - 70 -1 - 9 -$SHADEDGE - 70 -3 - 9 -$SHADEDIF - 70 -70 - 9 -$TILEMODE - 70 -1 - 9 -$MAXACTVP - 70 -64 - 9 -$PINSBASE - 10 -0.0 - 20 -0.0 - 30 -0.0 - 9 -$PLIMCHECK - 70 -0 - 9 -$PEXTMIN - 10 -1e+20 - 20 -1e+20 - 30 -1e+20 - 9 -$PEXTMAX - 10 --1e+20 - 20 --1e+20 - 30 --1e+20 - 9 -$PLIMMIN - 10 -0.0 - 20 -0.0 - 9 -$PLIMMAX - 10 -420.0 - 20 -297.0 - 9 -$UNITMODE - 70 -0 - 9 -$VISRETAIN - 70 -1 - 9 -$PLINEGEN - 70 -0 - 9 -$PSLTSCALE - 70 -1 - 9 -$TREEDEPTH - 70 -3020 - 9 -$CMLSTYLE - 2 -Standard - 9 -$CMLJUST - 70 -0 - 9 -$CMLSCALE - 40 -20.0 - 9 -$PROXYGRAPHICS - 70 -1 - 9 -$MEASUREMENT - 70 -1 - 9 -$CELWEIGHT -370 --1 - 9 -$ENDCAPS -280 -0 - 9 -$JOINSTYLE -280 -0 - 9 -$LWDISPLAY -290 -0 - 9 -$INSUNITS - 70 -6 - 9 -$HYPERLINKBASE - 1 - - 9 -$STYLESHEET - 1 - - 9 -$XEDIT -290 -1 - 9 -$CEPSNTYPE -380 -0 - 9 -$PSTYLEMODE -290 -1 - 9 -$FINGERPRINTGUID - 2 -{49398050-CF96-40FD-9CA1-CB4526AAE4CA} - 9 -$VERSIONGUID - 2 -{E9422FBF-5189-4DA2-8E37-FC263FADDE93} - 9 -$EXTNAMES -290 -1 - 9 -$PSVPSCALE - 40 -0.0 - 9 -$OLESTARTUP -290 -0 - 9 -$SORTENTS -280 -127 - 9 -$INDEXCTL -280 -0 - 9 -$HIDETEXT -280 -1 - 9 -$XCLIPFRAME -280 -1 - 9 -$HALOGAP -280 -0 - 9 -$OBSCOLOR - 70 -257 - 9 -$OBSLTYPE -280 -0 - 9 -$INTERSECTIONDISPLAY -280 -0 - 9 -$INTERSECTIONCOLOR - 70 -257 - 9 -$DIMASSOC -280 -2 - 9 -$PROJECTNAME - 1 - - 9 -$CAMERADISPLAY -290 -0 - 9 -$LENSLENGTH - 40 -50.0 - 9 -$CAMERAHEIGHT - 40 -0.0 - 9 -$STEPSPERSEC - 40 -24.0 - 9 -$STEPSIZE - 40 -100.0 - 9 -$3DDWFPREC - 40 -2.0 - 9 -$PSOLWIDTH - 40 -0.005 - 9 -$PSOLHEIGHT - 40 -0.08 - 9 -$LOFTANG1 - 40 -1.570796326795 - 9 -$LOFTANG2 - 40 -1.570796326795 - 9 -$LOFTMAG1 - 40 -0.0 - 9 -$LOFTMAG2 - 40 -0.0 - 9 -$LOFTPARAM - 70 -7 - 9 -$LOFTNORMALS -280 -1 - 9 -$LATITUDE - 40 -37.795 - 9 -$LONGITUDE - 40 --122.394 - 9 -$NORTHDIRECTION - 40 -0.0 - 9 -$TIMEZONE - 70 --8000 - 9 -$LIGHTGLYPHDISPLAY -280 -1 - 9 -$TILEMODELIGHTSYNCH -280 -1 - 9 -$CMATERIAL -347 -20 - 9 -$SOLIDHIST -280 -0 - 9 -$SHOWHIST -280 -1 - 9 -$DWFFRAME -280 -2 - 9 -$DGNFRAME -280 -2 - 9 -$REALWORLDSCALE -290 -1 - 9 -$INTERFERECOLOR - 62 -256 - 9 -$CSHADOW -280 -0 - 9 -$SHADOWPLANELOCATION - 40 -0.0 - 0 -ENDSEC - 0 -SECTION - 2 -CLASSES - 0 -CLASS - 1 -ACDBDICTIONARYWDFLT - 2 -AcDbDictionaryWithDefault - 3 -ObjectDBX Classes - 90 -0 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -SUN - 2 -AcDbSun - 3 -SCENEOE - 90 -1153 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -VISUALSTYLE - 2 -AcDbVisualStyle - 3 -ObjectDBX Classes - 90 -4095 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -MATERIAL - 2 -AcDbMaterial - 3 -ObjectDBX Classes - 90 -1153 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -SCALE - 2 -AcDbScale - 3 -ObjectDBX Classes - 90 -1153 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -TABLESTYLE - 2 -AcDbTableStyle - 3 -ObjectDBX Classes - 90 -4095 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -MLEADERSTYLE - 2 -AcDbMLeaderStyle - 3 -ACDB_MLEADERSTYLE_CLASS - 90 -4095 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -DICTIONARYVAR - 2 -AcDbDictionaryVar - 3 -ObjectDBX Classes - 90 -0 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -CELLSTYLEMAP - 2 -AcDbCellStyleMap - 3 -ObjectDBX Classes - 90 -1152 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -MENTALRAYRENDERSETTINGS - 2 -AcDbMentalRayRenderSettings - 3 -SCENEOE - 90 -1024 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -ACDBDETAILVIEWSTYLE - 2 -AcDbDetailViewStyle - 3 -ObjectDBX Classes - 90 -1025 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -ACDBSECTIONVIEWSTYLE - 2 -AcDbSectionViewStyle - 3 -ObjectDBX Classes - 90 -1025 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -RASTERVARIABLES - 2 -AcDbRasterVariables - 3 -ISM - 90 -0 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -LAYOUT - 2 -AcDbLayout - 3 -ObjectDBX Classes - 90 -0 - 91 -0 -280 -0 -281 -0 - 0 -CLASS - 1 -ACDBPLACEHOLDER - 2 -AcDbPlaceHolder - 3 -ObjectDBX Classes - 90 -0 - 91 -0 -280 -0 -281 -0 - 0 -ENDSEC - 0 -SECTION - 2 -TABLES - 0 -TABLE - 2 -VPORT - 5 -8 -330 -0 -100 -AcDbSymbolTable - 70 -1 - 0 -VPORT - 5 -23 -330 -8 -100 -AcDbSymbolTableRecord -100 -AcDbViewportTableRecord - 2 -*Active - 70 -0 - 10 -0.0 - 20 -0.0 - 11 -1.0 - 21 -1.0 - 12 -0.0 - 22 -0.0 - 13 -0.0 - 23 -0.0 - 14 -0.5 - 24 -0.5 - 15 -0.5 - 25 -0.5 - 16 -0.0 - 26 -0.0 - 36 -1.0 - 17 -0.0 - 27 -0.0 - 37 -0.0 - 40 -1000.0 - 41 -1.34 - 42 -50.0 - 43 -0.0 - 44 -0.0 - 50 -0.0 - 51 -0.0 - 71 -0 - 72 -1000 - 73 -1 - 74 -3 - 75 -0 - 76 -0 - 77 -0 - 78 -0 -281 -0 - 65 -0 -146 -0.0 - 0 -ENDTAB - 0 -TABLE - 2 -LTYPE - 5 -2 -330 -0 -100 -AcDbSymbolTable - 70 -3 - 0 -LTYPE - 5 -24 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -ByBlock - 70 -0 - 3 - - 72 -65 - 73 -0 - 40 -0.0 - 0 -LTYPE - 5 -25 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -ByLayer - 70 -0 - 3 - - 72 -65 - 73 -0 - 40 -0.0 - 0 -LTYPE - 5 -26 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -Continuous - 70 -0 - 3 - - 72 -65 - 73 -0 - 40 -0.0 - 0 -ENDTAB - 0 -TABLE - 2 -LAYER - 5 -1 -330 -0 -100 -AcDbSymbolTable - 70 -2 - 0 -LAYER - 5 -27 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -0 - 70 -0 - 62 -7 - 6 -Continuous -370 --3 -390 -13 -347 -21 - 0 -LAYER - 5 -28 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -Defpoints - 70 -0 - 62 -7 - 6 -Continuous -290 -0 -370 --3 -390 -13 -347 -21 - 0 -ENDTAB - 0 -TABLE - 2 -STYLE - 5 -5 -330 -0 -100 -AcDbSymbolTable - 70 -1 - 0 -STYLE - 5 -29 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -Standard - 70 -0 - 40 -0.0 - 41 -1.0 - 50 -0.0 - 71 -0 - 42 -2.5 - 3 -txt - 4 - - 0 -ENDTAB - 0 -TABLE - 2 -VIEW - 5 -7 -330 -0 -100 -AcDbSymbolTable - 70 -0 - 0 -ENDTAB - 0 -TABLE - 2 -UCS - 5 -6 -330 -0 -100 -AcDbSymbolTable - 70 -0 - 0 -ENDTAB - 0 -TABLE - 2 -APPID - 5 -3 -330 -0 -100 -AcDbSymbolTable - 70 -3 - 0 -APPID - 5 -2A -330 -3 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -ACAD - 70 -0 - 0 -APPID - 5 -33 -330 -3 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -HATCHBACKGROUNDCOLOR - 70 -0 - 0 -APPID - 5 -34 -330 -3 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -EZDXF - 70 -0 - 0 -ENDTAB - 0 -TABLE - 2 -DIMSTYLE - 5 -4 -330 -0 -100 -AcDbSymbolTable - 70 -1 -100 -AcDbDimStyleTable - 0 -DIMSTYLE -105 -2B -330 -4 -100 -AcDbSymbolTableRecord -100 -AcDbDimStyleTableRecord - 2 -Standard - 70 -0 - 40 -1.0 - 41 -2.5 - 42 -0.625 - 43 -3.75 - 44 -1.25 - 45 -0.0 - 46 -0.0 - 47 -0.0 - 48 -0.0 - 49 -2.5 -140 -2.5 -141 -2.5 -142 -0.0 -143 -0.03937007874 -144 -1.0 -145 -0.0 -146 -1.0 -147 -0.625 -148 -0.0 - 69 -0 - 70 -0 - 71 -0 - 72 -0 - 73 -0 - 74 -0 - 75 -0 - 76 -0 - 77 -1 - 78 -8 - 79 -3 -170 -0 -171 -3 -172 -1 -173 -0 -174 -0 -175 -0 -176 -0 -177 -0 -178 -0 -179 -2 -271 -2 -272 -2 -273 -2 -274 -3 -275 -0 -276 -0 -277 -2 -278 -44 -279 -0 -280 -0 -281 -0 -282 -0 -283 -0 -284 -8 -285 -0 -286 -0 -288 -0 -289 -3 -290 -0 -371 --2 -372 --2 - 0 -ENDTAB - 0 -TABLE - 2 -BLOCK_RECORD - 5 -9 -330 -0 -100 -AcDbSymbolTable - 70 -2 - 0 -BLOCK_RECORD - 5 -17 -330 -9 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*Model_Space -340 -1A - 70 -0 -280 -1 -281 -0 - 0 -BLOCK_RECORD - 5 -1B -330 -9 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*Paper_Space -340 -1E - 70 -0 -280 -1 -281 -0 - 0 -ENDTAB - 0 -ENDSEC - 0 -SECTION - 2 -BLOCKS - 0 -BLOCK - 5 -18 -330 -17 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*Model_Space - 70 -0 - 10 -0.0 - 20 -0.0 - 30 -0.0 - 3 -*Model_Space - 1 - - 0 -ENDBLK - 5 -19 -330 -17 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1C -330 -1B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*Paper_Space - 70 -0 - 10 -0.0 - 20 -0.0 - 30 -0.0 - 3 -*Paper_Space - 1 - - 0 -ENDBLK - 5 -1D -330 -1B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -ENDSEC - 0 -SECTION - 2 -ENTITIES - 0 -LINE - 5 -2F -330 -17 -100 -AcDbEntity - 8 -S_LP - 62 -1 -100 -AcDbLine - 10 -0.0 - 20 -0.0 - 30 -2500.0 - 11 -2000.0 - 21 -0.0 - 31 -2500.0 - 0 -LINE - 5 -30 -330 -17 -100 -AcDbEntity - 8 -S_LP - 62 -1 -100 -AcDbLine - 10 -0.0 - 20 -5000.0 - 30 -2500.0 - 11 -2000.0 - 21 -5000.0 - 31 -2500.0 - 0 -LINE - 5 -31 -330 -17 -100 -AcDbEntity - 8 -S_LP - 62 -1 -100 -AcDbLine - 10 -0.0 - 20 -0.0 - 30 -2500.0 - 11 -0.0 - 21 -2000.0 - 31 -2500.0 - 0 -LINE - 5 -32 -330 -17 -100 -AcDbEntity - 8 -S_LP - 62 -1 -100 -AcDbLine - 10 -5000.0 - 20 -0.0 - 30 -2500.0 - 11 -5000.0 - 21 -2000.0 - 31 -2500.0 - 0 -ENDSEC - 0 -SECTION - 2 -OBJECTS - 0 -DICTIONARY - 5 -A -330 -0 -100 -AcDbDictionary -280 -0 -281 -1 - 3 -ACAD_COLOR -350 -B - 3 -ACAD_GROUP -350 -C - 3 -ACAD_LAYOUT -350 -D - 3 -ACAD_MATERIAL -350 -E - 3 -ACAD_MLEADERSTYLE -350 -F - 3 -ACAD_MLINESTYLE -350 -10 - 3 -ACAD_PLOTSETTINGS -350 -11 - 3 -ACAD_PLOTSTYLENAME -350 -12 - 3 -ACAD_SCALELIST -350 -14 - 3 -ACAD_TABLESTYLE -350 -15 - 3 -ACAD_VISUALSTYLE -350 -16 - 3 -EZDXF_META -350 -2D - 0 -DICTIONARY - 5 -B -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 0 -DICTIONARY - 5 -C -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 0 -DICTIONARY - 5 -D -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 3 -Model -350 -1A - 3 -Layout1 -350 -1E - 0 -DICTIONARY - 5 -E -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 3 -ByBlock -350 -1F - 3 -ByLayer -350 -20 - 3 -Global -350 -21 - 0 -DICTIONARY - 5 -F -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 3 -Standard -350 -2C - 0 -DICTIONARY - 5 -10 -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 3 -Standard -350 -22 - 0 -DICTIONARY - 5 -11 -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 0 -ACDBDICTIONARYWDFLT - 5 -12 -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 3 -Normal -350 -13 -100 -AcDbDictionaryWithDefault -340 -13 - 0 -ACDBPLACEHOLDER - 5 -13 -330 -12 - 0 -DICTIONARY - 5 -14 -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 0 -DICTIONARY - 5 -15 -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 0 -DICTIONARY - 5 -16 -330 -A -100 -AcDbDictionary -280 -0 -281 -1 - 0 -LAYOUT - 5 -1A -330 -D -100 -AcDbPlotSettings - 1 - - 4 -A3 - 6 - - 40 -7.5 - 41 -20.0 - 42 -7.5 - 43 -20.0 - 44 -420.0 - 45 -297.0 - 46 -0.0 - 47 -0.0 - 48 -0.0 - 49 -0.0 -140 -0.0 -141 -0.0 -142 -1.0 -143 -1.0 - 70 -1024 - 72 -1 - 73 -0 - 74 -5 - 7 - - 75 -16 - 76 -0 - 77 -2 - 78 -300 -147 -1.0 -148 -0.0 -149 -0.0 -100 -AcDbLayout - 1 -Model - 70 -1 - 71 -0 - 10 -0.0 - 20 -0.0 - 11 -420.0 - 21 -297.0 - 12 -0.0 - 22 -0.0 - 32 -0.0 - 14 -1e+20 - 24 -1e+20 - 34 -1e+20 - 15 --1e+20 - 25 --1e+20 - 35 --1e+20 -146 -0.0 - 13 -0.0 - 23 -0.0 - 33 -0.0 - 16 -1.0 - 26 -0.0 - 36 -0.0 - 17 -0.0 - 27 -1.0 - 37 -0.0 - 76 -1 -330 -17 - 0 -LAYOUT - 5 -1E -330 -D -100 -AcDbPlotSettings - 1 - - 4 -A3 - 6 - - 40 -7.5 - 41 -20.0 - 42 -7.5 - 43 -20.0 - 44 -420.0 - 45 -297.0 - 46 -0.0 - 47 -0.0 - 48 -0.0 - 49 -0.0 -140 -0.0 -141 -0.0 -142 -1.0 -143 -1.0 - 70 -0 - 72 -1 - 73 -0 - 74 -5 - 7 - - 75 -16 - 76 -0 - 77 -2 - 78 -300 -147 -1.0 -148 -0.0 -149 -0.0 -100 -AcDbLayout - 1 -Layout1 - 70 -1 - 71 -1 - 10 -0.0 - 20 -0.0 - 11 -420.0 - 21 -297.0 - 12 -0.0 - 22 -0.0 - 32 -0.0 - 14 -1e+20 - 24 -1e+20 - 34 -1e+20 - 15 --1e+20 - 25 --1e+20 - 35 --1e+20 -146 -0.0 - 13 -0.0 - 23 -0.0 - 33 -0.0 - 16 -1.0 - 26 -0.0 - 36 -0.0 - 17 -0.0 - 27 -1.0 - 37 -0.0 - 76 -1 -330 -1B - 0 -MATERIAL - 5 -1F -102 -{ACAD_REACTORS -330 -E -102 -} -330 -E -100 -AcDbMaterial - 1 -ByBlock - 2 - - 70 -0 - 40 -1.0 - 71 -1 - 41 -1.0 - 91 --1023410177 - 42 -1.0 - 72 -1 - 3 - - 73 -1 - 74 -1 - 75 -1 - 44 -0.5 - 73 -0 - 45 -1.0 - 46 -1.0 - 77 -1 - 4 - - 78 -1 - 79 -1 -170 -1 - 48 -1.0 -171 -1 - 6 - -172 -1 -173 -1 -174 -1 -140 -1.0 -141 -1.0 -175 -1 - 7 - -176 -1 -177 -1 -178 -1 -143 -1.0 -179 -1 - 8 - -270 -1 -271 -1 -272 -1 -145 -1.0 -146 -1.0 -273 -1 - 9 - -274 -1 -275 -1 -276 -1 - 42 -1.0 - 72 -1 - 3 - - 73 -1 - 74 -1 - 75 -1 - 94 -63 - 0 -MATERIAL - 5 -20 -102 -{ACAD_REACTORS -330 -E -102 -} -330 -E -100 -AcDbMaterial - 1 -ByLayer - 2 - - 70 -0 - 40 -1.0 - 71 -1 - 41 -1.0 - 91 --1023410177 - 42 -1.0 - 72 -1 - 3 - - 73 -1 - 74 -1 - 75 -1 - 44 -0.5 - 73 -0 - 45 -1.0 - 46 -1.0 - 77 -1 - 4 - - 78 -1 - 79 -1 -170 -1 - 48 -1.0 -171 -1 - 6 - -172 -1 -173 -1 -174 -1 -140 -1.0 -141 -1.0 -175 -1 - 7 - -176 -1 -177 -1 -178 -1 -143 -1.0 -179 -1 - 8 - -270 -1 -271 -1 -272 -1 -145 -1.0 -146 -1.0 -273 -1 - 9 - -274 -1 -275 -1 -276 -1 - 42 -1.0 - 72 -1 - 3 - - 73 -1 - 74 -1 - 75 -1 - 94 -63 - 0 -MATERIAL - 5 -21 -102 -{ACAD_REACTORS -330 -E -102 -} -330 -E -100 -AcDbMaterial - 1 -Global - 2 - - 70 -0 - 40 -1.0 - 71 -1 - 41 -1.0 - 91 --1023410177 - 42 -1.0 - 72 -1 - 3 - - 73 -1 - 74 -1 - 75 -1 - 44 -0.5 - 73 -0 - 45 -1.0 - 46 -1.0 - 77 -1 - 4 - - 78 -1 - 79 -1 -170 -1 - 48 -1.0 -171 -1 - 6 - -172 -1 -173 -1 -174 -1 -140 -1.0 -141 -1.0 -175 -1 - 7 - -176 -1 -177 -1 -178 -1 -143 -1.0 -179 -1 - 8 - -270 -1 -271 -1 -272 -1 -145 -1.0 -146 -1.0 -273 -1 - 9 - -274 -1 -275 -1 -276 -1 - 42 -1.0 - 72 -1 - 3 - - 73 -1 - 74 -1 - 75 -1 - 94 -63 - 0 -MLINESTYLE - 5 -22 -102 -{ACAD_REACTORS -330 -10 -102 -} -330 -10 -100 -AcDbMlineStyle - 2 -Standard - 70 -0 - 3 - - 62 -256 - 51 -90.0 - 52 -90.0 - 71 -2 - 49 -0.5 - 62 -256 - 6 -BYLAYER - 49 --0.5 - 62 -256 - 6 -BYLAYER - 0 -MLEADERSTYLE - 5 -2C -102 -{ACAD_REACTORS -330 -F -102 -} -330 -F -100 -AcDbMLeaderStyle -179 -2 -170 -2 -171 -1 -172 -0 - 90 -2 - 40 -0.0 - 41 -0.0 -173 -1 - 91 --1056964608 - 92 --2 -290 -1 - 42 -2.0 -291 -1 - 43 -8.0 - 3 -Standard - 44 -4.0 -300 - -342 -29 -174 -1 -175 -1 -176 -0 -178 -1 - 93 --1056964608 - 45 -4.0 -292 -0 -297 -0 - 46 -4.0 - 94 --1056964608 - 47 -1.0 - 49 -1.0 -140 -1.0 -294 -1 -141 -0.0 -177 -0 -142 -1.0 -295 -0 -296 -0 -143 -3.75 -271 -0 -272 -9 -273 -9 - 0 -DICTIONARY - 5 -2D -330 -A -100 -AcDbDictionary -281 -1 - 3 -CREATED_BY_EZDXF -350 -2E - 3 -WRITTEN_BY_EZDXF -350 -35 - 0 -DICTIONARYVAR - 5 -2E -330 -2D -100 -DictionaryVariables -280 -0 - 1 -1.4.1 @ 2026-05-19T22:47:35.388108+00:00 - 0 -DICTIONARYVAR - 5 -35 -330 -2D -100 -DictionaryVariables -280 -0 - 1 -1.4.1 @ 2026-05-19T22:47:35.388898+00:00 - 0 -ENDSEC - 0 -EOF diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..bd669c9 --- /dev/null +++ b/tests/conftest.py @@ -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) diff --git a/tests/create_ILStest_dxf.py b/tests/create_ILStest_dxf.py deleted file mode 100644 index 5d2d7ed..0000000 --- a/tests/create_ILStest_dxf.py +++ /dev/null @@ -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) diff --git a/tests/create_testbase.py b/tests/create_testbase.py new file mode 100644 index 0000000..dfb655c --- /dev/null +++ b/tests/create_testbase.py @@ -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() diff --git a/tests/references/ILStest_export_ref.csv b/tests/references/ILStest_export_ref.csv deleted file mode 100644 index c8c594c..0000000 --- a/tests/references/ILStest_export_ref.csv +++ /dev/null @@ -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"} diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..330a418 --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,2 @@ +ezdxf>=1.0 +pytest>=7.0 diff --git a/tests/test_kreisel.py b/tests/test_kreisel.py new file mode 100644 index 0000000..cce5d89 --- /dev/null +++ b/tests/test_kreisel.py @@ -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}" diff --git a/tests/testdata/kreisel_tests.json b/tests/testdata/kreisel_tests.json new file mode 100644 index 0000000..b3c9158 --- /dev/null +++ b/tests/testdata/kreisel_tests.json @@ -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 + } + } + ] +} diff --git a/tests/validate_tests.py b/tests/validate_tests.py deleted file mode 100644 index 80a8614..0000000 --- a/tests/validate_tests.py +++ /dev/null @@ -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 - -Prueft: - 1. export_raw.json: Anzahl und Typ der Bloecke - 2. ILStest_export.csv: Zeilenanzahl und Inhalte gegen Referenz - 3. ILStest.dxf: Existenz und KR_-Block-Anzahl -""" - -import json -import sys -import os -import csv - - -def load_json(path): - with open(path, "r", encoding="utf-8") as f: - return json.load(f) - - -def load_csv_lines(path): - """Laedt CSV und gibt Liste von Dicts zurueck (ohne Header).""" - with open(path, "r", encoding="utf-8") as f: - return f.read().strip().split("\n") - - -def validate_raw_json(results_dir): - """Prueft export_raw.json auf erwartete Kreisel-Bloecke.""" - raw_path = os.path.join(results_dir, "export_raw.json") - if not os.path.exists(raw_path): - return False, "export_raw.json nicht gefunden" - - blocks = load_json(raw_path) - kr_blocks = [b for b in blocks if b["block_name"].startswith("KR_")] - - errors = [] - - if len(kr_blocks) != 5: - errors.append(f"Erwartet 5 KR_-Bloecke, gefunden: {len(kr_blocks)}") - - # Pruefen ob alle Attribute haben - empty_attribs = [b for b in kr_blocks if not b.get("attribs")] - if empty_attribs: - errors.append(f"{len(empty_attribs)} Kreisel ohne Attribute: " - + ", ".join(b["block_name"] for b in empty_attribs)) - - # Pruefen ob erwartete Namen vorhanden - expected_names = { - "TEST_H_ObenUnten", "TEST_H_UntenOben", - "TEST_V_LinksRechts", "TEST_V_RechtsLinks", - "TEST_Insert" - } - found_names = set() - for b in kr_blocks: - attribs = b.get("attribs", {}) - name = attribs.get("NAME", "") - if name: - found_names.add(name) - missing = expected_names - found_names - if missing: - errors.append(f"Fehlende Kreisel-Namen: {missing}") - - # Pruefen der spezifischen Werte - for b in kr_blocks: - attribs = b.get("attribs", {}) - name = attribs.get("NAME", "") - - if name == "TEST_Insert": - if attribs.get("ABSTAND") != "6000": - errors.append(f"TEST_Insert: ABSTAND={attribs.get('ABSTAND')}, erwartet 6000") - if attribs.get("KREISELART") != "PIN": - errors.append(f"TEST_Insert: KREISELART={attribs.get('KREISELART')}, erwartet PIN") - if abs(b.get("rotation", 0) - 10.0) > 0.1: - errors.append(f"TEST_Insert: rotation={b.get('rotation')}, erwartet 10") - if abs(b.get("z", 0) - 2000.0) > 0.1: - errors.append(f"TEST_Insert: z={b.get('z')}, erwartet 2000") - - if name == "TEST_H_ObenUnten": - if attribs.get("KREISELART") != "STANDARD": - errors.append(f"TEST_H_ObenUnten: KREISELART={attribs.get('KREISELART')}, erwartet STANDARD") - if abs(b.get("rotation", 0) - 270.0) > 0.1: - errors.append(f"TEST_H_ObenUnten: rotation={b.get('rotation')}, erwartet 270") - - if name == "TEST_H_UntenOben": - if attribs.get("KREISELART") != "PIN": - errors.append(f"TEST_H_UntenOben: KREISELART={attribs.get('KREISELART')}, erwartet PIN") - - if name == "TEST_V_LinksRechts": - if attribs.get("KREISELART") != "PIN": - errors.append(f"TEST_V_LinksRechts: KREISELART={attribs.get('KREISELART')}, erwartet PIN") - if abs(b.get("rotation", 0) - 0.0) > 0.1: - errors.append(f"TEST_V_LinksRechts: rotation={b.get('rotation')}, erwartet 0") - - if name == "TEST_V_RechtsLinks": - if attribs.get("KREISELART") != "STANDARD": - errors.append(f"TEST_V_RechtsLinks: KREISELART={attribs.get('KREISELART')}, erwartet STANDARD") - - if errors: - return False, "export_raw.json Fehler:\n " + "\n ".join(errors) - return True, f"export_raw.json OK: {len(kr_blocks)} Kreisel mit Attributen" - - -def validate_csv(results_dir, references_dir): - """Prueft CSV gegen Referenz (Zeilenanzahl, Kreisel-Anzahl).""" - csv_path = os.path.join(results_dir, "ILStest_export.csv") - ref_path = os.path.join(references_dir, "ILStest_export_ref.csv") - - if not os.path.exists(csv_path): - return False, "ILStest_export.csv nicht gefunden" - - csv_lines = load_csv_lines(csv_path) - kreisel_lines = [l for l in csv_lines[1:] if "ILS 2.0 Kreisel" in l] - - errors = [] - - if len(kreisel_lines) != 5: - errors.append(f"Erwartet 5 Kreisel-Zeilen in CSV, gefunden: {len(kreisel_lines)}") - - # Gegen Referenz vergleichen (falls vorhanden) - if os.path.exists(ref_path): - ref_lines = load_csv_lines(ref_path) - ref_kreisel = [l for l in ref_lines[1:] if "ILS 2.0 Kreisel" in l] - - if len(kreisel_lines) != len(ref_kreisel): - errors.append(f"CSV hat {len(kreisel_lines)} Kreisel, Referenz hat {len(ref_kreisel)}") - - # Vergleiche Merkmale (ohne TeileId, da UUID) - for i, (act, ref) in enumerate(zip(kreisel_lines, ref_kreisel)): - # Merkmale extrahieren (letztes Feld) - act_parts = act.split(";") - ref_parts = ref.split(";") - if len(act_parts) >= 8 and len(ref_parts) >= 8: - act_merkmale = act_parts[-1] - ref_merkmale = ref_parts[-1] - if act_merkmale != ref_merkmale: - errors.append(f"Zeile {i+1} Merkmale unterschiedlich:\n" - f" IST: {act_merkmale}\n" - f" SOLL: {ref_merkmale}") - else: - errors.append(f"Referenz-CSV nicht gefunden: {ref_path} (erster Lauf?)") - - if errors: - return False, "CSV Fehler:\n " + "\n ".join(errors) - return True, f"CSV OK: {len(kreisel_lines)} Kreisel-Zeilen" - - -def validate_dxf(test_dir): - """Prueft ob ILStest.dxf existiert und KR_-Bloecke enthaelt.""" - dxf_path = os.path.join(test_dir, "ILStest.dxf") - if not os.path.exists(dxf_path): - return False, "ILStest.dxf nicht gefunden" - - # Einfache Textsuche nach KR_-Blocknamen im DXF - with open(dxf_path, "r", encoding="utf-8", errors="ignore") as f: - content = f.read() - - # Zaehle KR_-Blockreferenzen im ENTITIES-Bereich - entities_start = content.find("ENTITIES") - if entities_start < 0: - return False, "Kein ENTITIES-Bereich in DXF" - - entities_section = content[entities_start:] - kr_count = 0 - pos = 0 - while True: - pos = entities_section.find("\nKR_", pos) - if pos < 0: - break - kr_count += 1 - pos += 1 - - if kr_count < 5: - return False, f"Nur {kr_count} KR_-Referenzen in ENTITIES (erwartet mind. 5)" - - return True, f"DXF OK: {kr_count} KR_-Referenzen gefunden" - - -def main(): - if len(sys.argv) < 3: - print("Aufruf: python validate_tests.py ") - print(" results_dir = Ordner mit Testergebnissen (z.B. results/)") - print(" references_dir = Ordner mit Referenzdateien (z.B. tests/references/)") - sys.exit(1) - - results_dir = sys.argv[1] - references_dir = sys.argv[2] - test_dir = os.path.dirname(os.path.abspath(__file__)) - - print("=" * 60) - print("ILS Test Validierung") - print("=" * 60) - - all_ok = True - - # Test 1: export_raw.json - ok, msg = validate_raw_json(results_dir) - status = "PASS" if ok else "FAIL" - print(f"\n[{status}] {msg}") - if not ok: - all_ok = False - - # Test 2: CSV Export - ok, msg = validate_csv(results_dir, references_dir) - status = "PASS" if ok else "FAIL" - print(f"\n[{status}] {msg}") - if not ok: - all_ok = False - - # Test 3: DXF Datei - ok, msg = validate_dxf(test_dir) - status = "PASS" if ok else "FAIL" - print(f"\n[{status}] {msg}") - if not ok: - all_ok = False - - print("\n" + "=" * 60) - if all_ok: - print("ERGEBNIS: ALLE TESTS BESTANDEN") - else: - print("ERGEBNIS: TESTS FEHLGESCHLAGEN") - print("=" * 60) - - sys.exit(0 if all_ok else 1) - - -if __name__ == "__main__": - main()