Files
dxfmakros/tests
y.wang 833a4b60a6 fix: Lauf-Anfang als selbstbeschreibender Wert, Dialog-Hinweise lesbar
Die Frage "Lauf beginnen mit" (Modus 2) journalisiert jetzt den WERT
("mit-gf1"/"direkt"/"ohne") statt der Auswahl-Ziffer. Anlass war die
Umstellung der Optionsreihenfolge auf Regelfall zuerst: mit einer Ziffer
haette dieselbe "3" vor und nach der Umstellung Verschiedenes bedeutet,
eine bestehende Kette waere beim Doppelklick still mit einer ANDEREN
Anfangsvariante neu gebaut worden. Alte Ketten laufen ueber die Tabelle
*vfl-m2-anfang-alt* weiter; ein Wert, der weder Alt-Ziffer noch gueltiger
Wert ist, bricht den Aufbau ab und nennt Kette und Wert, statt eine
Variante zu raten.

Weiter aus der Modus-2-Arbeit:
- Laengenbudget je VF-Einheit (max. 25 m, max. 2 Vario-Kurven,
  *vfk-vf-kurven-max*), bei Ueberschreitung automatischer Schnitt
- nach einer VF-Geraden ist der Bogentyp waehlbar (GF-Bogen/Vario-Kurve)
- Segmentnummer steht im Kopf jedes Dialogs
- "Separator NACH" ist am letzten GF-Stueck vor einem ES gesperrt, der
  automatische Separator wird dort erklaert
- "Ohne Umlenkstation" ist mit AS-Element gesperrt
- Fuellerlaenge nur noch dann aus dem Rueckanker, wenn der VF-Lauf das
  Pfadende ist

Dialoge: Hinweis steht in Klammern hinter dem Ankreuzfeld statt darunter,
Lauf-Anfang-Optionen tragen die Nummern der Konsolenliste, die
Begruendungszeile ist breit genug und wird nicht mehr abgeschnitten.

14 neue Unit-Tests zur Wert-Normierung (durchlaufen die Alt-Tabelle).
Sprachdateien 1205/1205 synchron.

Offen: der Fuellerlaengen-Fix ist in BricsCAD noch nicht nachgemessen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-23 15:39:57 +02:00
..
2026-10-19 15:46:07 +02:00

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
tests/alltests.json
   |
   v
BricsCAD                          Kommandozeile
   |                                   |
   |  SSG_RUN_ALL_TESTS                |
   |  (fuehrt je Eintrag aus           |
   |   alltests.json den passenden     |
   |   TEST_<NAME> aus)                |
   |        |                          |
   v        v                          |
tests/output/                          |
   <name>_results.json  (immer)        |
   <name>_tests.dxf/.dwg (gemaess save)|
                                       |
                              bin\run_tests.bat --check
                                       |
                                  pytest -v
                                       |
                              test_<name>.py je Modul

LISP-Unit-Tests fuer reine Standardfunktionen (--lisp)

Neben den zeichnungsbasierten Integrationstests gibt es Unit-Tests fuer einfache LISP-Standardfunktionen — reine Funktionen ohne Zeichnungsdatenbank, Auswahlsaetze, Dialoge oder Blockdateien (String-/Zahl-/Vektor-/Alist-Helfer). Sie funktionieren analog zu den Python-Unittests: jeder Testfall vergleicht einen Funktionsaufruf gegen ein erwartetes Ergebnis.

  • Testrunner: tests/test_unit.lsp — Befehl TEST_UNIT, Mini-Framework mit tu-eq (exakt), tu-eqf (Fliesskomma-Toleranz), tu-true, tu-nil.
  • Startskript: tests/test_unit.scr — laedt SSG_LIB + die Tests, ruft TEST_UNIT auf und beendet BricsCAD (pfadunabhaengig ueber DXFMAKRO).
  • Ergebnis: Konsole (PASS/FAIL je Test) und tests/output/unit_results.txt (letzte Zeile RESULT: OK / RESULT: FAIL).

Ausfuehrung ueber die Kommandozeile (startet BricsCAD headless):

bin\run_tests.bat --lisp

run_tests.bat --lisp loescht das alte Ergebnis, startet BricsCAD mit test_unit.scr, gibt danach unit_results.txt aus und liefert Exit-Code 1, wenn ein Test fehlschlaegt oder kein Report erzeugt wurde.

Direkt in BricsCAD (SSG_LIB geladen):

