Kreisel Script-Funktionen und flaches JSON-Testformat

- kreisel-insert-script und kreisel-connect-script in KreiselInsert.lsp
  fuer nicht-interaktives Einfuegen (Tests, Automatisierung)
- kreisel_tests.json von verschachteltem auf flaches JSON-Array umgestellt
  (kompatibel mit omni:load-json)
- test_kreisel.py an neues JSON-Format angepasst (direkte Felder statt
  nested expect/attributes)
- conftest.py: Leere kreisel_results.json wird jetzt korrekt uebersprungen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 16:05:40 +02:00
parent fc38d4740f
commit bd053d76d3
5 changed files with 181 additions and 137 deletions
+53
View File
@@ -638,6 +638,59 @@
)
;; ============================================================
;; Script-Funktionen (ohne User-Interaktion, fuer Tests)
;; ============================================================
;; Kreisel per Script einfuegen (Insert)
;; pt : Einfuegepunkt (x y z)
;; abstand : Abstand in mm
;; rotation : Drehwinkel in Grad
;; typ : Kreiselart ("STANDARD", "PIN", ...)
;; hoehe : Hoehe in mm (oder nil fuer Z aus pt)
;; Rueckgabe: Entity-Name des erzeugten Blocks oder nil
(defun kreisel-insert-script (pt abstand rotation typ hoehe / z blockEnt)
(ssg-start "Kreisel Script Insert" '(("OSMODE") ("CECOLOR")))
(if (null typ) (setq typ "STANDARD"))
(setq z (if hoehe hoehe
(if (and pt (caddr pt)) (caddr pt) *kreisel-default-hoehe*)))
(setq blockEnt
(draw-module (list (car pt) (cadr pt) z) abstand rotation
(list (cons "KREISELART" typ)
(cons "HOEHE" (rtos z 2 0)))))
(ssg-end)
blockEnt
)
;; Kreisel per Script einfuegen (Connect: Start- zu Endpunkt)
;; ptStart : Startpunkt (x y z)
;; ptEnd : Endpunkt (x y z)
;; typ : Kreiselart ("STANDARD", "PIN", ...)
;; hoehe : Hoehe in mm (oder nil fuer Z aus ptStart)
;; Rueckgabe: Entity-Name des erzeugten Blocks oder nil
(defun kreisel-connect-script (ptStart ptEnd typ hoehe / dx dy dist abstand rotation z blockEnt)
(ssg-start "Kreisel Script Connect" '(("OSMODE") ("CECOLOR")))
(if (null typ) (setq typ "STANDARD"))
(setq dx (- (car ptEnd) (car ptStart))
dy (- (cadr ptEnd) (cadr ptStart)))
(setq dist (sqrt (+ (* dx dx) (* dy dy))))
(setq abstand (- dist *kreisel-durchmesser*))
(if (<= abstand 0.0)
(progn (princ (strcat "\n[Connect] Distanz zu klein: " (rtos dist 2 0)))
(ssg-end) nil)
(progn
(setq rotation (* (/ 180.0 pi) (atan dy dx)))
(setq z (if hoehe hoehe
(if (and ptStart (caddr ptStart)) (caddr ptStart) *kreisel-default-hoehe*)))
(setq blockEnt
(draw-module (list (car ptStart) (cadr ptStart) z) abstand rotation
(list (cons "KREISELART" typ)
(cons "HOEHE" (rtos z 2 0)))))
(ssg-end) blockEnt))
)
;; Ende kreisel-connect-script
;; Neue Befehle für Beschriftungs-Einstellungen
(defun c:KreiselLabelPos ( / dx dy)
(setq dx (getreal (strcat "\nX-Abstand von AN8-Mitte <" (rtos *kreisel-beschriftung-abstand-x* 2 0) ">: ")))
+5 -2
View File
@@ -78,8 +78,11 @@ def kreisel_results():
"""Laedt die Kreisel-Ergebnisse aus output/kreisel_results.json."""
path = os.path.join(_output_dir(), "kreisel_results.json")
if not os.path.exists(path):
pytest.skip("kreisel_results.json nicht vorhanden - TESTRUN in BricsCAD ausfuehren")
return _load_json(path)
pytest.skip("kreisel_results.json nicht vorhanden - TEST_KREISEL in BricsCAD ausfuehren")
data = _load_json(path)
if not data:
pytest.skip("kreisel_results.json ist leer - TEST_KREISEL in BricsCAD ausfuehren")
return data
@pytest.fixture
+1 -1
View File
@@ -240,7 +240,7 @@
;; DXF speichern
(setq out-dxf (strcat tests-out-dir "/kreisel_tests.dxf"))
(command "_.SAVEAS" "DXF" out-dxf)
(command "_.SAVEAS" "" out-dxf)
(princ (strcat "\n DXF gespeichert: " out-dxf))
(ssg-end)
+13 -9
View File
@@ -21,7 +21,7 @@ class TestKreiselAttributes:
def test_all_tests_executed(self, kreisel_testdata, kreisel_results):
"""Alle definierten Testfaelle muessen ausgefuehrt worden sein."""
expected_ids = {t["id"] for t in kreisel_testdata["tests"]}
expected_ids = {t["id"] for t in kreisel_testdata}
result_ids = {r["test_id"] for r in kreisel_results}
missing = expected_ids - result_ids
assert not missing, f"Nicht ausgefuehrte Tests: {missing}"
@@ -35,23 +35,27 @@ class TestKreiselAttributes:
def test_attributes_match(self, kreisel_testdata, kreisel_results):
"""Erwartete Attribute muessen mit tatsaechlichen uebereinstimmen."""
results_by_id = {r["test_id"]: r for r in kreisel_results}
for test in kreisel_testdata["tests"]:
for test in kreisel_testdata:
result = results_by_id.get(test["id"])
if not result:
continue
for attr, expected in test["expect"]["attributes"].items():
actual = result["actual_attributes"].get(attr)
assert actual == expected, \
f'{test["id"]}: {attr} erwartet="{expected}", ist="{actual}"'
if "expect_kreiselart" in test:
actual = result["actual_attributes"].get("KREISELART")
assert actual == test["expect_kreiselart"], \
f'{test["id"]}: KREISELART erwartet="{test["expect_kreiselart"]}", ist="{actual}"'
if "expect_hoehe" in test:
actual = result["actual_attributes"].get("HOEHE")
assert actual == test["expect_hoehe"], \
f'{test["id"]}: HOEHE erwartet="{test["expect_hoehe"]}", ist="{actual}"'
def test_block_prefix(self, kreisel_testdata, kreisel_results):
"""Block-Namen muessen mit erwartetem Praefix beginnen."""
results_by_id = {r["test_id"]: r for r in kreisel_results}
for test in kreisel_testdata["tests"]:
for test in kreisel_testdata:
result = results_by_id.get(test["id"])
if not result:
continue
prefix = test["expect"]["block_prefix"]
prefix = test.get("expect_block_prefix", "KREISEL_")
assert result["block_name"].startswith(prefix), \
f'{test["id"]}: Block "{result["block_name"]}" beginnt nicht mit "{prefix}"'
@@ -77,7 +81,7 @@ class TestKreiselGeometry:
msp = kreisel_dxf.modelspace()
kr_inserts = [e for e in msp if e.dxftype() == "INSERT"
and e.dxf.name.startswith("KR_")]
expected_count = len(kreisel_testdata["tests"])
expected_count = len(kreisel_testdata)
assert len(kr_inserts) >= expected_count, \
f"Erwartet mind. {expected_count} KR_-Bloecke, gefunden: {len(kr_inserts)}"
+109 -125
View File
@@ -1,125 +1,109 @@
{
"module": "Kreisel",
"version": "1.0",
"description": "ILS Kreisel Testfaelle - alle Richtungen und Kreiselarten",
"base_dxf": "kreisel_testbase.dxf",
"output_dxf": "kreisel_tests.dxf",
"output_results": "kreisel_results.json",
"tests": [
{
"id": "KR_Horiz_ObenUnten",
"function": "draw-module",
"description": "Horizontaler Kreisel, oben nach unten, STANDARD",
"params": {
"basepoint": [500.0, 5000.0, 2500.0],
"abstand": 4200.0,
"rotation": 270.0,
"attribs": {
"KREISELART": "STANDARD",
"NAME": "TEST_H_ObenUnten"
}
},
"expect": {
"attributes": {
"KREISELART": "STANDARD",
"DREHUNG": "270.0",
"ABSTAND": "4200"
},
"block_prefix": "KR_",
"min_entities": 6
}
},
{
"id": "KR_Horiz_UntenOben",
"function": "draw-module",
"description": "Horizontaler Kreisel, unten nach oben, PIN",
"params": {
"basepoint": [1500.0, 0.0, 2500.0],
"abstand": 4200.0,
"rotation": 90.0,
"attribs": {
"KREISELART": "PIN",
"NAME": "TEST_H_UntenOben"
}
},
"expect": {
"attributes": {
"KREISELART": "PIN",
"DREHUNG": "90.0",
"ABSTAND": "4200"
},
"block_prefix": "KR_",
"min_entities": 6
}
},
{
"id": "KR_Vert_LinksRechts",
"function": "draw-module",
"description": "Vertikaler Kreisel, links nach rechts, PIN",
"params": {
"basepoint": [0.0, 500.0, 2500.0],
"abstand": 4200.0,
"rotation": 0.0,
"attribs": {
"KREISELART": "PIN",
"NAME": "TEST_V_LinksRechts"
}
},
"expect": {
"attributes": {
"KREISELART": "PIN",
"DREHUNG": "0.0",
"ABSTAND": "4200"
},
"block_prefix": "KR_",
"min_entities": 6
}
},
{
"id": "KR_Vert_RechtsLinks",
"function": "draw-module",
"description": "Vertikaler Kreisel, rechts nach links, STANDARD",
"params": {
"basepoint": [5000.0, 1500.0, 2500.0],
"abstand": 4200.0,
"rotation": 180.0,
"attribs": {
"KREISELART": "STANDARD",
"NAME": "TEST_V_RechtsLinks"
}
},
"expect": {
"attributes": {
"KREISELART": "STANDARD",
"DREHUNG": "180.0",
"ABSTAND": "4200"
},
"block_prefix": "KR_",
"min_entities": 6
}
},
{
"id": "KR_Insert_Schraeg",
"function": "draw-module",
"description": "Kreisel mit 10 Grad Drehung, 6000mm Abstand, PIN",
"params": {
"basepoint": [3000.0, 3000.0, 2000.0],
"abstand": 6000.0,
"rotation": 10.0,
"attribs": {
"KREISELART": "PIN",
"NAME": "TEST_Insert"
}
},
"expect": {
"attributes": {
"KREISELART": "PIN",
"DREHUNG": "10.0",
"ABSTAND": "6000"
},
"block_prefix": "KR_",
"min_entities": 6
}
}
]
}
[
{
"id": "KR_Insert_Horiz_ObenUnten",
"function": "insert",
"x": 500,
"y": 5000,
"z": 2500,
"abstand": 4200,
"rotation": 270.0,
"typ": "STANDARD",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2500",
"expect_kreiselart": "STANDARD"
},
{
"id": "KR_Insert_Horiz_UntenOben",
"function": "insert",
"x": 1500,
"y": 0,
"z": 2500,
"abstand": 4200,
"rotation": 90.0,
"typ": "PIN",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2500",
"expect_kreiselart": "PIN"
},
{
"id": "KR_Insert_Vert_LinksRechts",
"function": "insert",
"x": 0,
"y": 500,
"z": 2500,
"abstand": 4200,
"rotation": 0.0,
"typ": "PIN",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2500",
"expect_kreiselart": "PIN"
},
{
"id": "KR_Insert_Vert_RechtsLinks",
"function": "insert",
"x": 5000,
"y": 1500,
"z": 2500,
"abstand": 4200,
"rotation": 180.0,
"typ": "STANDARD",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2500",
"expect_kreiselart": "STANDARD"
},
{
"id": "KR_Insert_Schraeg",
"function": "insert",
"x": 3000,
"y": 3000,
"z": 2000,
"abstand": 6000,
"rotation": 10.0,
"typ": "PIN",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2000",
"expect_kreiselart": "PIN"
},
{
"id": "KR_Connect_Horizontal",
"function": "connect",
"start_x": 0,
"start_y": 10000,
"start_z": 2500,
"end_x": 5800,
"end_y": 10000,
"end_z": 2500,
"typ": "STANDARD",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2500",
"expect_kreiselart": "STANDARD"
},
{
"id": "KR_Connect_Vertikal",
"function": "connect",
"start_x": 8000,
"start_y": 0,
"start_z": 3000,
"end_x": 8000,
"end_y": 6000,
"end_z": 3000,
"typ": "PIN",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "3000",
"expect_kreiselart": "PIN"
},
{
"id": "KR_Connect_Schraeg_45",
"function": "connect",
"start_x": 10000,
"start_y": 0,
"start_z": 2000,
"end_x": 14000,
"end_y": 4000,
"end_z": 2000,
"typ": "STANDARD",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2000",
"expect_kreiselart": "STANDARD"
}
]