c36d2774bf
Winkel im Linienzug durchgaengig als echter Wert (30/60/90) statt Auswahl- Index (1/2/3) journalisiert - behebt den Bug, bei dem ein verrutschter String-Wert zum falschen Bogen fuehrte (vfl-menu-winkel/-winkel-live/ -winkel-normieren, GF-Bogen und Vario-Kurve). Zentrales Glied-Schema (*vfl-glied-schema*) als single source of truth fuer AS/ES/GF-Bogen/Vario-Kurve: generisches bauen/lesen/validieren, benanntes Debug-Log (GF-Bogen.winkel = 90 statt roher [INT]-Zeilen). VF-Einheit ueber Sub-Step-Referenz (*vfl-vf-substeps*) benannt geloggt, ohne sie in ein starres Feld-Schema zu zwingen. Vario-Kurve als eigenes Sub-Glied editierbar (eigener STEP-Marker wie ES): vfl-vario-slice-bauen/-werte/-splicen, vfl-glied-vario-dialog, Dispatcher-Zweig, Label. Schwanz-erhaltender Splice (vfl-vario-slice-splicen), da die Vario-Kurve mitten in der VF-Einheit steht und ihr Slice nachfolgende VF-Antworten enthaelt - naiver Splice haette diese verworfen (adversarial verifiziert). Uebrige VF-Sub-Segmente bleiben bewusst nur ueber Sektions-Ruecksprung editierbar. Neuer Unittest tests/test_vfl_schema.lsp (TEST_VFL_SCHEMA, in alltests.json): Roundtrip + Validierung + Vario-Schwanz-Splice ohne Geometrie. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
235 lines
10 KiB
Common Lisp
235 lines
10 KiB
Common Lisp
;; ============================================================
|
|
;; test_vfl_schema.lsp - Unittest fuer das Glied-Schema (vf_linienzug.lsp)
|
|
;;
|
|
;; Prueft die reinen Schema-Helfer OHNE Geometrie/BricsCAD-Bau:
|
|
;; - vfl-schema-slice-bauen / vfl-schema-slice-werte (Roundtrip)
|
|
;; - vfl-schema-feld-pruefen (Validierung Typ + erlaubte Werte)
|
|
;; - die Adapter vfl-gf-bogen-slice-bauen/-werte, vfl-es-slice-bauen/-werte
|
|
;; (Kompatibilitaet zum bisherigen flachen Journal-Format)
|
|
;;
|
|
;; Voraussetzung: VarioFoerderer.lsp (inkl. vf_linienzug.lsp) geladen.
|
|
;;
|
|
;; Aufruf in BricsCAD:
|
|
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_vfl_schema.lsp"))
|
|
;; TEST_VFL_SCHEMA
|
|
;;
|
|
;; Speichert tests/output/vfl_schema_results.json (Konvention test_run_all).
|
|
;; ============================================================
|
|
|
|
(setq *tvs-pass* 0 *tvs-fail* 0 *tvs-fails* '())
|
|
|
|
;; Ein Assert: erwartet-Wert gleich ist-Wert (equal). Loggt Pass/Fail.
|
|
(defun tvs-eq (name erwartet ist)
|
|
(if (equal erwartet ist)
|
|
(progn (setq *tvs-pass* (1+ *tvs-pass*))
|
|
(princ (strcat "\n [PASS] " name)))
|
|
(progn (setq *tvs-fail* (1+ *tvs-fail*))
|
|
(setq *tvs-fails* (cons name *tvs-fails*))
|
|
(princ (strcat "\n [FAIL] " name
|
|
"\n erwartet: " (vl-princ-to-string erwartet)
|
|
"\n ist: " (vl-princ-to-string ist))))))
|
|
|
|
;; Assert: Ausdruck ist nicht-nil (z.B. ein Fehlertext von der Validierung).
|
|
(defun tvs-truthy (name ist)
|
|
(if ist
|
|
(progn (setq *tvs-pass* (1+ *tvs-pass*))
|
|
(princ (strcat "\n [PASS] " name)))
|
|
(progn (setq *tvs-fail* (1+ *tvs-fail*))
|
|
(setq *tvs-fails* (cons name *tvs-fails*))
|
|
(princ (strcat "\n [FAIL] " name " (erwartet nicht-nil, war nil)")))))
|
|
|
|
;; Assert: Ausdruck ist nil (z.B. kein Validierungsfehler).
|
|
(defun tvs-nil (name ist)
|
|
(if (null ist)
|
|
(progn (setq *tvs-pass* (1+ *tvs-pass*))
|
|
(princ (strcat "\n [PASS] " name)))
|
|
(progn (setq *tvs-fail* (1+ *tvs-fail*))
|
|
(setq *tvs-fails* (cons name *tvs-fails*))
|
|
(princ (strcat "\n [FAIL] " name
|
|
" (erwartet nil, war " (vl-princ-to-string ist) ")")))))
|
|
|
|
(defun vfl-schema:tests ( / slice werte)
|
|
|
|
;; --- GF-Bogen: bauen erzeugt exakt die bisherige flache Struktur ---
|
|
;; STEP("GF-Bogen") STR("1") INT(90) STR("1")
|
|
(setq slice (vfl-gf-bogen-slice-bauen 90 "1"))
|
|
(tvs-eq "gf-bogen bauen: struktur"
|
|
(list (cons "STEP" "GF-Bogen") (cons "STR" "1")
|
|
(cons "INT" 90) (cons "STR" "1"))
|
|
slice)
|
|
|
|
;; --- GF-Bogen: Roundtrip bauen -> lesen ergibt (winkel seite) ---
|
|
(tvs-eq "gf-bogen roundtrip 60/rechts"
|
|
(list 60 "2")
|
|
(vfl-gf-bogen-slice-werte (vfl-gf-bogen-slice-bauen 60 "2")))
|
|
(tvs-eq "gf-bogen roundtrip 30/links"
|
|
(list 30 "1")
|
|
(vfl-gf-bogen-slice-werte (vfl-gf-bogen-slice-bauen 30 "1")))
|
|
|
|
;; --- GF-Bogen: die Seite ist der STR NACH dem INT (nicht der menue-STR) ---
|
|
;; Genau der Fall, an dem das alte "nach-int"-Flag haengt.
|
|
(tvs-eq "gf-bogen lesen: seite = STR nach INT"
|
|
(list 90 "2")
|
|
(vfl-gf-bogen-slice-werte
|
|
(list (cons "STEP" "GF-Bogen") (cons "STR" "1")
|
|
(cons "INT" 90) (cons "STR" "2"))))
|
|
|
|
;; --- GF-Bogen: Alt-Journal mit Index (1/2/3) statt Winkel wird auf den
|
|
;; Default 90 normiert (harte Umstellung, dokumentiertes Verhalten). ---
|
|
(tvs-eq "gf-bogen lesen: alt-index -> default 90"
|
|
(list 90 "1")
|
|
(vfl-gf-bogen-slice-werte
|
|
(list (cons "STEP" "GF-Bogen") (cons "STR" "1")
|
|
(cons "INT" 2) (cons "STR" "1"))))
|
|
|
|
;; --- ES: bauen/lesen Roundtrip (Winkel als STR "30"/"90") ---
|
|
(setq slice (vfl-es-slice-bauen "30" "2"))
|
|
(tvs-eq "es bauen: struktur"
|
|
(list (cons "STEP" "ES") (cons "STR" "30") (cons "STR" "2"))
|
|
slice)
|
|
(tvs-eq "es roundtrip 90/links"
|
|
(list "90" "1")
|
|
(vfl-es-slice-werte (vfl-es-slice-bauen "90" "1")))
|
|
|
|
;; --- Vario-Kurve: generisch bauen/lesen (winkel INT, seite/variante STR) ---
|
|
(setq slice (vfl-schema-slice-bauen "Vario-Kurve" (list 60 "2" "1")))
|
|
(tvs-eq "vario bauen: struktur"
|
|
(list (cons "STEP" "Vario-Kurve") (cons "INT" 60)
|
|
(cons "STR" "2") (cons "STR" "1"))
|
|
slice)
|
|
(tvs-eq "vario roundtrip"
|
|
(list 90 "1" "2")
|
|
(vfl-schema-slice-werte "Vario-Kurve"
|
|
(vfl-schema-slice-bauen "Vario-Kurve" (list 90 "1" "2"))
|
|
(list 90 "1" "1")))
|
|
|
|
;; --- Vario-Kurve Edit-Adapter (vfl-vario-slice-bauen/-werte) ---
|
|
;; Slice: STEP INT(winkel) STR(seite) STR(variante). Roundtrip inkl. Winkel-
|
|
;; Normierung (analog GF-Bogen).
|
|
(setq slice (vfl-vario-slice-bauen 60 "2" "1"))
|
|
(tvs-eq "vario-adapter bauen: struktur"
|
|
(list (cons "STEP" "Vario-Kurve") (cons "INT" 60)
|
|
(cons "STR" "2") (cons "STR" "1"))
|
|
slice)
|
|
(tvs-eq "vario-adapter roundtrip 30/rechts/innen"
|
|
(list 30 "2" "2")
|
|
(vfl-vario-slice-werte (vfl-vario-slice-bauen 30 "2" "2")))
|
|
;; Alt-Journal/Fremdwert im Winkel -> Default 90 (Normierung)
|
|
(tvs-eq "vario-adapter: fremdwinkel -> default 90"
|
|
(list 90 "1" "2")
|
|
(vfl-vario-slice-werte
|
|
(list (cons "STEP" "Vario-Kurve") (cons "INT" 2)
|
|
(cons "STR" "1") (cons "STR" "2"))))
|
|
;; Vario-Kurve ist jetzt im Schema (eigenes STEP-Glied)
|
|
(tvs-truthy "vario-kurve hat schema (eigenes glied)"
|
|
(vfl-schema-felder "Vario-Kurve"))
|
|
|
|
;; --- Vario-Kurve schwanz-erhaltende Splice (Regressionstest) ---
|
|
;; Die Vario-Kurve steht MITTEN in der VF-Einheit; nach ihren 3 Werten folgen
|
|
;; VF-Antworten in derselben Slice. Beim Editieren duerfen NUR die 3 Vario-
|
|
;; Felder ersetzt werden, der Schwanz muss erhalten bleiben (sonst verschiebt
|
|
;; sich beim Replay die Kette). alt-slice mit Schwanz STR("2") STR("1"):
|
|
(setq slice (list (cons "STEP" "Vario-Kurve") (cons "INT" 90)
|
|
(cons "STR" "1") (cons "STR" "2")
|
|
(cons "STR" "2") (cons "STR" "1"))) ; <- Schwanz (VF-Antworten)
|
|
(tvs-eq "vario splice: 3 felder ersetzt, schwanz erhalten"
|
|
(list (cons "STEP" "Vario-Kurve") (cons "INT" 60)
|
|
(cons "STR" "2") (cons "STR" "1")
|
|
(cons "STR" "2") (cons "STR" "1")) ; Schwanz unveraendert
|
|
(vfl-vario-slice-splicen slice 60 "2" "1"))
|
|
;; Reader liest trotz Schwanz korrekt die ersten 3 Felder (Vorbelegung):
|
|
(tvs-eq "vario werte-lesen ignoriert schwanz"
|
|
(list 90 "1" "2")
|
|
(vfl-vario-slice-werte slice))
|
|
|
|
;; --- Validierung: gueltige Werte -> kein Fehler ---
|
|
(tvs-nil "validierung gf-bogen winkel 90 ok"
|
|
(vfl-schema-feld-pruefen '("winkel" "INT" (30 60 90)) 90))
|
|
(tvs-nil "validierung seite '2' ok"
|
|
(vfl-schema-feld-pruefen '("seite" "STR" ("1" "2")) "2"))
|
|
|
|
;; --- Validierung: falscher Typ -> Fehlertext (nicht-nil) ---
|
|
;; Genau der Bug: ein STRING "30" in einem INT-Winkelfeld.
|
|
(tvs-truthy "validierung winkel als STRING -> fehler"
|
|
(vfl-schema-feld-pruefen '("winkel" "INT" (30 60 90)) "30"))
|
|
;; --- Validierung: Winkel ausserhalb der erlaubten Werte -> Fehlertext ---
|
|
(tvs-truthy "validierung winkel 45 nicht erlaubt -> fehler"
|
|
(vfl-schema-feld-pruefen '("winkel" "INT" (30 60 90)) 45))
|
|
;; --- Validierung: Seite ausserhalb ("3") -> Fehlertext ---
|
|
(tvs-truthy "validierung seite '3' nicht erlaubt -> fehler"
|
|
(vfl-schema-feld-pruefen '("seite" "STR" ("1" "2")) "3"))
|
|
|
|
;; --- Schema-Zugriff: unbekanntes Glied (VF-Einheit) -> keine Felder ---
|
|
(tvs-nil "vf-einheit hat kein schema"
|
|
(vfl-schema-felder "Horizontal-VF"))
|
|
;; --- AS ist bewusst kein STEP-Glied -> slice-bauen liefert nil ---
|
|
(tvs-nil "as slice-bauen ist nil (praeambel-sonderfall)"
|
|
(vfl-schema-slice-bauen "AS" (list "90" "1")))
|
|
|
|
;; --- VF-Einheit: Sub-Step-Benennung nach Wert-Muster ---
|
|
;; 1. STR einer VF-Einheit = fuehrende Menue-Wahl "4" (Horizontal-VF)
|
|
(tvs-eq "vf-substep: 1. STR = menue"
|
|
"menue"
|
|
(car (vfl-vf-substep-benennen (cons "STR" "4") 0)))
|
|
(tvs-nil "vf-substep: menue '4' ist gueltig"
|
|
(cdr (vfl-vf-substep-benennen (cons "STR" "4") 0)))
|
|
;; menue-Wert ausserhalb ("2") -> Fehlertext
|
|
(tvs-truthy "vf-substep: menue '2' ungueltig -> fehler"
|
|
(cdr (vfl-vf-substep-benennen (cons "STR" "2") 0)))
|
|
;; spaetere STR "3" = 1-3-Menue-Schritt (ist-ende/naechstes-vf)
|
|
(tvs-eq "vf-substep: spaetere STR '3' = menue3"
|
|
"ist-ende/naechstes-vf"
|
|
(car (vfl-vf-substep-benennen (cons "STR" "3") 1)))
|
|
;; spaetere STR "2" = ja/nein bzw. 1-3 (1/2)
|
|
(tvs-eq "vf-substep: spaetere STR '2' = wahl(1/2)"
|
|
"wahl(1/2)"
|
|
(car (vfl-vf-substep-benennen (cons "STR" "2") 1)))
|
|
;; DL/REAL = Laenge
|
|
(tvs-eq "vf-substep: DL = laenge"
|
|
"laenge"
|
|
(car (vfl-vf-substep-benennen (cons "DL" 4566.7) 0)))
|
|
;; eingebettete Vario-Kurve: INT-Winkel gueltig
|
|
(tvs-nil "vf-substep: eingebetteter vario-winkel 60 gueltig"
|
|
(cdr (vfl-vf-substep-benennen (cons "INT" 60) 1)))
|
|
(tvs-truthy "vf-substep: eingebetteter vario-winkel 45 ungueltig"
|
|
(cdr (vfl-vf-substep-benennen (cons "INT" 45) 1)))
|
|
|
|
(princ))
|
|
|
|
|
|
;; Ergebnis-Export (Konvention <name>:export-results fuer test_run_all.lsp)
|
|
(defun vfl_schema:export-results (out-dir / f pfad)
|
|
(setq pfad (strcat out-dir "/vfl_schema_results.json"))
|
|
(setq f (open pfad "w"))
|
|
(if f
|
|
(progn
|
|
(write-line "{" f)
|
|
(write-line (strcat " \"pass\": " (itoa *tvs-pass*) ",") f)
|
|
(write-line (strcat " \"fail\": " (itoa *tvs-fail*) ",") f)
|
|
(write-line (strcat " \"status\": \""
|
|
(if (= *tvs-fail* 0) "OK" "FEHLER") "\"") f)
|
|
(write-line "}" f)
|
|
(close f)
|
|
(princ (strcat "\n Ergebnis: " pfad))))
|
|
(princ))
|
|
|
|
|
|
(defun c:TEST_VFL_SCHEMA ( / )
|
|
(setq *tvs-pass* 0 *tvs-fail* 0 *tvs-fails* '())
|
|
(princ "\n================================================================")
|
|
(princ "\n TEST_VFL_SCHEMA - Glied-Schema (vf_linienzug.lsp)")
|
|
(princ "\n================================================================")
|
|
(vfl-schema:tests)
|
|
(princ "\n\n----------------------------------------------------------------")
|
|
(princ (strcat "\n Ergebnis: " (itoa *tvs-pass*) " PASS, "
|
|
(itoa *tvs-fail*) " FAIL"))
|
|
(if (> *tvs-fail* 0)
|
|
(progn
|
|
(princ "\n Fehlgeschlagen:")
|
|
(foreach n (reverse *tvs-fails*) (princ (strcat "\n - " n)))))
|
|
(princ "\n================================================================")
|
|
(princ))
|
|
|
|
(princ "\nTEST_VFL_SCHEMA geladen. Aufruf: TEST_VFL_SCHEMA")
|
|
(princ)
|