(load (strcat (getenv "DXFMAKRO") "/tests/test_unit.lsp"))
TEST_UNIT

Getestete Module: ssg_core, ssg_lang, ssg_id, vf_core, export, Gefaellestrecke, OmniModulInsert, KreiselInsert.

Zeichnungsbasierte Integrationstests

Jedes Testmodul laeuft in einer eigenen, neuen Zeichnung (statt die aktuelle zu leeren/wiederzuverwenden). SSG_RUN_ALL_TESTS fragt beim Start interaktiv nach dem gewuenschten Modus:

  • Kontroll-Modus (Default, Enter/Nein): Zeichnung wird gespeichert, per _.ZOOM _Extents auf den Inhalt gezoomt und bleibt als eigener Tab offen — der naechste Test startet in einer weiteren neuen Zeichnung. Am Ende des Laufs sind alle Testzeichnungen gleichzeitig offen und direkt sichtbar. Sinnvoll, wenn neue/geaenderte Testfaelle visuell geprueft werden sollen. c:EXPORTCSV/c:EXPORTSIVAS laufen nicht automatisch mit — CSV/Sivas- Export danach bei Bedarf manuell ueber TEST_EXPORT_ALL (tests/test_export_all.lsp, Menuepunkt "Export CSV/Sivas ALL"), das alle vorhandenen DXF/DWG-Dateien aus tests/output/ einliest und je Datei <basis>_export.csv/<basis>_sivas.csv erzeugt.
  • Automatik-Modus (Ja): Zeichnung wird gespeichert, direkt per c:EXPORTCSV/c:EXPORTSIVAS exportiert (<name>_tests_export.csv/ <name>_tests_sivas.csv) und danach sofort wieder geschlossen. Kompletter Lauf ohne manuellen Zusatzschritt, aber ohne gleichzeitige visuelle Kontrolle aller Zeichnungen am Ende. Sinnvoll fuer reine CI-artige Validierung.

alltests.json — Testregistry

Die Datei tests/alltests.json ist die zentrale Registry aller Test-Module. SSG_RUN_ALL_TESTS liest sie beim Start — die Testliste ist nicht hartcodiert in test_run_all.lsp.

[
  { "name": "kreisel",         "save": "dxf", "module": "KreiselInsert"   },
  { "name": "foerderer",       "save": "dwg", "module": "VarioFoerderer"  },
  { "name": "linienzug",       "save": "dwg", "module": "VarioFoerderer"  },
  { "name": "vfl_schema",                     "module": "VarioFoerderer"  },
  { "name": "omniflo",         "save": "dxf", "module": "OmniModulInsert" },
  { "name": "omniflo_strecke", "save": "dxf", "module": "OmniModulInsert" },
  { "name": "gefaellestrecke", "save": "dwg", "module": "Gefaellestrecke" },
  { "name": "mubea",           "save": "dxf", "module": "KreiselInsert"   },
  { "name": "hundm05",         "save": "dxf", "module": "VarioFoerderer" }
]

Felder pro Eintrag:

Feld Typ Bedeutung
name String Basisname des Testmoduls (Pflicht)
save "dxf" / "dwg" / null Ob und als welches Format die Zeichnung gespeichert wird
module String LISP-Feature-Modul, das vor dem Test per ssg-ensure geladen wird
disabled true (optional) Schaltet den Eintrag ab: SSG_RUN_ALL_TESTS ueberspringt ihn komplett (kein Bauen/Speichern/Export) und gibt nur einen Hinweis auf der Konsole aus. Zum Reaktivieren das Feld entfernen.

JSON-Export laeuft immer — unabhaengig vom save-Feld. Die Datei <name>_results.json wird in tests/output/ geschrieben, sobald der Test abgeschlossen ist.

GUI-Aus waehrend des Laufs: SSG_RUN_ALL_TESTS (und der Einzeltest TEST_LINIENZUG) rufen (ssg-gui-aus) (ssg_core.lsp) auf, damit keine DCL-/Wizard-Dialoge den automatischen Lauf blockieren; danach wird (ssg-gui-an) wieder gesetzt. Bei abgeschalteter GUI fallen die Eingaben auf den Konsolen-/Mock-/Replay-Pfad zurueck. Interaktiver Betrieb (FOERDERANLAGE etc.) ist davon unberuehrt (GUI standardmaessig an).

