This commit is contained in:
2026-07-03 13:05:20 +02:00
36 changed files with 1422 additions and 2417689 deletions
+41 -18
View File
@@ -16,8 +16,8 @@ BricsCAD Kommandozeile
| SSG_RUN_ALL_TESTS |
| (TEST_KREISEL, |
| TEST_FOERDERER, |
| TEST_KSEINAUS, |
| TEST_OMNIFLO) |
| TEST_OMNIFLO, |
| TEST_GEFAELLESTRECKE) |
| | |
v v |
tests/output/ |
@@ -25,11 +25,10 @@ tests/output/ |
kreisel_tests.dxf (save: dxf) |
foerderer_results.json (immer) |
foerderer_tests.dwg (save: dwg) |
kseinaus_results.json (immer) |
(keine Zeichnung) (save: null) |
omniflo_results.json (immer) |
omniflo_tests.dxf (save: dxf) |
omniflo_export.csv |
gefaellestrecke_results.json |
gefaellestrecke_tests.dwg |
|
bin\run_tests.bat --runall
|
@@ -37,8 +36,29 @@ tests/output/ |
|
test_kreisel.py
test_omniflo.py
test_foerderer.py
```
**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.
@@ -46,10 +66,10 @@ Die Datei `tests/alltests.json` ist die zentrale Registry aller Test-Module.
```json
[
{ "name": "kreisel", "save": "dxf" },
{ "name": "foerderer", "save": "dwg" },
{ "name": "kseinaus", "save": null },
{ "name": "omniflo", "save": "dxf" }
{ "name": "kreisel", "save": "dxf" },
{ "name": "foerderer", "save": "dwg" },
{ "name": "omniflo", "save": "dxf" },
{ "name": "gefaellestrecke", "save": "dwg" }
]
```
@@ -73,7 +93,7 @@ wird in `tests/output/` geschrieben, sobald der Test abgeschlossen ist.
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.
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 oder als neue Referenz speichern:
- `bin\run_tests.bat --runall` — pytest prueft die Ergebnisse aus `output/` gegen Testdefinitionen und Referenzdaten
@@ -90,9 +110,9 @@ 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_kseinaus.lsp # LISP-Testrunner: C:TEST_KSEINAUS
test_omniflo.lsp # LISP-Testrunner: C:TEST_OMNIFLO
test_omniflo.py # pytest-Validierung der Omniflo-Ergebnisse
test_export_all.lsp # LISP-Testrunner: C:TEST_EXPORT_ALL (manuell, nicht in alltests.json)
testdata/
kreisel_tests.json # Testfall-Definitionen fuer Kreisel
omniflo_tests.json # Testfall-Definitionen fuer Omniflo
@@ -100,12 +120,14 @@ tests/
kreisel_results.json # JSON-Ergebnisse pro Testmodul
kreisel_tests.dxf # DXF-Zeichnung pro Testmodul
foerderer_results.json
foerderer_tests.dxf
kseinaus_results.json
kseinaus_tests.dxf
foerderer_tests.dwg
omniflo_results.json
omniflo_tests.dxf
omniflo_export.csv # CSV-Export (Omniflo-spezifisch)
gefaellestrecke_results.json
gefaellestrecke_tests.dwg
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)
kreisel_ref.dxf
...
@@ -173,7 +195,7 @@ 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)
- **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`).
@@ -381,8 +403,9 @@ def <modul>_ref_dxf():
| Klasse | Prueft |
|---|---|
| `TestOmnifloExportUnit` | Mock-Export: Merkmale, Datentypen, Vollstaendigkeit (ohne BricsCAD) |
| `TestOmnifloExportCSV` | CSV aus BricsCAD: Header, Spalten, JSON-Merkmale |
| `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 |
## Umgebungsvariablen
+1 -2
View File
@@ -1,7 +1,6 @@
[
{ "name": "kreisel", "save": "dxf", "module": "KreiselInsert" },
{ "name": "foerderer", "save": "dwg", "module": "VarioFoerderer" },
{ "name": "kseinaus", "save": null, "module": "VarioFoerderer" },
{ "name": "omniflo", "save": "dxf", "module": "OmniModulInsert" },
{ "name": "gefaellestrecke", "save": "dxf", "module": "Gefaellestrecke" }
{ "name": "gefaellestrecke", "save": "dwg", "module": "Gefaellestrecke" }
]
+51 -17
View File
@@ -32,8 +32,18 @@ def _reference_dir():
def _load_json(path):
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
"""Laedt JSON, tolerant gegenueber BricsCAD-Ausgaben.
AutoLISP schreibt Dateien (write-line) im ANSI-Codepage des Systems,
nicht in UTF-8 - Sonderzeichen (z.B. Grad-Zeichen in Beschreibungen)
koennen daher nicht als UTF-8 dekodierbar sein. Fallback auf cp1252.
"""
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except UnicodeDecodeError:
with open(path, "r", encoding="cp1252") as f:
return json.load(f)
# --- Foerderer Fixtures ---
@@ -68,22 +78,15 @@ def omniflo_testdata():
@pytest.fixture
def omniflo_csv():
"""Laedt den Inhalt der omniflo_export.csv aus output/."""
import csv as _csv
path = os.path.join(_output_dir(), "omniflo_export.csv")
def omniflo_results():
"""Laedt die Omniflo-Ergebnisse aus output/omniflo_results.json."""
path = os.path.join(_output_dir(), "omniflo_results.json")
if not os.path.exists(path):
pytest.skip(
"omniflo_export.csv nicht vorhanden - "
"TEST_OMNIFLO_EXPORT in BricsCAD ausfuehren"
)
rows = []
with open(path, "r", encoding="utf-8") as f:
reader = _csv.reader(f, delimiter=";")
header = next(reader)
for row in reader:
rows.append(row)
return {"header": header, "rows": rows}
pytest.skip("omniflo_results.json nicht vorhanden - TEST_OMNIFLO in BricsCAD ausfuehren")
data = _load_json(path)
if not data:
pytest.skip("omniflo_results.json ist leer")
return data
# --- Kreisel Fixtures ---
@@ -123,3 +126,34 @@ def kreisel_ref_dxf():
if not os.path.exists(path):
pytest.skip("kreisel_ref.dxf nicht vorhanden - Referenz noch nicht erstellt")
return ezdxf.readfile(path)
# --- Gefaellestrecke Fixtures ---
@pytest.fixture
def gefaellestrecke_testdata():
"""Laedt die Gefaellestrecke-Testdefinitionen aus testdata/gefaellestrecke_tests.json."""
path = os.path.join(_testdata_dir(), "gefaellestrecke_tests.json")
data = _load_json(path)
return [t for t in data if "test_id" in t]
@pytest.fixture
def gefaellestrecke_results():
"""Laedt die Gefaellestrecke-Ergebnisse aus output/gefaellestrecke_results.json."""
path = os.path.join(_output_dir(), "gefaellestrecke_results.json")
if not os.path.exists(path):
pytest.skip("gefaellestrecke_results.json nicht vorhanden - TEST_GEFAELLESTRECKE in BricsCAD ausfuehren")
data = _load_json(path)
if not data:
pytest.skip("gefaellestrecke_results.json ist leer")
return data
@pytest.fixture
def gefaellestrecke_dxf():
"""Laedt die erzeugte Gefaellestrecke-DXF aus output/gefaellestrecke_tests.dxf."""
path = os.path.join(_output_dir(), "gefaellestrecke_tests.dxf")
if not os.path.exists(path):
pytest.skip("gefaellestrecke_tests.dxf nicht vorhanden - TESTRUN in BricsCAD ausfuehren")
return ezdxf.readfile(path)
@@ -106,3 +106,4 @@ Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale
105;"Omniflo Weiche";"0000";"OFWeiche :6";1;{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372404+0_BG071090"}
106;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Deltaweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372401"}
107;"Omniflo Weiche";"0000";"OFWeiche :1";1;{"Weichentyp": "Sternweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372420"}
108;"Omniflo Sum";"autogenerated_of_json";"Omniflo sum";1;{"Anzahl Bögen": 27, "Anzahl Weichengrundkörper": 0, "Anzahl Einwegweichen": 30, "Anzahl Deltaweichen": 7, "Anzahl Doppelweichen und Dreiwegeweichen": 42, "Anzahl Sternweichen": 1, "Gesamtlänge AP110": 0.0, "Gesamtlänge AP60": 0.0}
Can't render this file because it contains an unexpected character in line 2 and column 42.
+197
View File
@@ -0,0 +1,197 @@
;; ============================================================
;; test_export_all.lsp - Batch-Export aller Testzeichnungen
;;
;; Oeffnet jede vorhandene DXF/DWG-Datei aus tests/output/ und fuehrt
;; darauf c:EXPORTCSV und c:EXPORTSIVAS aus (Lisp/export.lsp).
;;
;; Muss als LETZTES Modul in tests/alltests.json stehen: Es liest
;; die Ausgabedateien aller anderen Testmodule, die zu diesem
;; Zeitpunkt bereits geschrieben sein muessen.
;;
;; Ausgabe je Quelldatei <basis>.dxf/.dwg:
;; tests/output/<basis>_export.csv
;; tests/output/<basis>_sivas.csv
;; tests/output/export_all_results.json (Zusammenfassung, immer)
;;
;; Voraussetzungen:
;; - SSG_LIB geladen (export.lsp, ssg_core.lsp)
;; - Umgebungsvariable DXFMAKRO gesetzt
;;
;; Aufruf in BricsCAD:
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_export_all.lsp"))
;; TEST_EXPORT_ALL
;; ============================================================
(vl-load-com)
;; --- Auf Fertigstellung einer asynchron geschriebenen Datei warten ---
;; csv:run-export startet Python per startapp (fire-and-forget). Pollt
;; bis die Datei existiert und ihre Groesse ueber ein Intervall stabil
;; bleibt, oder bis timeout-sec erreicht ist. Rueckgabe: T bei Erfolg.
(defun export_all:wait-for-file (path timeout-sec / elapsed size1 size2 done)
(setq elapsed 0.0 done nil)
(while (and (not done) (< elapsed timeout-sec))
(if (findfile path)
(progn
(setq size1 (vl-file-size path))
(command "_.DELAY" 400)
(setq size2 (vl-file-size path))
(if (and size1 size2 (= size1 size2) (> size1 0))
(setq done T)
)
)
(command "_.DELAY" 400)
)
(setq elapsed (+ elapsed 0.4))
)
done
)
;; --- Zeichnung zusaetzlich oeffnen, ohne die aktuelle zu schliessen ---
;; Nutzt reines ActiveX Documents.Open statt (command "_.OPEN" ...):
;; Damit entfaellt sowohl die interaktive "Speichern?"-Abfrage als auch
;; das vorherige Schliessen des aktiven Dokuments. Letzteres fuehrte dazu,
;; dass BricsCAD (weil kein Dokument mehr offen war) automatisch ein neues
;; Blank-Dokument erzeugt und dabei den kompletten Modul-/Menue-Ladezyklus
;; (inkl. Fremd-Addons) erneut durchlaeuft - pro verarbeiteter Datei.
(defun export_all:open-drawing (filepath / app doc)
(setq app (vlax-get-acad-object))
(setq doc (vla-open (vla-get-documents app) filepath))
(vla-put-activedocument app doc)
doc
)
;; --- Basisname (ohne Dateiendung) aus einem Dateinamen extrahieren ---
(defun export_all:basisname (dateiname / i punkt-pos)
(setq i 0 punkt-pos nil)
(while (setq i (vl-string-search "." dateiname i))
(setq punkt-pos i)
(setq i (1+ i))
)
(if punkt-pos (substr dateiname 1 punkt-pos) dateiname)
)
;; --- Ergebnis eines Datei-Exports als JSON-String erzeugen ---
(defun export_all:result-json (basis csv-ok sivas-ok / json)
(strcat " {\n"
" \"quelldatei\": \"" basis "\",\n"
" \"csv_ok\": " (if csv-ok "true" "false") ",\n"
" \"sivas_ok\": " (if sivas-ok "true" "false") "\n"
" }")
)
;; --- JSON-Export der Ergebnisse ---
(defun export_all:export-results (tests-out-dir / out-json f first)
(if (null *export-all-results*)
(princ "\n Keine Export-All-Ergebnisse vorhanden.")
(progn
(vl-mkdir tests-out-dir)
(setq out-json (strcat tests-out-dir "/export_all_results.json"))
(setq f (open out-json "w"))
(if f
(progn
(write-line "[" f)
(setq first T)
(foreach r *export-all-results*
(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!"))
)
)
)
)
;; ============================================================
;; C:TEST_EXPORT_ALL
;;
;; Oeffnet jede DXF/DWG-Datei aus tests/output/ und exportiert sie
;; per EXPORTCSV/EXPORTSIVAS in eigene, nach der Quelldatei benannte
;; CSV-Dateien.
;; ============================================================
(defun c:TEST_EXPORT_ALL (/ tests-out-dir dateien datei basis doc
csv-name sivas-name csv-pfad sivas-pfad
csv-ok sivas-ok results-list old-filenames)
(setq tests-out-dir (strcat (getenv "DXFMAKRO") "/tests/output"))
(vl-mkdir tests-out-dir)
(setenv "DXFM_RESULTS" tests-out-dir)
(setq dateien (append
(vl-directory-files tests-out-dir "*.dxf" 1)
(vl-directory-files tests-out-dir "*.dwg" 1)
))
(setq old-filenames *export-filenames*)
(setq results-list nil)
(princ "\n================================================================")
(princ "\n TEST_EXPORT_ALL")
(princ (strcat "\n " (itoa (length dateien)) " Zeichnung(en) gefunden"))
(princ "\n================================================================")
(foreach datei dateien
(setq basis (export_all:basisname datei))
(princ (strcat "\n\n>>> " datei " <<<"))
(setq doc (export_all:open-drawing (strcat tests-out-dir "/" datei)))
;; Datei-/Skriptnamen fuer diesen Durchlauf ueberschreiben, damit
;; jede Quelldatei ihre eigenen CSV-Ergebnisse bekommt (statt der
;; fixen Standardnamen "export.csv"/"export_sivas.csv").
(setq csv-name (strcat basis "_export.csv"))
(setq sivas-name (strcat basis "_sivas.csv"))
(setq csv-pfad (strcat tests-out-dir "/" csv-name))
(setq sivas-pfad (strcat tests-out-dir "/" sivas-name))
(if (findfile csv-pfad) (vl-file-delete csv-pfad))
(if (findfile sivas-pfad) (vl-file-delete sivas-pfad))
(setq *export-filenames*
(list
(cons "raw_json_datei" (cdr (assoc "raw_json_datei" old-filenames)))
(cons "sivas_script" (cdr (assoc "sivas_script" old-filenames)))
(cons "sivas_csv" sivas-name)
(cons "csv_script" (cdr (assoc "csv_script" old-filenames)))
(cons "csv_csv" csv-name)
)
)
(princ (strcat "\n[TEST_EXPORT_ALL] CSV-Export -> " csv-name))
(c:EXPORTCSV)
(setq csv-ok (export_all:wait-for-file csv-pfad 30.0))
(princ (if csv-ok "\n[TEST_EXPORT_ALL] CSV OK" "\n[TEST_EXPORT_ALL] CSV TIMEOUT/FEHLER"))
(princ (strcat "\n[TEST_EXPORT_ALL] Sivas-Export -> " sivas-name))
(c:EXPORTSIVAS)
(setq sivas-ok (export_all:wait-for-file sivas-pfad 30.0))
(princ (if sivas-ok "\n[TEST_EXPORT_ALL] Sivas OK" "\n[TEST_EXPORT_ALL] Sivas TIMEOUT/FEHLER"))
(setq results-list (cons
(export_all:result-json basis csv-ok sivas-ok)
results-list))
;; Diese Zeichnung wieder schliessen (verwirft ID/Hoehe/Drehung-Updates
;; aus dem Export). Das urspruengliche Dokument (vor dieser Schleife
;; aktiv) bleibt dabei durchgehend offen, BricsCAD erzeugt also kein
;; neues Blank-Dokument und der teure Modul-/Menue-Reload entfaellt.
(vla-close doc :vlax-false)
)
(setq *export-filenames* old-filenames)
(setq *export-all-results* (reverse results-list))
(princ "\n\n================================================================")
(princ "\n TEST_EXPORT_ALL abgeschlossen.")
(princ "\n================================================================")
(princ)
)
+15 -17
View File
@@ -75,7 +75,7 @@
y-offset y-abstand idx
anz-gebaut anz-nicht-gebaut results-list
startpunkt vf-nummer hoehe-von hoehe-bis lastEnt
tests-out-dir old-dxfm-results)
sub-ent sub-typ)
;; Bibliothek initialisieren (laedt Block-Library und extrahiert Masse)
(if (not *lib-initialized*)
@@ -103,7 +103,7 @@
;; Konfiguration aus erstem Eintrag (ohne test_id)
(setq cfg (car testdaten))
(setq y-abstand (ssg-val cfg "y_abstand"))
(if (or (null y-abstand) (= y-abstand 0)) (setq y-abstand 400))
(if (or (null y-abstand) (= y-abstand 0)) (setq y-abstand 800))
;; Nur Eintraege mit test_id sind Testfaelle
(setq tests
@@ -175,6 +175,19 @@
(/ L_GF 2.0) (/ L_GF 2.0)
richtung best-winkel startpunkt lastEnt 0.0)
;; lastEnt hinter den SEQEND des VF-Blocks schieben.
;; Ohne diesen Schritt wuerde entnext vom INSERT-Entity
;; in die ATTRIB-Kette des gerade erstellten VF-Blocks
;; springen und diese beim naechsten _.-BLOCK-Aufruf
;; in den neuen Block verschieben (Datenverlust).
(setq lastEnt (entlast))
(setq sub-ent (entnext lastEnt))
(while (and sub-ent
(not (equal (cdr (assoc 0 (entget sub-ent))) "SEQEND")))
(setq lastEnt sub-ent)
(setq sub-ent (entnext lastEnt)))
(if sub-ent (setq lastEnt sub-ent))
(setq results-list (cons
(foerderer:test-result-json test-id richtung deltaL deltaH
"GEBAUT" best-winkel L_GF L_VF)
@@ -205,21 +218,6 @@
;; Ergebnisse in globaler Variable speichern
(setq *foerderer-test-results* (reverse results-list))
;; CSV- und Sivas-Export nach tests/output/
(setq tests-out-dir (strcat (getenv "DXFMAKRO") "/tests/output"))
(vl-mkdir tests-out-dir)
(setq old-dxfm-results (getenv "DXFM_RESULTS"))
(setenv "DXFM_RESULTS" tests-out-dir)
(princ "\n================================================================")
(princ "\n[TEST_FOERDERER] CSV-Export -> foerderer_export.csv")
(csv:run-export "FOERDERER_CSV" "export_csv.py" "foerderer_export.csv")
(princ "\n[TEST_FOERDERER] Sivas-Export -> foerderer_sivas.csv")
(csv:run-export "FOERDERER_SIVAS" "export_sivas.py" "foerderer_sivas.csv")
(setenv "DXFM_RESULTS" (if old-dxfm-results old-dxfm-results ""))
(ssg-end)
(princ "\n================================================================")
(princ "\n TEST_FOERDERER abgeschlossen.")
+14 -14
View File
@@ -7,8 +7,8 @@ Prueft:
1. Status-Werte und Vollstaendigkeit (foerderer_results.json)
2. Mathematische Invarianten (Laengen, Winkel, Richtung)
3. Geometrisch unmoegliche Faelle
4. CSV-Export-Struktur (foerderer_export.csv, falls vorhanden)
5. Sivas-Export-Struktur (foerderer_sivas.csv, falls vorhanden)
4. CSV-Export-Struktur (foerderer_tests_export.csv, aus TEST_EXPORT_ALL)
5. Sivas-Export-Struktur (foerderer_tests_sivas.csv, aus TEST_EXPORT_ALL)
"""
import csv
@@ -179,19 +179,19 @@ class TestFoerdererMathematik:
# ---------------------------------------------------------------------------
# Klasse 3: CSV-Export-Pruefung (foerderer_export.csv)
# Klasse 3: CSV-Export-Pruefung (foerderer_tests_export.csv)
# ---------------------------------------------------------------------------
class TestFoerdererExportCSV:
"""Prueft den CSV-Export aus BricsCAD (foerderer_export.csv)."""
"""Prueft den CSV-Export aus BricsCAD (foerderer_tests_export.csv, aus TEST_EXPORT_ALL)."""
@pytest.fixture(autouse=True)
def setup(self):
csv_path = os.path.join(_output_dir(), "foerderer_export.csv")
csv_path = os.path.join(_output_dir(), "foerderer_tests_export.csv")
if not os.path.exists(csv_path):
pytest.skip(
"foerderer_export.csv nicht vorhanden - "
"TEST_FOERDERER in BricsCAD ausfuehren (exportiert automatisch)"
"foerderer_tests_export.csv nicht vorhanden - "
"TEST_FOERDERER und anschliessend TEST_EXPORT_ALL in BricsCAD ausfuehren"
)
self.rows = []
with open(csv_path, "r", encoding="utf-8") as f:
@@ -211,7 +211,7 @@ class TestFoerdererExportCSV:
def test_hat_eintraege(self):
"""CSV muss mindestens einen Dateneintrag enthalten."""
assert len(self.rows) > 0, "foerderer_export.csv enthaelt keine Daten"
assert len(self.rows) > 0, "foerderer_tests_export.csv enthaelt keine Daten"
def test_vario_teileart(self):
"""Alle Eintraege muessen TeileArt 'VarioFoerderer' haben."""
@@ -265,19 +265,19 @@ class TestFoerdererExportCSV:
# ---------------------------------------------------------------------------
# Klasse 4: Sivas-Export-Pruefung (foerderer_sivas.csv)
# Klasse 4: Sivas-Export-Pruefung (foerderer_tests_sivas.csv)
# ---------------------------------------------------------------------------
class TestFoerdererExportSivas:
"""Prueft den Sivas-Export aus BricsCAD (foerderer_sivas.csv)."""
"""Prueft den Sivas-Export aus BricsCAD (foerderer_tests_sivas.csv, aus TEST_EXPORT_ALL)."""
@pytest.fixture(autouse=True)
def setup(self):
csv_path = os.path.join(_output_dir(), "foerderer_sivas.csv")
csv_path = os.path.join(_output_dir(), "foerderer_tests_sivas.csv")
if not os.path.exists(csv_path):
pytest.skip(
"foerderer_sivas.csv nicht vorhanden - "
"TEST_FOERDERER in BricsCAD ausfuehren (exportiert automatisch)"
"foerderer_tests_sivas.csv nicht vorhanden - "
"TEST_FOERDERER und anschliessend TEST_EXPORT_ALL in BricsCAD ausfuehren"
)
self.rows = []
with open(csv_path, "r", encoding="utf-8") as f:
@@ -297,7 +297,7 @@ class TestFoerdererExportSivas:
def test_hat_eintraege(self):
"""Sivas-CSV muss mindestens einen Dateneintrag enthalten."""
assert len(self.rows) > 0, "foerderer_sivas.csv enthaelt keine Daten"
assert len(self.rows) > 0, "foerderer_tests_sivas.csv enthaelt keine Daten"
def test_strecke_zeile_vorhanden(self):
"""Eine Zeile mit TeileArt 'ILS 2.0 Strecke - Module' muss vorhanden sein."""
+216
View File
@@ -0,0 +1,216 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
test_gefaellestrecke.py - Validiert GEFAELLESTRECKE Testergebnisse.
Prueft:
1. Status-Werte und Vollstaendigkeit (gefaellestrecke_results.json)
2. Mathematische Invarianten (Hoehen, Winkel, deltaH)
3. Konsistenz zwischen den Modi (Modus 1 Richtungsunabhaengigkeit,
Modus 3 uebernimmt deltaH/deltaL aus Modus 2)
"""
import json
import os
import pytest
# ---------------------------------------------------------------------------
# Hilfsfunktionen
# ---------------------------------------------------------------------------
def _testdata_dir():
return os.getenv("DXFM_TESTDATA",
os.path.join(os.path.dirname(os.path.abspath(__file__)), "testdata"))
def _output_dir():
return os.getenv("DXFM_TESTOUT",
os.path.join(os.path.dirname(os.path.abspath(__file__)), "output"))
def _load_json(path):
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
def _load_gefaellestrecke_results():
path = os.path.join(_output_dir(), "gefaellestrecke_results.json")
if not os.path.exists(path):
pytest.skip(
"gefaellestrecke_results.json nicht vorhanden - "
"TEST_GEFAELLESTRECKE in BricsCAD ausfuehren"
)
data = _load_json(path)
if not data:
pytest.skip("gefaellestrecke_results.json ist leer")
return data
def _load_gefaellestrecke_testdata():
path = os.path.join(_testdata_dir(), "gefaellestrecke_tests.json")
return _load_json(path)
# ---------------------------------------------------------------------------
# Klasse 1: Status und Vollstaendigkeit
# ---------------------------------------------------------------------------
class TestGefaellestreckeStatus:
"""Prueft Status-Werte und Vollstaendigkeit der Ergebnisse."""
@pytest.fixture(autouse=True)
def setup(self):
self.results = _load_gefaellestrecke_results()
testdata = _load_gefaellestrecke_testdata()
self.tests = [t for t in testdata if "test_id" in t]
self.results_by_id = {r["test_id"]: r for r in self.results}
def test_alle_testfaelle_vorhanden(self):
"""Alle Testfaelle muessen in den Ergebnissen vorhanden sein."""
expected_ids = {t["test_id"] for t in self.tests}
result_ids = {r["test_id"] for r in self.results}
missing = expected_ids - result_ids
assert not missing, f"Fehlende Testfaelle in Ergebnissen: {missing}"
def test_status_werte_gueltig(self):
"""Status muss GEBAUT oder FEHLER (bzw. FEHLER_LINIE) sein."""
gueltige_status = {"GEBAUT", "FEHLER", "FEHLER_LINIE"}
for r in self.results:
assert r["status"] in gueltige_status, (
f'{r["test_id"]}: Unbekannter Status "{r["status"]}"'
)
def test_alle_modus1_gebaut(self):
"""Alle vier Modus-1-Richtungen (hz=0/90/180/270) muessen GEBAUT sein."""
modus1 = [r for r in self.results if r["modus"] == 1]
assert len(modus1) == 4, f"Erwartet 4 Modus-1-Testfaelle, gefunden {len(modus1)}"
for r in modus1:
assert r["status"] == "GEBAUT", (
f'{r["test_id"]}: erwartet GEBAUT, ist "{r["status"]}"'
)
def test_modus2_und_modus3_gebaut(self):
"""Modus 2 und Modus 3 muessen GEBAUT sein."""
for test_id in ("M2_hz000", "M3_hz270"):
r = self.results_by_id.get(test_id)
assert r is not None, f"{test_id} fehlt in den Ergebnissen"
assert r["status"] == "GEBAUT", (
f'{test_id}: erwartet GEBAUT, ist "{r["status"]}"'
)
def test_mindestens_ein_gebaut(self):
"""Mindestens ein Testfall muss GEBAUT sein."""
gebaut = [r for r in self.results if r["status"] == "GEBAUT"]
assert len(gebaut) > 0, "Keine einzige Gefaellestrecke konnte gebaut werden"
# ---------------------------------------------------------------------------
# Klasse 2: Mathematische Invarianten
# ---------------------------------------------------------------------------
class TestGefaellestreckeMathematik:
"""Prueft mathematische Korrektheit der berechneten Werte."""
@pytest.fixture(autouse=True)
def setup(self):
self.results = _load_gefaellestrecke_results()
self.gebaut = [r for r in self.results if r["status"] == "GEBAUT"]
self.results_by_id = {r["test_id"]: r for r in self.results}
def test_gebaut_hat_pflichtfelder(self):
"""GEBAUT-Ergebnisse muessen alle Kernfelder enthalten."""
pflichtfelder = {
"modus", "hz_grad", "deltaL_mm", "winkel_grad",
"hoehe_von_mm", "hoehe_bis_mm", "delta_h_mm",
}
for r in self.gebaut:
missing = pflichtfelder - set(r.keys())
assert not missing, f'{r["test_id"]}: fehlende Felder {missing}'
def test_deltaL_positiv(self):
"""deltaL_mm muss fuer alle GEBAUT-Faelle groesser als 0 sein."""
for r in self.gebaut:
assert r["deltaL_mm"] > 0, (
f'{r["test_id"]}: deltaL_mm={r["deltaL_mm"]} muss > 0 sein'
)
def test_winkel_positiv(self):
"""Der berechnete Gefaellewinkel muss groesser als 0 Grad sein."""
for r in self.gebaut:
assert r["winkel_grad"] > 0, (
f'{r["test_id"]}: winkel_grad={r["winkel_grad"]} muss > 0 sein'
)
def test_delta_h_konsistent_mit_hoehen(self):
"""delta_h_mm muss der absoluten Differenz von hoehe_von/hoehe_bis entsprechen."""
for r in self.gebaut:
erwartet = abs(r["hoehe_von_mm"] - r["hoehe_bis_mm"])
assert erwartet == r["delta_h_mm"], (
f'{r["test_id"]}: delta_h_mm={r["delta_h_mm"]}, '
f'erwartet |{r["hoehe_von_mm"]}-{r["hoehe_bis_mm"]}|={erwartet}'
)
def test_hoehe_bis_kleiner_hoehe_von(self):
"""Bei einer Gefaellestrecke muss die Endhoehe unter der Starthoehe liegen."""
for r in self.gebaut:
assert r["hoehe_bis_mm"] < r["hoehe_von_mm"], (
f'{r["test_id"]}: hoehe_bis_mm={r["hoehe_bis_mm"]} '
f'nicht < hoehe_von_mm={r["hoehe_von_mm"]}'
)
# ---------------------------------------------------------------------------
# Klasse 3: Konsistenz zwischen den Modi
# ---------------------------------------------------------------------------
class TestGefaellestreckeModusKonsistenz:
"""Prueft Zusammenhaenge zwischen Modus 1/2/3 (Richtungsunabhaengigkeit,
Uebernahme von deltaH/deltaL aus Modus 2 in Modus 3)."""
# Toleranz fuer die 2-Pass-Winkelkorrektur in Modus 3 (mm)
DELTA_H_TOLERANZ_MM = 5
@pytest.fixture(autouse=True)
def setup(self):
self.results = _load_gefaellestrecke_results()
self.results_by_id = {r["test_id"]: r for r in self.results}
self.testdata = _load_gefaellestrecke_testdata()
self.tests_by_id = {t["test_id"]: t for t in self.testdata if "test_id" in t}
def test_modus1_richtungsunabhaengig(self):
"""Alle vier Modus-1-Richtungen muessen dieselbe Hoehe/Winkel liefern,
da nur die Fahrtrichtung (hz), nicht die Geometrie variiert."""
modus1 = [r for r in self.results
if r["modus"] == 1 and r["status"] == "GEBAUT"]
assert len(modus1) >= 2, "Zu wenige Modus-1-Ergebnisse fuer Vergleich"
referenz = modus1[0]
for r in modus1[1:]:
assert r["delta_h_mm"] == referenz["delta_h_mm"], (
f'{r["test_id"]}: delta_h_mm={r["delta_h_mm"]} weicht von '
f'{referenz["test_id"]}={referenz["delta_h_mm"]} ab (Richtungsabhaengigkeit!)'
)
assert r["winkel_grad"] == referenz["winkel_grad"], (
f'{r["test_id"]}: winkel_grad={r["winkel_grad"]} weicht von '
f'{referenz["test_id"]}={referenz["winkel_grad"]} ab'
)
def test_modus3_uebernimmt_deltaH_aus_modus2(self):
"""Modus 3 (Linienzug mit 2-Pass-Korrektur) muss innerhalb einer kleinen
Toleranz dieselbe Hoehendifferenz wie die Quelle aus Modus 2 erreichen."""
m3_test = self.tests_by_id.get("M3_hz270")
if m3_test is None:
pytest.skip("M3_hz270 nicht in Testdaten definiert")
quelle_id = m3_test.get("deltaH_quelle")
m2 = self.results_by_id.get(quelle_id)
m3 = self.results_by_id.get("M3_hz270")
if m2 is None or m3 is None:
pytest.skip("M2- oder M3-Ergebnis fehlt")
if m2["status"] != "GEBAUT" or m3["status"] != "GEBAUT":
pytest.skip("M2 oder M3 nicht GEBAUT")
abweichung = abs(m3["delta_h_mm"] - m2["delta_h_mm"])
assert abweichung <= self.DELTA_H_TOLERANZ_MM, (
f'M3_hz270: delta_h_mm={m3["delta_h_mm"]} weicht um {abweichung} mm '
f'von {quelle_id}={m2["delta_h_mm"]} ab '
f'(Toleranz {self.DELTA_H_TOLERANZ_MM} mm)'
)
-261
View File
@@ -1,261 +0,0 @@
;; ============================================================
;; test_kseinaus.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/kseinaus_results.json (Ergebnisse)
;; - tests/output/kseinaus_tests.dxf (Zeichnung)
;;
;; Voraussetzungen:
;; - SSG_LIB geladen (VarioFoerderer.lsp, ssg_core.lsp)
;; - Umgebungsvariable DXFMAKRO gesetzt
;;
;; Aufruf in BricsCAD:
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_kseinaus.lsp"))
;; TEST_KSEINAUS
;; ============================================================
;; --- Ergebnis eines Testfalls als JSON-String erzeugen ---
(defun kseinaus: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 kseinaus: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
(kseinaus: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
(kseinaus: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
(kseinaus: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
(kseinaus: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)
)
;; --- JSON-Export der KS-Testergebnisse ---
(defun kseinaus:export-results (tests-out-dir / out-json f first)
(if (null *kseinaus-test-results*)
(princ "\n Keine KS-Ergebnisse vorhanden.")
(progn
(vl-mkdir tests-out-dir)
(setq out-json (strcat tests-out-dir "/kseinaus_results.json"))
(setq f (open out-json "w"))
(if f
(progn
(write-line "[" f)
(setq first T)
(foreach r *kseinaus-test-results*
(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!"))
)
)
)
)
;; ============================================================
;; 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)
;; 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 (kseinaus: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 (kseinaus: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 (kseinaus: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 in globaler Variable speichern
(setq *kseinaus-test-results* (reverse results-list))
(ssg-end)
(princ "\n================================================================")
(princ "\n TEST_KSEINAUS abgeschlossen.")
(princ "\n================================================================")
(princ)
)
+6 -20
View File
@@ -1,10 +1,11 @@
;; ============================================================
;; test_omniflo.lsp - Automatischer Integrationstest fuer Omniflo
;;
;; Laedt Testfaelle aus tests/testdata/omniflo_tests.json,
;; Laedt Testfaelle aus tests/testdata/omniflo_tests.json und
;; fuegt je einen Bogen und Weiche jeden Typs in verschiedenen
;; Hoehen ein (Versatz in x-Richtung je 200mm) und exportiert
;; die CSV-Datei nach tests/output/omniflo_export.csv.
;; Hoehen ein (Versatz in x-Richtung je 200mm). Ergebnisse werden
;; ueber omniflo:export-results nach tests/output/omniflo_results.json
;; geschrieben (Aufruf durch SSG_RUN_ALL_TESTS oder manuell).
;;
;; Voraussetzungen:
;; - SSG_LIB geladen (OmniModulInsert.lsp, export.lsp)
@@ -104,14 +105,13 @@
;; ============================================================
;; C:TEST_OMNIFLO
;;
;; Liest omniflo_tests.json, fuegt alle Testbloecke ein,
;; exportiert CSV nach tests/output/.
;; Liest omniflo_tests.json und fuegt alle Testbloecke ein.
;; ============================================================
(defun c:TEST_OMNIFLO (/ tests-json-pfad testfaelle
x-val y-val
idx eintrag sivasnr hoehe-str drehung-str
description insert-pt anzahl-ok anzahl-fehler
results-list tests-out-dir old-results)
results-list)
(ssg-start "TEST_OMNIFLO"
'(("OSMODE") ("ATTREQ") ("ATTDIA")))
@@ -217,24 +217,10 @@
;; Ergebnisse in globaler Variable speichern
(setq *omniflo-test-results* (reverse results-list))
;; CSV-Export nach tests/output/
(setq tests-out-dir
(strcat (getenv "DXFMAKRO") "/tests/output"))
(vl-mkdir tests-out-dir)
(setq old-results (getenv "DXFM_RESULTS"))
(setenv "DXFM_RESULTS" tests-out-dir)
(princ "\n[TEST_OMNIFLO] Starte OMNI_EXPORT -> tests/output/omniflo_export.csv")
(c:OMNI_EXPORT)
(setenv "DXFM_RESULTS" (if old-results old-results ""))
(ssg-end)
(princ "\n================================================================")
(princ "\n TEST_OMNIFLO abgeschlossen.")
(princ (strcat "\n CSV: " tests-out-dir "/omniflo_export.csv"))
(princ "\n================================================================")
(princ)
)
+58 -95
View File
@@ -6,11 +6,11 @@ test_omniflo.py - Validiert Omniflo Bogen/Weiche Export.
Prueft:
1. CSV-Inhalt gegen Testdefinitionen (Unit-Test, ohne BricsCAD)
2. Merkmale-Werte gegen JSON-Katalog
3. Korrekte Anzahl und Reihenfolge der Elemente
4. Integrationstest: liest CSV aus BricsCAD-Lauf (falls vorhanden)
3. Korrekte Anzahl und Reihenfolge der Elemente inkl. Omniflo-Sum-Zeile
4. Integrationstest: liest omniflo_results.json aus BricsCAD-Lauf (falls vorhanden)
5. Referenz-Vergleich: CSV-Export aus export_csv.py gegen abgenommene Referenz-CSV
"""
import csv
import json
import os
import sys
@@ -99,6 +99,9 @@ class TestOmnifloExportUnit:
drehung=float(tc["drehung"]),
))
self.items = process_blocks(self.blocks, self.lookup)
# Item-Zeilen ohne die abschliessende "Omniflo Sum"-Zeile
self.element_items = [it for it in self.items if it["teileart"] != "Omniflo Sum"]
self.sum_item = next((it for it in self.items if it["teileart"] == "Omniflo Sum"), None)
# CSV in output speichern
out_dir = _output_dir()
@@ -112,27 +115,40 @@ class TestOmnifloExportUnit:
def test_item_count_matches_testcases(self):
"""Anzahl exportierter Elemente muss Anzahl Testfaelle entsprechen."""
assert len(self.items) == len(self.tests), (
f"Erwartet {len(self.tests)} Elemente, erhalten {len(self.items)}"
assert len(self.element_items) == len(self.tests), (
f"Erwartet {len(self.tests)} Elemente, erhalten {len(self.element_items)}"
)
def test_numbering_starts_at_one(self):
"""Element-Nummerierung muss bei 1 beginnen."""
assert self.items[0]["nr"] == 1, (
f"Erstes Element: nr={self.items[0]['nr']}, erwartet 1"
assert self.element_items[0]["nr"] == 1, (
f"Erstes Element: nr={self.element_items[0]['nr']}, erwartet 1"
)
def test_numbering_is_consecutive(self):
"""Element-Nummern muessen lueckenlos aufsteigen."""
"""Element-Nummern muessen lueckenlos aufsteigen (inkl. abschliessender Sum-Zeile)."""
for i, item in enumerate(self.items):
assert item["nr"] == i + 1, (
f"Element {i}: nr={item['nr']}, erwartet {i + 1}"
)
def test_sum_zeile_angehaengt(self):
"""Nach allen Omniflo-Elementen muss eine 'Omniflo Sum'-Zeile folgen."""
assert self.sum_item is not None, "Keine 'Omniflo Sum'-Zeile erzeugt"
assert self.sum_item["nr"] == len(self.items)
assert self.sum_item["teileid"] == "autogenerated_of_json"
m = self.sum_item["merkmale"]
bogen_tests = [tc for tc in self.tests if tc["type"] == "bogen"]
weiche_tests = [tc for tc in self.tests if tc["type"] == "weiche"]
assert m["Anzahl Bögen"] == len(bogen_tests)
assert (m["Anzahl Weichengrundkörper"] + m["Anzahl Einwegweichen"]
+ m["Anzahl Deltaweichen"] + m["Anzahl Doppelweichen und Dreiwegeweichen"]
+ m["Anzahl Sternweichen"]) == len(weiche_tests)
def test_bogen_teileart(self):
"""Boegen muessen TeileArt 'Omniflo Kurve' haben."""
bogen_tests = [tc for tc in self.tests if tc["type"] == "bogen"]
bogen_items = [it for it in self.items if it["teileart"] == "Omniflo Kurve"]
bogen_items = [it for it in self.element_items if it["teileart"] == "Omniflo Kurve"]
assert len(bogen_items) == len(bogen_tests), (
f"Erwartet {len(bogen_tests)} Boegen, erhalten {len(bogen_items)}"
)
@@ -140,7 +156,7 @@ class TestOmnifloExportUnit:
def test_weiche_teileart(self):
"""Weichen muessen TeileArt 'Omniflo Weiche' haben."""
weiche_tests = [tc for tc in self.tests if tc["type"] == "weiche"]
weiche_items = [it for it in self.items if it["teileart"] == "Omniflo Weiche"]
weiche_items = [it for it in self.element_items if it["teileart"] == "Omniflo Weiche"]
assert len(weiche_items) == len(weiche_tests), (
f"Erwartet {len(weiche_tests)} Weichen, erhalten {len(weiche_items)}"
)
@@ -148,7 +164,7 @@ class TestOmnifloExportUnit:
def test_bogen_merkmale_felder(self):
"""Boegen-Merkmale muessen alle Pflichtfelder enthalten."""
required = {"Kurvenwinkel", "Radius", "Höhe", "Drehung", "SivasNummer"}
for item in self.items:
for item in self.element_items:
if item["teileart"] != "Omniflo Kurve":
continue
merkmale = item["merkmale"]
@@ -161,7 +177,7 @@ class TestOmnifloExportUnit:
"""Weichen-Merkmale muessen alle Pflichtfelder enthalten."""
required = {"Weichentyp", "Richtung", "Weichenwinkel",
"Höhe", "Drehung", "Antrieb Kurve", "SivasNummer"}
for item in self.items:
for item in self.element_items:
if item["teileart"] != "Omniflo Weiche":
continue
merkmale = item["merkmale"]
@@ -174,7 +190,7 @@ class TestOmnifloExportUnit:
"""Bogen-Merkmale muessen mit JSON-Katalog uebereinstimmen."""
for tc, item in zip(
[t for t in self.tests if t["type"] == "bogen"],
[it for it in self.items if it["teileart"] == "Omniflo Kurve"]
[it for it in self.element_items if it["teileart"] == "Omniflo Kurve"]
):
sivasnr = tc["sivasnr"]
assert sivasnr in self.lookup, f"SivasNr {sivasnr} nicht im Katalog"
@@ -200,7 +216,7 @@ class TestOmnifloExportUnit:
"""Weichen-Merkmale muessen mit JSON-Katalog uebereinstimmen."""
for tc, item in zip(
[t for t in self.tests if t["type"] == "weiche"],
[it for it in self.items if it["teileart"] == "Omniflo Weiche"]
[it for it in self.element_items if it["teileart"] == "Omniflo Weiche"]
):
sivasnr = tc["sivasnr"]
assert sivasnr in self.lookup, f"SivasNr {sivasnr} nicht im Katalog"
@@ -229,7 +245,7 @@ class TestOmnifloExportUnit:
def test_bogen_hoehe_als_string(self):
"""Bogen-Hoehe muss als String vorliegen (z.B. '2000', nicht 2000)."""
for item in self.items:
for item in self.element_items:
if item["teileart"] != "Omniflo Kurve":
continue
assert isinstance(item["merkmale"]["Höhe"], str), (
@@ -239,7 +255,7 @@ class TestOmnifloExportUnit:
def test_weiche_hoehe_als_string(self):
"""Weichen-Hoehe muss als String vorliegen."""
for item in self.items:
for item in self.element_items:
if item["teileart"] != "Omniflo Weiche":
continue
assert isinstance(item["merkmale"]["Höhe"], str), (
@@ -248,7 +264,7 @@ class TestOmnifloExportUnit:
def test_kurvenwinkel_als_float(self):
"""Kurvenwinkel muss als Float vorliegen (90.0, nicht 90)."""
for item in self.items:
for item in self.element_items:
if item["teileart"] == "Omniflo Kurve":
assert isinstance(item["merkmale"]["Kurvenwinkel"], float), (
f"{item['bezeichnung']}: Kurvenwinkel muss float sein"
@@ -273,90 +289,37 @@ class TestOmnifloExportUnit:
# ---------------------------------------------------------------------------
# Integrations-Tests: CSV aus BricsCAD-Lauf validieren
# Integrations-Tests: Omniflo-Ergebnisse aus BricsCAD-Lauf validieren
# (tests/output/omniflo_results.json, geschrieben von omniflo:export-results)
# ---------------------------------------------------------------------------
class TestOmnifloExportCSV:
"""Validiert CSV-Datei aus dem BricsCAD-Lauf (c:TEST_OMNIFLO_EXPORT)."""
class TestOmnifloResults:
"""Validiert omniflo_results.json aus dem BricsCAD-Lauf (c:TEST_OMNIFLO)."""
@pytest.fixture(autouse=True)
def setup(self):
csv_path = os.path.join(_output_dir(), "omniflo_export.csv")
if not os.path.exists(csv_path):
pytest.skip(
"omniflo_export.csv nicht vorhanden - "
"TEST_OMNIFLO_EXPORT in BricsCAD ausfuehren"
)
self.csv_path = csv_path
self.rows = []
with open(csv_path, "r", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=";")
self.header = next(reader)
for row in reader:
self.rows.append(row)
def test_all_tests_executed(self, omniflo_testdata, omniflo_results):
"""Alle definierten Testfaelle muessen ausgefuehrt worden sein."""
expected_sivas = {t["sivasnr"] for t in omniflo_testdata}
result_sivas = {r["sivasnr"] for r in omniflo_results}
missing = expected_sivas - result_sivas
assert not missing, f"Nicht ausgefuehrte Tests: {missing}"
def test_header_felder(self):
"""CSV-Header muss korrekte Spaltenbezeichnungen haben."""
assert self.header[0] == "Elementnummer"
assert self.header[1] == "TeileArt"
assert self.header[2] == "TeileId"
assert self.header[3] == "Bezeichnung"
assert self.header[4] == "Anzahl"
assert self.header[5] == "Merkmale"
def test_mindest_anzahl_zeilen(self):
"""CSV muss mindestens so viele Zeilen haben wie Testfaelle."""
tests = _load_omniflo_tests()
assert len(self.rows) >= len(tests), (
f"CSV hat {len(self.rows)} Zeilen, "
f"erwartet mind. {len(tests)}"
)
def test_anzahl_spalte_ist_eins(self):
"""Anzahl-Spalte muss fuer alle Zeilen '1' sein."""
for i, row in enumerate(self.rows):
if len(row) < 5:
continue
assert row[4] == "1", (
f"Zeile {i + 2}: Anzahl={row[4]}, erwartet 1"
def test_all_executed_successfully(self, omniflo_results):
"""Alle Ergebnisse muessen Status 'OK' haben."""
for result in omniflo_results:
assert result["status"] == "OK", (
f'{result["test_id"]} ({result["sivasnr"]}): Status={result["status"]}'
)
def test_merkmale_sind_valides_json(self):
"""Merkmale-Spalte muss valides JSON enthalten."""
for i, row in enumerate(self.rows):
if len(row) < 6:
def test_hoehe_matches(self, omniflo_testdata, omniflo_results):
"""Eingefuegte Hoehe muss dem Testfall entsprechen."""
results_by_sivas = {r["sivasnr"]: r for r in omniflo_results}
for test in omniflo_testdata:
result = results_by_sivas.get(test["sivasnr"])
if not result:
continue
try:
json.loads(row[5])
except json.JSONDecodeError as e:
pytest.fail(
f"Zeile {i + 2}: Merkmale ist kein valides JSON: {e}\n"
f" Inhalt: {row[5][:100]}"
)
def test_bogen_merkmale_felder_in_csv(self):
"""Bogen-Zeilen muessen Pflichtfelder in Merkmale haben."""
required = {"Kurvenwinkel", "Radius", "Höhe", "Drehung", "SivasNummer"}
for i, row in enumerate(self.rows):
if len(row) < 6 or row[1].strip('"') != "Omniflo Kurve":
continue
merkmale = json.loads(row[5])
missing = required - set(merkmale.keys())
assert not missing, (
f"Zeile {i + 2}: Fehlende Bogen-Felder: {missing}"
)
def test_weiche_merkmale_felder_in_csv(self):
"""Weichen-Zeilen muessen Pflichtfelder in Merkmale haben."""
required = {"Weichentyp", "Richtung", "Weichenwinkel",
"Höhe", "Drehung", "Antrieb Kurve", "SivasNummer"}
for i, row in enumerate(self.rows):
if len(row) < 6 or row[1].strip('"') != "Omniflo Weiche":
continue
merkmale = json.loads(row[5])
missing = required - set(merkmale.keys())
assert not missing, (
f"Zeile {i + 2}: Fehlende Weichen-Felder: {missing}"
assert result["hoehe"] == str(int(test["hoehe"])), (
f'{test["sivasnr"]}: Hoehe erwartet={test["hoehe"]}, '
f'ist={result["hoehe"]}'
)
@@ -377,7 +340,7 @@ def _normalize_row(line):
class TestOmnifloReferenceCSV:
"""Vergleicht den erzeugten Unit-Test-CSV-Export mit einer Referenzdatei."""
"""Vergleicht den von export_csv.py erzeugten CSV-Export mit einer Referenzdatei."""
@pytest.fixture(autouse=True)
def setup(self):
+188 -29
View File
@@ -20,8 +20,50 @@
;; Aufruf in BricsCAD:
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp"))
;; SSG_RUN_ALL_TESTS
;;
;; Jedes Testmodul laeuft in einer eigenen, neuen Zeichnung (statt die
;; aktuelle zu leeren/wiederzuverwenden). SSG_RUN_ALL_TESTS fragt zu
;; Beginn interaktiv nach dem gewuenschten Modus:
;; Kontroll-Modus (Default): Zeichnung wird gespeichert, auf den
;; Inhalt gezoomt und bleibt als Tab offen - kein CSV/Sivas-Export.
;; Am Ende sind alle Testzeichnungen gleichzeitig offen und koennen
;; direkt begutachtet werden. CSV/Sivas-Export danach bei Bedarf
;; manuell ueber TEST_EXPORT_ALL (tests/test_export_all.lsp).
;; Automatik-Modus: Zeichnung wird gespeichert, per EXPORTCSV/
;; EXPORTSIVAS exportiert und danach sofort wieder geschlossen -
;; kompletter Lauf ohne manuellen Zusatzschritt, aber ohne
;; gleichzeitige visuelle Kontrolle aller Zeichnungen am Ende.
;; ============================================================
(vl-load-com)
;; --- Auf Fertigstellung einer asynchron geschriebenen Datei warten ---
;; csv:run-export startet Python per startapp (fire-and-forget). Pollt
;; bis die Datei existiert und ihre Groesse ueber ein Intervall stabil
;; bleibt, oder bis timeout-sec erreicht ist. Rueckgabe: T bei Erfolg.
;; (Analog zu export_all:wait-for-file aus tests/test_export_all.lsp,
;; hier lokal, da hier direkt auf der offenen Zeichnung exportiert wird
;; statt auf einer bereits gespeicherten Datei.)
(defun testrun:wait-for-file (path timeout-sec / elapsed size1 size2 done)
(setq elapsed 0.0 done nil)
(while (and (not done) (< elapsed timeout-sec))
(if (findfile path)
(progn
(setq size1 (vl-file-size path))
(command "_.DELAY" 400)
(setq size2 (vl-file-size path))
(if (and size1 size2 (= size1 size2) (> size1 0))
(setq done T)
)
)
(command "_.DELAY" 400)
)
(setq elapsed (+ elapsed 0.4))
)
done
)
;; --- Hilfsfunktion: String-Wert aus JSON-Objekt-Zeile lesen ---
;; Sucht "key": "value" in obj-str und gibt value zurueck.
@@ -99,14 +141,17 @@
)
(defun c:SSG_RUN_ALL_TESTS ( / tests-pfad tests-out-dir
(defun c:SSG_RUN_ALL_TESTS ( / tests-pfad tests-out-dir app auto-export
idx anz entry name save-fmt module
namen befehl datei export-fn
out-path old-json test-result)
namen befehl datei export-fn new-doc
out-path dwg-pfad dxf-pfad old-json test-result
old-filenames csv-name sivas-name csv-pfad
sivas-pfad csv-ok sivas-ok)
(setq tests-pfad (strcat (getenv "DXFMAKRO") "/tests"))
(setq tests-out-dir (strcat tests-pfad "/output"))
(vl-mkdir tests-out-dir)
(setq app (vlax-get-acad-object))
;; Testliste aus alltests.json laden
(setq *test-module* (alltests:load tests-pfad))
@@ -120,15 +165,29 @@
(setq anz (length *test-module*))
(setq idx 0)
;; Modus abfragen: Kontrolle (Zeichnungen bleiben offen, kein Export)
;; oder Automatik (Speichern + CSV/Sivas-Export + Schliessen je Test).
;; ssg-ques gibt T zurueck wenn "No" gewaehlt wurde - deshalb "not".
;; Default = Nein -> Kontroll-Modus (nicht-destruktiver Default).
(setq auto-export
(not (ssg-ques
"Zeichnungen automatisch speichern, exportieren (CSV/Sivas) und schliessen"
nil))
)
(princ "\n")
(princ "\n================================================================")
(princ "\n SSG_RUN_ALL_TESTS")
(princ (strcat "\n " (itoa anz) " Testmodule (aus alltests.json)"))
(princ (if auto-export
"\n Modus: Automatik (speichern + CSV/Sivas-Export + schliessen)"
"\n Modus: Kontrolle (Zeichnungen bleiben offen, kein Export)"
))
(princ "\n================================================================")
;; Tests laden und ausfuehren
;; Vor jedem Test werden alle Entities geloescht, damit jeder
;; Testlauf eine eigene saubere Zeichnung erzeugt.
;; Jeder Test bekommt eine eigene neue Zeichnung (statt die aktuelle
;; zu leeren/wiederzuverwenden) und bleibt danach als Tab offen.
(foreach entry *test-module*
(setq idx (1+ idx))
(setq name (cdr (assoc "name" entry)))
@@ -158,19 +217,18 @@
(princ " [kein Speichern]")
)
;; Zeichnung leeren fuer sauberen Testlauf
;; Frozen Layer werden von _.ERASE _ALL ignoriert - deshalb
;; erst alle Layer auftauen, entsperren und einschalten.
(command "_.LAYER" "_Thaw" "*" "_Unlock" "*" "_On" "*" "")
(if (ssget "_X")
(command "_.ERASE" "_ALL" "")
)
;; PURGE mehrfach, da verschachtelte Block-Referenzen
;; erst nach mehreren Durchlaeufen entfernt werden
(repeat 5
(command "_.PURGE" "_ALL" "" "_N")
)
;; Block-Library-Flag zuruecksetzen
;; Neue, leere Zeichnung fuer diesen Test anlegen und aktivieren
(setq new-doc (vla-add (vla-get-documents app)))
(vla-put-activedocument app new-doc)
;; vf_core.lsp/Gefaellestrecke.lsp setzen die globalen Variablen "doc"
;; und "modelspace" nur EINMAL, beim ersten Laden des Moduls (Top-Level-
;; Code, kein erneuter Aufruf durch ssg-ensure). Ohne diese Aktualisierung
;; wuerden VarioFoerderer/Gefaellestrecke weiterhin in das allererste
;; Dokument der Sitzung zeichnen statt in die hier neu angelegte
;; Zeichnung - die neuen Tabs blieben leer.
(setq doc new-doc)
(setq modelspace (vla-get-modelspace new-doc))
;; Block-Library-Flag zuruecksetzen (Bloecke sind pro Zeichnung neu zu laden)
(setq *lib-initialized* nil)
(if (findfile datei)
@@ -193,19 +251,117 @@
;; JSON-Export (immer)
(apply export-fn (list tests-out-dir))
;; Datei speichern je nach save-fmt aus alltests.json
(setq out-path (strcat tests-out-dir "/" name "_tests"))
(cond
((and save-fmt (= (strcase save-fmt) "DXF"))
(command "_.DXFOUT" out-path 6)
(princ (strcat "\n DXF gespeichert: " out-path ".dxf"))
(if auto-export
;; ==========================================================
;; AUTOMATIK-MODUS: speichern (vereinfacht, kein Tab-Naming-
;; Trick noetig) + CSV/Sivas-Export + Zeichnung schliessen.
;; ==========================================================
(progn
(cond
((and save-fmt (= (strcase save-fmt) "DWG"))
(setq dwg-pfad (strcat out-path ".dwg"))
(vla-saveas new-doc dwg-pfad)
(princ (strcat "\n DWG gespeichert: " dwg-pfad))
)
((and save-fmt (= (strcase save-fmt) "DXF"))
(command "_.DXFOUT" out-path 6)
(princ (strcat "\n DXF gespeichert: " out-path ".dxf"))
)
(T
(princ "\n (kein Speichern der Zeichnung)")
)
)
;; CSV/Sivas-Export direkt auf der offenen Zeichnung.
;; *export-filenames* temporaer umbiegen, damit jeder Test
;; seine eigenen CSV-Ergebnisse bekommt (statt der fixen
;; Standardnamen "export.csv"/"export_sivas.csv").
(setq csv-name (strcat name "_tests_export.csv"))
(setq sivas-name (strcat name "_tests_sivas.csv"))
(setq csv-pfad (strcat tests-out-dir "/" csv-name))
(setq sivas-pfad (strcat tests-out-dir "/" sivas-name))
(if (findfile csv-pfad) (vl-file-delete csv-pfad))
(if (findfile sivas-pfad) (vl-file-delete sivas-pfad))
(setq old-filenames *export-filenames*)
(setq *export-filenames*
(list
(cons "raw_json_datei" (cdr (assoc "raw_json_datei" old-filenames)))
(cons "sivas_script" (cdr (assoc "sivas_script" old-filenames)))
(cons "sivas_csv" sivas-name)
(cons "csv_script" (cdr (assoc "csv_script" old-filenames)))
(cons "csv_csv" csv-name)
)
)
(princ (strcat "\n CSV-Export -> " csv-name))
(c:EXPORTCSV)
(setq csv-ok (testrun:wait-for-file csv-pfad 30.0))
(princ (if csv-ok "\n CSV OK" "\n CSV TIMEOUT/FEHLER"))
(princ (strcat "\n Sivas-Export -> " sivas-name))
(c:EXPORTSIVAS)
(setq sivas-ok (testrun:wait-for-file sivas-pfad 30.0))
(princ (if sivas-ok "\n Sivas OK" "\n Sivas TIMEOUT/FEHLER"))
(setq *export-filenames* old-filenames)
;; Zeichnung schliessen: der urspruenglich schon offene Tab
;; bleibt unangetastet, BricsCAD erzeugt daher kein neues
;; Blank-Dokument samt Modul-/Menue-Reload.
(vla-close new-doc :vlax-false)
)
((and save-fmt (= (strcase save-fmt) "DWG"))
(command "_.-SAVEAS" "R2013" (strcat out-path ".dwg"))
(princ (strcat "\n DWG gespeichert: " out-path ".dwg"))
)
(T
(princ "\n (kein Speichern der Zeichnung)")
;; ==========================================================
;; KONTROLL-MODUS: speichern, auf Inhalt zoomen, Tab offen
;; lassen (bisheriges Verhalten).
;; ==========================================================
(progn
(cond
((and save-fmt (= (strcase save-fmt) "DWG"))
;; Direkt als DWG speichern - Tab bleibt offen und benannt.
;; Ueber ActiveX statt "_.-SAVEAS" "R2013" ...: Das Versions-
;; Keyword "R2013" wird von BricsCADs Kommandozeilen-SAVEAS
;; nicht zuverlaessig erkannt, wodurch der Befehl auf eine
;; ungueltige Eingabe wartet und nie eine Datei schreibt
;; (nachfolgende LISP-Eingaben landen dann im haengenden
;; Prompt). vla-saveas ist deterministisch.
(setq dwg-pfad (strcat out-path ".dwg"))
(vla-saveas new-doc dwg-pfad)
(princ (strcat "\n DWG gespeichert: " dwg-pfad))
)
((and save-fmt (= (strcase save-fmt) "DXF"))
;; Erst als DWG speichern (nur fuer den Tab-Namen) und DXF
;; exportieren. Danach die Zeichnung schliessen (entsperrt die
;; DWG-Datei), die temporaere DWG loeschen und stattdessen die
;; eigentlich angeforderte DXF-Datei erneut oeffnen - der Tab
;; ist dann korrekt an die DXF gebunden, keine ungewollte DWG
;; bleibt liegen.
(setq dwg-pfad (strcat out-path ".dwg"))
(setq dxf-pfad (strcat out-path ".dxf"))
(vla-saveas new-doc dwg-pfad)
(command "_.DXFOUT" out-path 6)
(vla-close new-doc :vlax-false)
(if (findfile dwg-pfad) (vl-file-delete dwg-pfad))
(setq new-doc (vla-open (vla-get-documents app) dxf-pfad))
(vla-put-activedocument app new-doc)
(setq doc new-doc)
(setq modelspace (vla-get-modelspace new-doc))
(princ (strcat "\n DXF gespeichert: " dxf-pfad))
)
(T
;; Kein Speichern angefordert: keine Datei erzeugen, Tab
;; bleibt beim generischen Namen ("ZeichnungN").
(princ "\n (kein Speichern der Zeichnung)")
)
)
;; Ansicht auf den gesamten Inhalt zoomen, Tab bleibt offen
;; (naechster Test startet in einer neuen Zeichnung).
(command "_.ZOOM" "_Extents")
)
)
)
@@ -216,6 +372,9 @@
(princ "\n\n================================================================")
(princ "\n SSG_RUN_ALL_TESTS abgeschlossen.")
(princ (strcat "\n Ergebnisse in: " (getenv "DXFMAKRO") "/tests/output/"))
(if (not auto-export)
(princ "\n CSV/Sivas-Export: TEST_EXPORT_ALL manuell aufrufen (Menue: Tests -> Export CSV/Sivas ALL)")
)
(princ "\n================================================================")
(princ)
)
+1 -1
View File
@@ -1,6 +1,6 @@
[
{
"y_abstand": 400
"y_abstand": 600
},
{
"test_id": "VF_Auf_0",
+59
View File
@@ -0,0 +1,59 @@
[
{
"deltaL_mm": 10000,
"winkel_grad": 3.0,
"z_start_mm": 5000
},
{
"test_id": "M1_hz000",
"modus": 1,
"hz_grad": 0.0,
"start_mm": [0, 0, 5000],
"as_seite": "links",
"es_seite": "links"
},
{
"test_id": "M1_hz090",
"modus": 1,
"hz_grad": 90.0,
"start_mm": [15000, 0, 5000],
"as_seite": "links",
"es_seite": "links"
},
{
"test_id": "M1_hz180",
"modus": 1,
"hz_grad": 180.0,
"start_mm": [0, -15000, 5000],
"as_seite": "links",
"es_seite": "links"
},
{
"test_id": "M1_hz270",
"modus": 1,
"hz_grad": 270.0,
"start_mm": [15000, -15000, 5000],
"as_seite": "links",
"es_seite": "links"
},
{
"test_id": "M2_hz000",
"modus": 2,
"hz_grad": 0.0,
"start_mm": [0, -35000, 5000],
"linie_start_mm": [0, -35000, 0],
"linie_ende_mm": [10000, -35000, 0],
"as_seite": "links",
"es_seite": "links"
},
{
"test_id": "M3_hz270",
"modus": 3,
"richtung": "Sued",
"start_mm": [0, -50000, 5000],
"deltaH_quelle": "M2_hz000",
"deltaL_quelle": "M2_hz000",
"as_seite": "links",
"es_seite": "links"
}
]