5902343352
Nach dem gruenen VF_SPEC_BAU-Lauf bauten zwei Tests dieselben 5 Ketten. Der Spec-Pfad ist jetzt der routinemaessige Bau-Test, der Aufzeichnungs-Pfad der abgeschaltete Regressionstest fuer das Journal-Format. Umbenennungen: - tests/testdata/vf_spec_hundm05.json -> tests/testdata/hundm05.json Die Spec ist das Eingabeformat und die Datei, in der weitere Ketten der Anlage nachgetragen werden. spec_ids jetzt VF_hundm05_LZ_* (wie im Aufzeichnungs-Protokoll), damit sich die Ergebnisse beider Laeufe paaren lassen. - tests/testdata/hundm05.json -> tests/testdata/hm_recformat.json tests/test_hundm05.lsp -> tests/test_hm_recformat.lsp (TEST_HM_RECFORMAT, Praefix hmrec:, Export hm_recformat:export-results) tests/test_hundm05.py -> tests/test_hm_recformat.py In alltests.json auf "disabled": true. Neu: tests/test_hundm05.lsp (TEST_HUNDM05) baut die Spec - OHNE eigene Bau-Logik, es ruft vsp-bau-datei aus Lisp/vf_spec.lsp. Damit gibt es genau einen Code-Pfad, der aus einer Spec Geometrie erzeugt; c:VF_SPEC_BAU nutzt denselben. tests/test_hundm05.py prueft das Ergebnis (die 9 Tests, die vorher in test_vf_spec.py standen); test_vf_spec.py ist jetzt reiner Uebersetzer-Test ohne CAD. Warum das Aufzeichnungsformat bleibt (Details in doc/TODO-plan-vf-interactive.md Abschnitt 4.7): - hm_recformat.json ist die EINZIGE eingecheckte Kopie der Originaldaten (data/polylines.dxf ist mit 124 MB per .gitignore ausgeschlossen). Die Spec ist daraus abgeleitet; ohne die Aufzeichnung faellt die rechte Seite des Rundlauf-Beweises weg. - Es prueft eine ANDERE Invariante: das Journal kommt roh aus der XDATA einer Kundenzeichnung. TEST_HM_RECFORMAT ist damit der einzige Test dafuer, dass ein BESTEHENDER VF_n-Block weiter abspielbar ist - also dass Doppelklick-Edit und 2D/3D-Konvertierung an Altbestand funktionieren. Ein spec-gebautes Journal kann das nicht zeigen, es kommt aus dem Uebersetzer. - Es dokumentiert die Frage-Reihenfolge (kommentar je Eintrag); die Spec verbirgt den Dialog, das ist ihr Zweck. Weitere Anpassungen: - Ergebnisdatei heisst nach der Spec-Datei (<basisname>_results.json), damit Befehl und Testrunner in dieselbe Datei schreiben. Verzeichnis: tests/output (Override DXFM_VF_SPEC_OUT); NICHT DXFM_RESULTS - das sind die Sivas-/ CSV-Exporte, dort landete die Datei ausserhalb des Testbaums. - Neu *vsp-dim-override* fuer TEST_HUNDM05_2D/_3D: wird je Kette angewandt, weil der Abbruch-Handler in vf-linienzug-modus *ssg-ils-dim* zurueck setzt. - Das Anlagenkuerzel der test_id in lib/vf_journal_export.py kam aus dem Namen der Ziel-JSON. Nach der Umbenennung haette eine Regenerierung die ids stillschweigend auf VF_hm_recformat_LZ_* geaendert und die Paarung der beiden Laeufe zerlegt - jetzt feste Konstante TEST_ID_ANLAGE. - conftest: hundm05_* Fixtures -> hmrec_* (die Spec-Fixtures stehen in tests/test_hundm05.py). Verifiziert: 98 pytest-Tests gruen (die 9 Ergebnis-Tests warten auf einen neuen TEST_HUNDM05-Lauf), alle .lsp lint-sauber, Spec-Regenerierung idempotent, TEST_VF_SPEC in BricsCAD 28 PASS / 0 FAIL. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
493 lines
22 KiB
Common Lisp
493 lines
22 KiB
Common Lisp
;; ============================================================
|
|
;; test_vf_spec.lsp - Unittest fuer den Spec-Uebersetzer (vf_spec.lsp)
|
|
;;
|
|
;; Prueft vsp-journal OHNE Geometrie und ohne Zeichnung: aus einer Spec muss
|
|
;; genau die Tokenfolge entstehen, die der interaktive Ablauf aufzeichnen
|
|
;; wuerde. Weicht sie ab, baut der Spec-Pfad eine ANDERE Kette als die
|
|
;; Vorlage - der Fehler waere in der Zeichnung schwer zu sehen und im
|
|
;; Sivas-Export falsch.
|
|
;;
|
|
;; Zwei Arten von Testfaellen:
|
|
;; 1. Sieben handgebaute Specs, je ein Glied-Typ bzw. Sonderfall. Die
|
|
;; erwarteten Tokenfolgen sind NICHT von Hand abgeleitet, sondern mit
|
|
;; dem geprueften Python-Emitter erzeugt (lib/vf_spec_export.py) und
|
|
;; zusaetzlich durch den unabhaengigen Python-DEKODER gelaufen
|
|
;; (lib/vf_journal_export.py) - drei Implementierungen derselben
|
|
;; Grammatik, die einander pruefen.
|
|
;; 2. Die 5 echten HundM-Ketten: die Spec-Datei
|
|
;; tests/testdata/hundm05.json muss dieselben Journale ergeben
|
|
;; wie das aufgezeichnete Protokoll tests/testdata/hm_recformat.json.
|
|
;; Das ist der Beweis "Spec-Pfad == Journal-Pfad" auf Datenebene; der
|
|
;; Beweis auf Geometrie-Ebene ist VF_SPEC_BAU (siehe tests/test_vf_spec.py).
|
|
;;
|
|
;; Voraussetzung: VarioFoerderer.lsp geladen (vf_core laedt vf_spec mit).
|
|
;;
|
|
;; Aufruf in BricsCAD:
|
|
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_vf_spec.lsp"))
|
|
;; TEST_VF_SPEC
|
|
;;
|
|
;; Dieser Test baut KEINE Geometrie - er prueft nur den Uebersetzer.
|
|
;; Ergebnis: tests/output/vf_spec_unit_results.json (Pass/Fail-Zaehler).
|
|
;; Die gebaute Anlage prueft TEST_HUNDM05 (tests/test_hundm05.lsp).
|
|
;; ============================================================
|
|
|
|
(setq *tsp-pass* 0 *tsp-fail* 0 *tsp-fails* '())
|
|
|
|
(defun tsp-eq (name erwartet ist)
|
|
(if (equal erwartet ist)
|
|
(progn (setq *tsp-pass* (1+ *tsp-pass*))
|
|
(princ (strcat "\n [PASS] " name)))
|
|
(progn (setq *tsp-fail* (1+ *tsp-fail*))
|
|
(setq *tsp-fails* (cons name *tsp-fails*))
|
|
(princ (strcat "\n [FAIL] " name
|
|
"\n erwartet: " (vl-princ-to-string erwartet)
|
|
"\n ist: " (vl-princ-to-string ist))))))
|
|
|
|
(defun tsp-truthy (name ist)
|
|
(if ist
|
|
(progn (setq *tsp-pass* (1+ *tsp-pass*))
|
|
(princ (strcat "\n [PASS] " name)))
|
|
(progn (setq *tsp-fail* (1+ *tsp-fail*))
|
|
(setq *tsp-fails* (cons name *tsp-fails*))
|
|
(princ (strcat "\n [FAIL] " name " (erwartet nicht-nil, war nil)")))))
|
|
|
|
(defun tsp-nil (name ist)
|
|
(if (null ist)
|
|
(progn (setq *tsp-pass* (1+ *tsp-pass*))
|
|
(princ (strcat "\n [PASS] " name)))
|
|
(progn (setq *tsp-fail* (1+ *tsp-fail*))
|
|
(setq *tsp-fails* (cons name *tsp-fails*))
|
|
(princ (strcat "\n [FAIL] " name
|
|
" (erwartet nil, war " (vl-princ-to-string ist) ")")))))
|
|
|
|
;; Journal-Vergleich mit Fundstelle: bei 15-70 Tokens ist "erwartet (...)
|
|
;; ist (...)" unlesbar, der Index der ersten Abweichung dagegen sofort
|
|
;; brauchbar.
|
|
(defun tsp-journal-eq (name erwartet ist / i a b diff)
|
|
(setq i 0 diff nil)
|
|
(while (and (null diff) (or erwartet ist))
|
|
(setq i (1+ i) a (car erwartet) b (car ist))
|
|
(if (not (equal a b))
|
|
(setq diff (strcat "Token " (itoa i) ": erwartet "
|
|
(vl-princ-to-string a) ", ist "
|
|
(vl-princ-to-string b))))
|
|
(setq erwartet (cdr erwartet) ist (cdr ist)))
|
|
(if diff
|
|
(progn (setq *tsp-fail* (1+ *tsp-fail*))
|
|
(setq *tsp-fails* (cons name *tsp-fails*))
|
|
(princ (strcat "\n [FAIL] " name "\n " diff)))
|
|
(progn (setq *tsp-pass* (1+ *tsp-pass*))
|
|
(princ (strcat "\n [PASS] " name)))))
|
|
|
|
|
|
;; ============================================================
|
|
;; Spec-Bausteine
|
|
;; ============================================================
|
|
;; Eine Spec ist (kopf sektionen), eine Sektion (felder subs) - genau die
|
|
;; Struktur, die vsp-gruppieren aus dem flachen JSON baut.
|
|
|
|
(defun tsp-kopf (as-p)
|
|
(if as-p
|
|
(list (cons "spec_id" "TEST") (cons "modus" 1)
|
|
(cons "start_punkt" (list 1000.0 2000.0 3000.0))
|
|
(cons "start_hoehe" 3000.0) (cons "as" 1)
|
|
(cons "as_winkel" "90") (cons "as_seite" "links"))
|
|
(list (cons "spec_id" "TEST") (cons "modus" 1)
|
|
(cons "start_punkt" (list 1000.0 2000.0 3000.0))
|
|
(cons "start_hoehe" 3000.0) (cons "as" 0))))
|
|
|
|
(defun tsp-sek (felder subs) (list felder subs))
|
|
|
|
(defun tsp-es (winkel seite)
|
|
(tsp-sek (list (cons "glied" "ES") (cons "winkel" winkel)
|
|
(cons "seite" seite)) nil))
|
|
|
|
(defun tsp-spec (as-p sektionen) (list (tsp-kopf as-p) sektionen))
|
|
|
|
;; Praeambel-Tokens (kommen in fast jedem Fall vor)
|
|
(defun tsp-pre-mit-as ()
|
|
(list (cons "PT" (list 1000.0 2000.0 3000.0))
|
|
(cons "REAL" 3000.0)
|
|
(cons "STR" "1")
|
|
(cons "STR" "90")
|
|
(cons "STR" "1")))
|
|
|
|
(defun tsp-pre-ohne-as ()
|
|
(list (cons "PT" (list 1000.0 2000.0 3000.0))
|
|
(cons "REAL" 3000.0)
|
|
(cons "STR" "2")))
|
|
|
|
|
|
;; ============================================================
|
|
;; 1. Handgebaute Faelle je Glied-Typ
|
|
;; ============================================================
|
|
|
|
(defun tsp-tests-glieder ( / spec)
|
|
|
|
;; --- Linie-GF, Kettenende mit ES ---
|
|
;; Erste Sektion: Menue-Code "1" (4 Optionen, ohne Frame).
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Linie-GF") (cons "dl" 5500.0)
|
|
(cons "hz" 0.0) (cons "gefaelle" "winkel")
|
|
(cons "winkel" 3.0) (cons "ende" "ja-mit-es")) nil)
|
|
(tsp-es "90" "rechts"))))
|
|
(tsp-journal-eq "Linie-GF + ES"
|
|
(append (tsp-pre-mit-as)
|
|
(list (cons "STEP" "Linie-GF") (cons "STR" "1")
|
|
(cons "DL" 5500.0) (cons "REAL" 0.0)
|
|
(cons "STR" "2") (cons "REAL" 3.0) (cons "STR" "1")
|
|
(cons "STEP" "ES") (cons "STR" "90") (cons "STR" "2")))
|
|
(vsp-journal spec))
|
|
|
|
;; --- Horizontal-VF: horizontaler Erstkoerper ---
|
|
;; Nur hier stehen Separator vor/nach VOR der Endpunkt-Antwort
|
|
;; (vfl-baue-horizontal-koerper im Ziel-Modus).
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Horizontal-VF") (cons "dl" 8000.0)
|
|
(cons "hz" 90.0) (cons "gf_verteilung" "einlauf")
|
|
(cons "vf_sep_vor" 0) (cons "vf_sep_nach" 0)
|
|
(cons "vf_ende" "ja-mit-es"))
|
|
(list (list (cons "sub" "motorstation"))))
|
|
(tsp-es "90" "rechts"))))
|
|
(tsp-journal-eq "Horizontal-VF + Motorstation + ES"
|
|
(append (tsp-pre-mit-as)
|
|
(list (cons "STEP" "Horizontal-VF") (cons "STR" "3")
|
|
(cons "DL" 8000.0) (cons "REAL" 90.0)
|
|
(cons "STR" "2") ; GF-Verteilung: Einlauf
|
|
(cons "STR" "2") (cons "STR" "2") ; Separator vor / nach
|
|
(cons "STR" "1") ; Endpunkt: Motorstation
|
|
(cons "STR" "1") ; Kettenende: ja mit ES
|
|
(cons "STEP" "ES") (cons "STR" "90") (cons "STR" "2")))
|
|
(vsp-journal spec))
|
|
|
|
;; --- Linie-VF: GEWINKELTER Erstkoerper ---
|
|
;; Kein Separator-Fragenpaar (der Koerper wird ohne Frage gebaut), dafuer
|
|
;; Zielhoehe + optionale Winkelwahl. Danach eine Vario-Kurve und ein
|
|
;; Abschluss "nein" mit Separator.
|
|
(setq spec (tsp-spec nil (list
|
|
(tsp-sek (list (cons "glied" "Linie-VF") (cons "dl" 12000.0)
|
|
(cons "hz" 0.0) (cons "hoehe" 2000.0)
|
|
(cons "winkel_idx" 2) (cons "gf_verteilung" "haelfte")
|
|
(cons "vf_ende" "nein") (cons "vf_separator" 1))
|
|
(list (list (cons "sub" "vario-kurve") (cons "winkel" 90)
|
|
(cons "seite" "links") (cons "variante" "aussen"))
|
|
(list (cons "sub" "motorstation")))))))
|
|
(tsp-journal-eq "Linie-VF + Vario-Kurve (kein Separator-Paar)"
|
|
(append (tsp-pre-ohne-as)
|
|
(list (cons "STEP" "Linie-VF") (cons "STR" "2")
|
|
(cons "DL" 12000.0) (cons "REAL" 0.0)
|
|
(cons "REAL" 2000.0) (cons "INT" 2)
|
|
(cons "STR" "1") ; GF-Verteilung: Haelfte
|
|
(cons "STR" "2") (cons "STR" "2") ; weiter -> Vario-Kurve
|
|
(cons "STEP" "Vario-Kurve") (cons "INT" 90)
|
|
(cons "STR" "1") (cons "STR" "1") ; links, aussen
|
|
(cons "STR" "1") ; Endpunkt: Motorstation
|
|
(cons "STR" "2") (cons "STR" "1"))) ; kein Kettenende, Separator
|
|
(vsp-journal spec))
|
|
|
|
;; --- GF-Bogen als ZWEITE Sektion ---
|
|
;; Ab der zweiten Sektion gilt die 5-Optionen-Tabelle: Linie-GF ist dort
|
|
;; "2" (nicht mehr "1"), GF-Bogen ist "1".
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Linie-GF") (cons "dl" 3000.0)
|
|
(cons "hz" 180.0) (cons "gefaelle" "hoehe")
|
|
(cons "hoehe" 2500.0) (cons "ende" "nein")) nil)
|
|
(tsp-sek (list (cons "glied" "GF-Bogen") (cons "winkel" 60)
|
|
(cons "seite" "rechts")) nil))))
|
|
(tsp-journal-eq "GF-Bogen als zweite Sektion (Menue-Codes am Frame)"
|
|
(append (tsp-pre-mit-as)
|
|
(list (cons "STEP" "Linie-GF") (cons "STR" "1")
|
|
(cons "DL" 3000.0) (cons "REAL" 180.0)
|
|
(cons "STR" "1") (cons "REAL" 2500.0) (cons "STR" "3")
|
|
(cons "STEP" "GF-Bogen") (cons "STR" "1")
|
|
(cons "INT" 60) (cons "STR" "2")))
|
|
(vsp-journal spec))
|
|
|
|
;; --- Linie bis Kettenende, als reine Gefaellestrecke aufgeloest ---
|
|
;; Kein VF-Block: nach Laenge und Zielhoehe folgt direkt das ES-Glied.
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Linie") (cons "dl" 4000.0)
|
|
(cons "hz" 270.0) (cons "hoehe" 2000.0)
|
|
(cons "segment_typ" "GF")) nil)
|
|
(tsp-es "30" "links"))))
|
|
(tsp-journal-eq "Linie -> GF + ES"
|
|
(append (tsp-pre-mit-as)
|
|
(list (cons "STEP" "Linie") (cons "STR" "4")
|
|
(cons "DL" 4000.0) (cons "REAL" 270.0) (cons "REAL" 2000.0)
|
|
(cons "STEP" "ES") (cons "STR" "30") (cons "STR" "1")))
|
|
(vsp-journal spec))
|
|
|
|
;; --- Linie bis Kettenende, als VF-Einheit aufgeloest ---
|
|
;; auto_ende: das ES-Glied folgt OHNE Kettenende-Frage.
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Linie") (cons "dl" 9000.0)
|
|
(cons "hz" 0.0) (cons "hoehe" 1500.0)
|
|
(cons "segment_typ" "VF")
|
|
(cons "gf_verteilung" "einlauf")
|
|
(cons "vf_ende" "automatisch"))
|
|
(list (list (cons "sub" "auf-ab") (cons "dl" 3000.0)
|
|
(cons "hoehe" 1200.0))
|
|
(list (cons "sub" "motorstation"))))
|
|
(tsp-es "90" "rechts"))))
|
|
(tsp-journal-eq "Linie -> VF (auto-Ende, ES ohne Frage)"
|
|
(append (tsp-pre-mit-as)
|
|
(list (cons "STEP" "Linie") (cons "STR" "4")
|
|
(cons "DL" 9000.0) (cons "REAL" 0.0) (cons "REAL" 1500.0)
|
|
(cons "STR" "2") ; GF-Verteilung: Einlauf
|
|
(cons "STR" "2") (cons "STR" "3") ; weiter -> Auf/Ab
|
|
(cons "DL" 3000.0) (cons "REAL" 1200.0)
|
|
(cons "STR" "1") ; Endpunkt: Motorstation
|
|
(cons "STEP" "ES") (cons "STR" "90") (cons "STR" "2")))
|
|
(vsp-journal spec))
|
|
|
|
;; --- Kettenende am Zielpunkt OHNE ES ---
|
|
;; Die Kette endet direkt am Zielpunkt: kein Separator, kein ES, keine
|
|
;; weitere Frage.
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Horizontal-VF") (cons "dl" 7000.0)
|
|
(cons "hz" 0.0) (cons "gf_verteilung" "einlauf")
|
|
(cons "vf_sep_vor" 1) (cons "vf_sep_nach" 1)
|
|
(cons "vf_ende" "zielpunkt-ohne-es"))
|
|
(list (list (cons "sub" "kettenende") (cons "es" 0)
|
|
(cons "dl" 2500.0) (cons "hoehe" 1000.0)))))))
|
|
(tsp-journal-eq "Kettenende am Zielpunkt ohne ES"
|
|
(append (tsp-pre-mit-as)
|
|
(list (cons "STEP" "Horizontal-VF") (cons "STR" "3")
|
|
(cons "DL" 7000.0) (cons "REAL" 0.0)
|
|
(cons "STR" "2") ; GF-Verteilung: Einlauf
|
|
(cons "STR" "1") (cons "STR" "1") ; Separator vor / nach: ja
|
|
(cons "STR" "3") ; Endpunkt: Kettenende
|
|
(cons "STR" "2") ; ES setzen? nein
|
|
(cons "DL" 2500.0) (cons "REAL" 1000.0)))
|
|
(vsp-journal spec))
|
|
(princ))
|
|
|
|
|
|
;; ============================================================
|
|
;; 2. Validierung: die Spec darf nichts raten
|
|
;; ============================================================
|
|
|
|
(defun tsp-tests-validierung ( / spec)
|
|
|
|
;; --- hz nur beim ERSTEN Segment ---
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Linie-GF") (cons "dl" 3000.0)
|
|
(cons "hz" 0.0) (cons "gefaelle" "winkel")
|
|
(cons "winkel" 3.0) (cons "ende" "nein")) nil)
|
|
(tsp-sek (list (cons "glied" "Linie-GF") (cons "dl" 2000.0)
|
|
(cons "hz" 90.0) ; <- verboten
|
|
(cons "gefaelle" "winkel") (cons "winkel" 3.0)
|
|
(cons "ende" "nein")) nil))))
|
|
(tsp-nil "hz in spaeterer Sektion: kein Journal" (vsp-journal spec))
|
|
(tsp-truthy "hz in spaeterer Sektion: Fehler gemeldet" *vsp-fehler*)
|
|
|
|
;; --- hz fehlt beim ersten Segment ---
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Linie-GF") (cons "dl" 3000.0)
|
|
(cons "gefaelle" "winkel") (cons "winkel" 3.0)
|
|
(cons "ende" "nein")) nil))))
|
|
(tsp-nil "hz fehlt: kein Journal" (vsp-journal spec))
|
|
|
|
;; --- GF-Bogen in der ERSTEN Sektion (ohne Frame nicht waehlbar) ---
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "GF-Bogen") (cons "winkel" 90)
|
|
(cons "seite" "links")) nil))))
|
|
(tsp-nil "GF-Bogen als erste Sektion: kein Journal" (vsp-journal spec))
|
|
|
|
;; --- unbekannter Domaenenwert ---
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "GF-Bogen") (cons "winkel" 90)
|
|
(cons "seite" "mitte")) nil))))
|
|
(tsp-nil "Seite \"mitte\": kein Journal" (vsp-journal spec))
|
|
|
|
;; --- VF-Einheit ohne Abschluss-Knoten ---
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Horizontal-VF") (cons "dl" 8000.0)
|
|
(cons "hz" 0.0) (cons "gf_verteilung" "einlauf")
|
|
(cons "vf_sep_vor" 0) (cons "vf_sep_nach" 0)
|
|
(cons "vf_ende" "ja-mit-es"))
|
|
(list (list (cons "sub" "vario-kurve") (cons "winkel" 90)
|
|
(cons "seite" "links") (cons "variante" "innen")))))))
|
|
(tsp-nil "VF-Einheit endet mit Vario-Kurve: kein Journal" (vsp-journal spec))
|
|
|
|
;; --- Pflichtfeld fehlt ---
|
|
(setq spec (list (list (cons "spec_id" "X")
|
|
(cons "start_punkt" (list 0.0 0.0 0.0)))
|
|
(list (tsp-sek (list (cons "glied" "Linie-GF")
|
|
(cons "dl" 1000.0) (cons "hz" 0.0)
|
|
(cons "gefaelle" "winkel")
|
|
(cons "winkel" 3.0)
|
|
(cons "ende" "nein")) nil))))
|
|
(tsp-nil "start_hoehe fehlt: kein Journal" (vsp-journal spec))
|
|
|
|
;; --- gueltige Spec: vsp-pruefen meldet nichts ---
|
|
(setq spec (tsp-spec T (list
|
|
(tsp-sek (list (cons "glied" "Linie") (cons "dl" 4000.0)
|
|
(cons "hz" 0.0) (cons "hoehe" 2000.0)
|
|
(cons "segment_typ" "GF")) nil)
|
|
(tsp-es "90" "links"))))
|
|
(tsp-nil "gueltige Spec: keine Fehler" (vsp-pruefen spec))
|
|
(princ))
|
|
|
|
|
|
;; ============================================================
|
|
;; 3. Gruppieren des flachen JSON
|
|
;; ============================================================
|
|
|
|
(defun tsp-tests-gruppieren ( / objekte specs sek)
|
|
(setq objekte (list
|
|
(list (cons "spec_id" "A") (cons "start_punkt" (list 0.0 0.0 0.0)))
|
|
(list (cons "glied" "Horizontal-VF") (cons "nr" 1))
|
|
(list (cons "sub" "vario-kurve"))
|
|
(list (cons "sub" "motorstation"))
|
|
(list (cons "glied" "ES") (cons "nr" 2))
|
|
(list (cons "spec_id" "B") (cons "start_punkt" (list 1.0 1.0 1.0)))
|
|
(list (cons "glied" "Linie") (cons "nr" 1))))
|
|
(setq specs (vsp-gruppieren objekte))
|
|
(tsp-eq "gruppieren: 2 Specs" 2 (length specs))
|
|
(tsp-eq "gruppieren: Spec A hat 2 Sektionen" 2
|
|
(length (vsp-sektionen (car specs))))
|
|
(setq sek (car (vsp-sektionen (car specs))))
|
|
(tsp-eq "gruppieren: erste Sektion ist Horizontal-VF" "Horizontal-VF"
|
|
(ssg-val (vsp-sek-felder sek) "glied"))
|
|
(tsp-eq "gruppieren: sie hat 2 subs in Reihenfolge"
|
|
(list "vario-kurve" "motorstation")
|
|
(mapcar '(lambda (s) (ssg-val s "sub")) (vsp-sek-subs sek)))
|
|
(tsp-eq "gruppieren: ES-Sektion hat keine subs" nil
|
|
(vsp-sek-subs (cadr (vsp-sektionen (car specs)))))
|
|
(tsp-eq "gruppieren: Spec B hat 1 Sektion" 1
|
|
(length (vsp-sektionen (cadr specs))))
|
|
(princ))
|
|
|
|
|
|
;; ============================================================
|
|
;; 4. Die 5 echten HundM-Ketten: Spec == aufgezeichnetes Journal
|
|
;; ============================================================
|
|
;; Das aufgezeichnete Protokoll (hm_recformat.json) in Journal-Tokens
|
|
;; zurueckuebersetzen - dieselbe Umrechnung wie in test_hm_recformat.lsp, hier
|
|
;; bewusst dupliziert, damit der Test ohne den anderen Treiber laeuft.
|
|
|
|
(defun tsp-als-string (v)
|
|
(cond ((null v) "")
|
|
((= (type v) 'STR) v)
|
|
((= (type v) 'INT) (itoa v))
|
|
((= (type v) 'REAL) (rtos v 2 6))
|
|
(T (vl-princ-to-string v))))
|
|
|
|
(defun tsp-eintrag->journal (e / typ w hz)
|
|
(setq typ (ssg-val e "typ"))
|
|
(cond
|
|
((= typ "point_abs")
|
|
(setq w (ssg-val e "wert"))
|
|
(if (and w (listp w) (>= (length w) 3))
|
|
(list (cons "PT" (mapcar 'float w))) nil))
|
|
((= typ "point_rel")
|
|
(setq w (ssg-val e "dL") hz (ssg-val e "hz"))
|
|
(cond ((not (numberp w)) nil)
|
|
((numberp hz) (list (cons "DL" (float w)) (cons "REAL" (float hz))))
|
|
(T (list (cons "DL" (float w))))))
|
|
((= typ "real")
|
|
(setq w (ssg-val e "wert"))
|
|
(if (numberp w) (list (cons "REAL" (float w))) nil))
|
|
((= typ "int")
|
|
(setq w (ssg-val e "wert"))
|
|
(if (numberp w) (list (cons "INT" (fix w))) nil))
|
|
((= typ "string") (list (cons "STR" (tsp-als-string (ssg-val e "wert")))))
|
|
((= typ "step") (list (cons "STEP" (tsp-als-string (ssg-val e "wert")))))
|
|
(T nil)))
|
|
|
|
(defun tsp-protokoll-journale (daten / ketten aktuell journal)
|
|
(setq ketten '() journal '())
|
|
(foreach obj daten
|
|
(cond
|
|
((ssg-val obj "test_id")
|
|
(if aktuell (setq ketten (cons (list aktuell (reverse journal)) ketten)))
|
|
(setq aktuell (ssg-val obj "test_id") journal '()))
|
|
((ssg-val obj "typ")
|
|
(foreach j (tsp-eintrag->journal obj) (setq journal (cons j journal))))
|
|
(T nil)))
|
|
(if aktuell (setq ketten (cons (list aktuell (reverse journal)) ketten)))
|
|
(reverse ketten))
|
|
|
|
(defun tsp-tests-echte-ketten ( / p-datei s-datei p-daten specs journale i n
|
|
spec soll ist sid)
|
|
(setq p-datei (strcat (getenv "DXFMAKRO") "/tests/testdata/hm_recformat.json"))
|
|
(setq s-datei (strcat (getenv "DXFMAKRO")
|
|
"/tests/testdata/hundm05.json"))
|
|
(cond
|
|
((null (findfile p-datei))
|
|
(princ (strcat "\n [SKIP] " p-datei " fehlt")))
|
|
((null (findfile s-datei))
|
|
(princ (strcat "\n [SKIP] " s-datei " fehlt")))
|
|
(T
|
|
(setq p-daten (ssg-load-json p-datei))
|
|
(setq journale (tsp-protokoll-journale p-daten))
|
|
(setq specs (vsp-json-laden s-datei))
|
|
(tsp-eq "echte Ketten: 5 Protokolle" 5 (length journale))
|
|
(tsp-eq "echte Ketten: 5 Specs" 5 (length specs))
|
|
(setq n (min (length journale) (length specs)) i 0)
|
|
(while (< i n)
|
|
(setq spec (nth i specs))
|
|
(setq soll (cadr (nth i journale)))
|
|
(setq sid (vsp-spec-id (vsp-kopf spec)))
|
|
(setq ist (vsp-journal spec))
|
|
(if (null ist)
|
|
(progn
|
|
(tsp-truthy (strcat sid ": Spec fehlerfrei") nil)
|
|
(foreach f *vsp-fehler* (princ (strcat "\n - " f))))
|
|
(tsp-journal-eq (strcat sid " == aufgezeichnetes Journal ("
|
|
(car (nth i journale)) ")")
|
|
soll ist))
|
|
(setq i (1+ i)))))
|
|
(princ))
|
|
|
|
|
|
;; ============================================================
|
|
;; Ergebnis-Export (Konvention <name>:export-results fuer test_run_all.lsp)
|
|
;; ============================================================
|
|
|
|
(defun vf_spec:export-results (out-dir / f pfad)
|
|
(setq pfad (strcat out-dir "/vf_spec_unit_results.json"))
|
|
(setq f (open pfad "w"))
|
|
(if f
|
|
(progn
|
|
(write-line "{" f)
|
|
(write-line (strcat " \"pass\": " (itoa *tsp-pass*) ",") f)
|
|
(write-line (strcat " \"fail\": " (itoa *tsp-fail*) ",") f)
|
|
(write-line (strcat " \"status\": \""
|
|
(if (= *tsp-fail* 0) "OK" "FEHLER") "\"") f)
|
|
(write-line "}" f)
|
|
(close f)
|
|
(princ (strcat "\n Ergebnis: " pfad))))
|
|
(princ))
|
|
|
|
|
|
(defun c:TEST_VF_SPEC ( / )
|
|
(setq *tsp-pass* 0 *tsp-fail* 0 *tsp-fails* '())
|
|
(princ "\n================================================================")
|
|
(princ "\n TEST_VF_SPEC - Spec-Uebersetzer (vf_spec.lsp)")
|
|
(princ "\n================================================================")
|
|
(if (null (car (atoms-family 1 '("VSP-JOURNAL"))))
|
|
(princ "\n FEHLER: vf_spec.lsp nicht geladen (VarioFoerderer laden).")
|
|
(progn
|
|
(princ "\n\n-- Glied-Typen --")
|
|
(tsp-tests-glieder)
|
|
(princ "\n\n-- Validierung --")
|
|
(tsp-tests-validierung)
|
|
(princ "\n\n-- Gruppieren --")
|
|
(tsp-tests-gruppieren)
|
|
(princ "\n\n-- Echte HundM-Ketten --")
|
|
(tsp-tests-echte-ketten)))
|
|
(princ "\n\n----------------------------------------------------------------")
|
|
(princ (strcat "\n Ergebnis: " (itoa *tsp-pass*) " PASS, "
|
|
(itoa *tsp-fail*) " FAIL"))
|
|
(if (> *tsp-fail* 0)
|
|
(progn
|
|
(princ "\n Fehlgeschlagen:")
|
|
(foreach nm (reverse *tsp-fails*) (princ (strcat "\n - " nm)))))
|
|
(princ "\n================================================================")
|
|
(princ))
|
|
|
|
(princ "\nTEST_VF_SPEC geladen. Aufruf: TEST_VF_SPEC")
|
|
(princ)
|