Wann welches save verwenden:

  • "dxf" — wenn ein Python-Test (ezdxf) die Geometrie der Zeichnung pruefen soll
  • "dwg" — wenn die Zeichnung zur manuellen Kontrolle oder als DWG-Referenz erhalten bleiben soll
  • null (oder Feld weglassen) — wenn nur der JSON-Export benoetigt wird

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). Jede Testzeichnung bleibt als eigener Tab offen (auf den Inhalt gezoomt) und kann direkt visuell inspiziert werden.

  3. Kommandozeile: Ergebnisse validieren:

    • bin\run_tests.bat --check — pytest prueft die Ergebnisse aus output/ gegen Testdefinitionen und Referenzdaten (optional: einzelnes Modul, z.B. --check test_kreisel.py)
    • bin\run_tests.bat --diff_references — vergleicht die CSVs in output/ gegen reference/ (gleicher Dateiname, siehe Abschnitt "Referenz-Namenskonvention") und oeffnet bei Unterschieden das Diff-Tool (meld); optional eine einzelne Datei, z.B. --diff_references kreisel_tests_export.csv
    • Referenz aktualisieren (nach geprueftem Lauf): die betreffende(n) Datei(en) aus output/ unter DEMSELBEN Namen nach reference/ kopieren (es gibt keinen eigenen Schalter dafuer)

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_run_all.lsp         # Fuehrt alle Tests aus: C:SSG_RUN_ALL_TESTS
  test_kreisel.lsp         # LISP-Testrunner: C:TEST_KREISEL
  test_kreisel.py          # pytest-Validierung der Kreisel-Ergebnisse
  test_foerderer.lsp       # LISP-Testrunner: C:TEST_FOERDERER
  test_omniflo.lsp         # LISP-Testrunner: C:TEST_OMNIFLO
  test_omniflo.py          # pytest-Validierung der Omniflo-Ergebnisse
  test_omniflo_strecke.lsp # LISP-Testrunner: C:TEST_OMNIFLO_STRECKE (Streckenzug)
  test_omniflo_strecke.py  # pytest-Validierung des Omniflo-Streckenzugs
  test_export_all.lsp      # LISP-Testrunner: C:TEST_EXPORT_ALL (manuell, nicht in alltests.json)
  test_foerderer.py        # pytest-Validierung Foerderer (Status/Mathematik/CSV/Sivas)
  test_gefaellestrecke.py  # pytest-Validierung Gefaellestrecke
  test_mubea.py            # pytest-Validierung Mubea-Gesamtmodell
  test_hundm05.lsp         # LISP: baut die 5 HundM-Ketten aus ihrer
                           #   Spec (testdata/hundm05.json) - ruft
                           #   vsp-bau-datei, keine eigene Bau-Logik
  test_hundm05.py          # pytest: die so gebaute Anlage pruefen
  test_hm_recformat.lsp    # LISP: dieselben Ketten aus dem ROHEN
                           #   Journal der Kundenzeichnung - der
                           #   Regressionstest fuers Aufzeichnungs-
                           #   format (in alltests.json abgeschaltet,
                           #   baut sonst dieselbe Geometrie zweimal)
  test_hm_recformat.py     # pytest-Validierung dazu
  test_vf_geometrie.py     # pytest: die GEBAUTE Geometrie gegen
                           #   reference/hundm05_attribute.json - Attribute,
                           #   Bausteine, Einfuegepunkt (faengt eine
                           #   vertauschte vfl-acc-*-Reihenfolge)
  test_vf_spec.lsp         # LISP-Unittest: Spec-Uebersetzer (vsp-journal),
                           #   je Glied-Typ + die 5 echten HundM-Ketten
                           #   gegen ihr aufgezeichnetes Journal
  test_vf_spec.py          # pytest: Rundlauf Journal->Spec->Journal, die
                           #   Spec-Testdaten, und die Ergebnisse von
                           #   VF_SPEC_BAU (letztere brauchen BricsCAD)
  test_vf_journal_grammatik.py # pytest ohne CAD: Journal-Dekoder aus
                           #   lib/vf_journal_export.py gegen handgebaute
                           #   Journale (Linie-VF, gewinkelter Erstkoerper)
  test_vf_headless_statisch.py # pytest ohne CAD: statischer Waechter, dass
                           #   im VF-Bau-Pfad kein alert/get*/ssget neu
                           #   auftaucht und der Headless-Riegel an allen
                           #   vfl-in-*-Wrappern sitzt
  test_unit.lsp / .scr     # LISP-Unit-Tests: C:TEST_UNIT (ueber --lisp)
  testdata/
    kreisel_tests.json     # Testfall-Definitionen fuer Kreisel
    omniflo_tests.json     # Testfall-Definitionen fuer Omniflo
    omniflo_strecke_tests.json # Streckenzug: 4 Geraden + 2 Boegen + 1 Weiche (7 Elemente)
    hm_recformat.json      # Aufzeichnung: rohes Journal der 5 Ketten
    hundm05.json           # daraus abgeleitete Spec (wird erweitert)
    foerderer_tests.json / mubea.json / ...
  output/                  # Ergebnisse aus BricsCAD (nicht in Git)
    <name>_results.json    # JSON-Ergebnisse pro Testmodul (immer)
    <name>_tests.dxf/.dwg  # Zeichnung pro Testmodul (gemaess save in alltests.json)
    export_all_results.json    # nur nach manuellem TEST_EXPORT_ALL-Lauf
    <basis>_export.csv         # EXPORTCSV je Quelldatei, nur nach TEST_EXPORT_ALL
    <basis>_sivas.csv          # EXPORTSIVAS je Quelldatei, nur nach TEST_EXPORT_ALL
  reference/               # Abgenommene Referenzdaten (in Git): *_results.json,
    ...                    # *_tests_export.csv / *_tests_sivas.csv, *_tests.dxf,
    ...                    # omniflo_export.csv, export_raw.json

Referenz-Namenskonvention (vereinheitlicht)

Eine Referenz traegt IMMER denselben Dateinamen wie das zugehoerige Ist-Ergebnis in output/. Der einzige Unterschied ist das Verzeichnis:

output/<datei>      # Ist-Ergebnis (bei jedem Lauf neu, nicht in Git)
reference/<datei>   # abgenommener Soll-Stand (identischer Name, in Git)

Damit gilt durchgehend: Referenz festlegen = Datei aus output/ nach reference/ kopieren - kein Umbenennen, kein Suffix. Beispiele:

Ist-Ergebnis in output/ Referenz in reference/
kreisel_tests.dxf kreisel_tests.dxf
kreisel_tests_export.csv kreisel_tests_export.csv
foerderer_results.json foerderer_results.json
omniflo_export.csv omniflo_export.csv
copy tests\output\kreisel_tests.dxf tests\reference\kreisel_tests.dxf

Frueher gab es zwei Ausreisser, die bewusst auf dieses Schema gezogen wurden (nicht mehr verwenden):

  • reference/kreisel_ref.dxf (bzw. der Tippfehler Kresel_ref.dxf) -> jetzt reference/kreisel_tests.dxf
  • reference/omniflo_export_reference.csv -> jetzt reference/omniflo_export.csv

Die pytest-Fixtures und -Checks suchen ausschliesslich nach dem vereinheitlichten Namen; fehlt die Referenz, wird der Vergleich mit einem Hinweis uebersprungen (kein Fehler).

Workflow

1. LISP-Tests in BricsCAD ausfuehren

BricsCAD starten (ueber bin\start_briscad.bat) und Module laden:

(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp"))

Dann alle Tests auf einmal ausfuehren:

;; Alle Tests ausfuehren (empfohlen)
(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp"))
SSG_RUN_ALL_TESTS

SSG_RUN_ALL_TESTS liest die Testliste aus tests/alltests.json und fuehrt fuer jedes Modul aus:

  1. Zeichnung leeren (ERASE ALL + PURGE x5) — saubere Basis fuer jeden Test
  2. test_<name>.lsp laden und TEST_<NAME> ausfuehren
  3. JSON-Export aufrufen: <name>:export-results — immer, unabhaengig von save
  4. Zeichnung speichern — nur wenn "save" in alltests.json gesetzt ist ("dxf" oder "dwg")
  5. Bei Fehler: weiter mit naechstem Test (vl-catch-all-apply)

Einzeltest (z.B. nur Kreisel pruefen):

;; Test-Datei laden und Befehl ausfuehren
(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp"))
TEST_KREISEL
;; JSON-Export manuell aufrufen:
(kreisel:export-results (strcat (getenv "DXFMAKRO") "/tests/output"))

Unterschied SSG_RUN_ALL_TESTS vs. Einzeltest:

SSG_RUN_ALL_TESTS Einzeltest
Testliste aus alltests.json manuell gewaehlter Test
Zeichnung leeren automatisch vor jedem Test nein (Zeichnung bleibt)
JSON-Export automatisch nach jedem Test manuell aufrufen
DXF/DWG speichern gemaess save in alltests.json manuell (SAVEAS / DXFOUT)
Fehlerisolation ja (Fehler unterbricht nicht weitere Tests) nein

2. Python-Validierung ausfuehren

bin\run_tests.bat --check

Oder fuer ein einzelnes Testmodul:

bin\run_tests.bat --check 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 ueber lib/export_csv.py (Omniflo: Spalten, Merkmale, Sum-Zeile, Datentypen)

Tests, deren Eingabedaten fehlen (z.B. kein BricsCAD-Lauf), werden automatisch uebersprungen (pytest.skip).

3. Referenz erstellen/aktualisieren

Nach einem erfolgreichen, geprueften Testlauf die betreffende(n) Ergebnisdatei(en) manuell aus output/ unter DEMSELBEN Dateinamen nach reference/ kopieren (nur bei bestandenen Tests, siehe Abschnitt "Referenz-Namenskonvention"). Es gibt keinen eigenen Batch-Schalter dafuer.

copy tests\output\<datei> tests\reference\<datei>

Beispiel (Kreisel-DXF und Omniflo-CSV als Referenz festlegen):

copy tests\output\kreisel_tests.dxf tests\reference\kreisel_tests.dxf
copy tests\output\omniflo_export.csv tests\reference\omniflo_export.csv

Zum Vergleich der aktuellen CSVs gegen die Referenz (mit Diff-Tool meld):

bin\run_tests.bat --diff_references

Neuen Test erstellen

Schritt 1: Testdaten definieren (JSON)

Neue Testfaelle in testdata/<modul>_tests.json eintragen. Das Format ist ein flaches JSON-Array (kompatibel mit omni:load-json).

Kreisel-Beispiel (kreisel_tests.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):

[
  {
    "sivasnr": "834372001",
    "type": "bogen",
    "description": "Bogen 90 Grad R200",
    "hoehe": 2000,
    "drehung": 0
  }
]

Foerderer-Beispiel (foerderer_tests.json):

[
  { "y_abstand": 800 },
  {
    "test_id": "VF_Auf_2000_Rechts",
    "richtung": "Auf",
    "deltaL": 7000,
    "deltaH": 2000,
    "seite": "rechts",
    "winkel": 27,
    "gf_verteilung": "vorne"
  }
]

Felder:

  • test_id — Eindeutiger Name des Testfalls
  • richtung — "Auf" oder "Ab"
  • deltaL, deltaH — Horizontal-/Hoehendistanz in mm
  • seite (optional, Default "links") — "links" oder "rechts", steuert AS-/ES-Seite (SEITE_AS/SEITE_ES-Attribut)
  • winkel (optional) — erzwingt einen bestimmten Kandidatenwinkel statt des automatisch gewaehlten kleinsten gueltigen Winkels; muss ein gueltiger Wert aus der bogen_winkel-Kandidatenliste sein, sonst wird der Testfall NICHT_GEBAUT
  • gf_verteilung (optional, Default "gleichmaessig") — "gleichmaessig" (50/50 auf Einlauf/Auslauf), "vorne" (alles am Einlauf) oder "hinten" (alles am Auslauf)

Schritt 2: LISP-Testrunner erweitern (falls neues Modul)

Fuer ein neues Modul eine neue .lsp-Datei erstellen nach dem Muster:

;; test_<modul>.lsp
;; Konvention: Basisname <modul> bestimmt Befehl, DXF und Export-Funktion

;; Export-Funktion (wird von test_run_all.lsp aufgerufen)
(defun <modul>:export-results (tests-out-dir / out-json f first)
  (if (null *<modul>-test-results*)
    (princ "\n  Keine <modul>-Ergebnisse vorhanden.")
    (progn
      (vl-mkdir tests-out-dir)
      (setq out-json (strcat tests-out-dir "/<modul>_results.json"))
      ;; ... JSON-Array schreiben ...
    )
  )
)

(defun c:TEST_<MODUL> (/ ...)
  (ssg-start "TEST_<MODUL>" '(("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/<modul>_tests.json")))

  ;; 2. Testfaelle ausfuehren, Ergebnisse sammeln
  (foreach eintrag testfaelle
    ;; ... Script-Funktion aufrufen, Ergebnis pruefen ...
  )

  ;; 3. Ergebnisse in globaler Variable speichern
  (setq *<modul>-test-results* (reverse results-list))

  (ssg-end)
)

Dann den Basisnamen in tests/alltests.json eintragen:

{ "name": "<modul>", "save": "dxf" }

"save" waehlen je nach Bedarf ("dxf", "dwg" oder null). test_run_all.lsp leitet alle Namen aus dem "name"-Feld ab — nichts in test_run_all.lsp aendern.

Namenskonventionen (werden von test_run_all.lsp automatisch abgeleitet)

Aus dem Basisnamen <name> in alltests.json entstehen durch Konvention:

Element Schema Beispiel fuer "name": "kreisel"
LISP-Datei tests/test_<name>.lsp tests/test_kreisel.lsp
BricsCAD-Befehl TEST_<NAME> (Grossbuchstaben) TEST_KREISEL
Export-Funktion <name>:export-results kreisel:export-results
JSON-Ergebnis output/<name>_results.json output/kreisel_results.json
DXF/DWG-Datei output/<name>_tests.dxf/.dwg output/kreisel_tests.dxf
Referenz (Soll) reference/<gleicher Name wie output> reference/kreisel_tests.dxf

Die Export-Funktion muss exakt so heissen: <name>:export-results (Namespace-Notation mit Doppelpunkt). Sie nimmt genau einen Parameter entgegen: den Pfad zum Output-Verzeichnis.

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_<modul>.py erstellen:

import pytest

class TestModulAttributes:
    """Prueft Attribute gegen Testdefinitionen."""

    def test_all_executed(self, <modul>_results):
        """Alle Testfaelle muessen ausgefuehrt worden sein."""
        # ...

    def test_attribute_values(self, <modul>_testdata, <modul>_results):
        """Attributwerte muessen mit Erwartungen uebereinstimmen."""
        # ...

class TestModulGeometry:
    """Prueft DXF-Geometrie mit ezdxf."""

    def test_blocks_exist(self, <modul>_dxf):
        """Bloecke muessen im Modelspace vorhanden sein."""
        # ...

class TestModulReference:
    """Vergleicht gegen Referenz."""

    def test_matches_reference(self, <modul>_dxf, <modul>_ref_dxf):
        # ...

Schritt 4: Fixtures in conftest.py ergaenzen

Neue Fixtures fuer Testdaten, Ergebnisse und DXF in conftest.py hinzufuegen:

@pytest.fixture
def <modul>_testdata():
    path = os.path.join(_testdata_dir(), "<modul>_tests.json")
    return _load_json(path)

@pytest.fixture
def <modul>_results():
    path = os.path.join(_output_dir(), "<modul>_results.json")
    if not os.path.exists(path):
        pytest.skip("<modul>_results.json nicht vorhanden")
    return _load_json(path)

@pytest.fixture
def <modul>_dxf():
    path = os.path.join(_output_dir(), "<modul>_tests.dxf")
    if not os.path.exists(path):
        pytest.skip("<modul>_tests.dxf nicht vorhanden")
    return ezdxf.readfile(path)

@pytest.fixture
def <modul>_ref_dxf():
    # Konvention: Referenz = GLEICHER Dateiname wie das Ist-Ergebnis in output/.
    path = os.path.join(_reference_dir(), "<modul>_tests.dxf")
    if not os.path.exists(path):
        pytest.skip("reference/<modul>_tests.dxf nicht vorhanden - Referenz noch "
                    "nicht festgelegt (output/<modul>_tests.dxf nach reference/ kopieren)")
    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 ueber lib/export_csv.py: Merkmale, Datentypen, Sum-Zeile, Vollstaendigkeit (ohne BricsCAD)
TestOmnifloResults omniflo_results.json aus BricsCAD: Testfaelle vollstaendig, Status OK, Hoehe
TestOmnifloReferenceCSV CSV-Export aus lib/export_csv.py gegen abgenommene Referenz-CSV

test_omniflo_strecke.py

Streckenzug 4 Geraden -> 180-Grad-Kurve (4x 45-Grad-Bogen) -> 4 Geraden. Die Geometrie wird ohne BricsCAD direkt aus omniflo_strecke_tests.json geprueft.

Klasse Prueft
TestStreckeStruktur 4+4+4 = 12 Elemente, Reihenfolge der Gruppen, Typen
TestStreckeKatalog Bogen-SivasNummern existieren in omniflo_boegen.json (Radius/Winkel)
TestStreckeGeometrie Lueckenlose Verkettung, Kurvensumme 180 Grad, gemeinsamer Bogen-Mittelpunkt
TestStreckeResults omniflo_strecke_results.json aus BricsCAD: Elemente vollstaendig, Status OK

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