[FEAT] Weitere Objekte der Anlage in hundm05.json bauen (Kreisel)
tests/testdata/hundm05.json enthaelt jetzt neben den 5 Spec-Ketten auch andere Objekte der Anlage - erkennbar am Feld "function", im Format der jeweiligen Einzel-Testdaten (ein Kreisel also wie in kreisel_tests.json). Damit beschreibt EINE Datei die ganze Anlage. - tests/test_hundm05.lsp: hundm05:bau-zusatzobjekte sammelt alle Objekte mit "function" und baut sie; hundm05:bau-kreisel ruft kreisel-insert-script (wie tests/test_kreisel.lsp) und liefert einen Ergebnis-Record in derselben Form wie die Ketten. Eigener ssg-start-Rahmen mit ATTREQ/ATTDIA 0, weil vsp-bau-datei seinen schon geschlossen hat und (command "_.INSERT" ...) sonst nach Attributwerten fragt. Je Objekt gefangen, damit ein Fehler die restlichen nicht mitnimmt. - Lisp/vf_spec.lsp: "kind" ist jetzt ein Record-Feld (Default "linienzug") statt eines Literals in vsp-result-json - so schreibt vsp-results-schreiben beide Objektarten in EINE Ergebnisdatei. - lib/vf_spec_export.py: Objekte der Ziel-Datei, die keine Kette beschreiben, werden beim Neuschreiben unveraendert ans Dateiende uebernommen. Ohne das waere jeder von Hand ergaenzte Eintrag beim naechsten Generatorlauf weg - die Datei ist erzeugt UND handgepflegt. spec_aus_flachen_objekten ueberspringt sie jetzt statt zu werfen, genau wie vsp-gruppieren in LISP. - tests/test_hundm05.py: die Ketten-Tests filtern auf kind "linienzug" (Records ohne das Feld stammen aus aelteren Laeufen und waren nur Ketten); neue Klasse TestZusatzobjekte prueft Status, expect_block_prefix, expect_hoehe (Attribut HOEHE), expect_kreiselart (KREISELART) und den Einfuegepunkt - dieselben Erwartungsfelder wie tests/test_kreisel.py. - tests/test_vf_spec.py: neuer Test, dass die Zusatzobjekte die Ketten-Zerlegung nicht beeinflussen - auch nicht, wenn sie mitten zwischen den Sektionen stehen (der eingetragene Kreisel stand zunaechst inmitten der Sub-Knoten von Kette 5; nach dem Regenerieren steht er am Dateiende). Verifiziert: 118 pytest-Tests gruen, Spec-Regenerierung uebernimmt das Zusatzobjekt (58 Objekte), beide .lsp lint-sauber. Die Kreisel-Tests warten auf den naechsten TEST_HUNDM05-Lauf. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+107
-1
@@ -38,7 +38,7 @@ def spec_objekte():
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def spec_ergebnisse():
|
||||
def alle_ergebnisse():
|
||||
for pfad in ERGEBNIS_ORTE:
|
||||
if os.path.isfile(pfad):
|
||||
with open(pfad, encoding="utf-8") as fh:
|
||||
@@ -47,6 +47,37 @@ def spec_ergebnisse():
|
||||
"ausfuehren")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def spec_ergebnisse(alle_ergebnisse):
|
||||
"""Nur die Ketten. Die Ergebnisdatei enthaelt seit dem Nachtragen
|
||||
weiterer Anlagenteile mehrere Objektarten, unterschieden ueber "kind"
|
||||
(Records ohne das Feld stammen aus einem aelteren Lauf und waren
|
||||
ausschliesslich Ketten)."""
|
||||
return [r for r in alle_ergebnisse
|
||||
if r.get("kind", "linienzug") == "linienzug"]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def kreisel_ergebnisse(alle_ergebnisse):
|
||||
raus = [r for r in alle_ergebnisse if r.get("kind") == "kreisel"]
|
||||
if not raus:
|
||||
pytest.skip("keine Kreisel-Ergebnisse (Lauf vor dem Nachtragen "
|
||||
"weiterer Anlagenteile?)")
|
||||
return raus
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def kreisel_objekte(spec_objekte):
|
||||
"""Die nachgetragenen Anlagenteile aus den Testdaten - alles mit
|
||||
"function", das keine Kette beschreibt."""
|
||||
raus = [o for o in spec_objekte
|
||||
if o.get("function") and not ("spec_id" in o or "glied" in o
|
||||
or "sub" in o)]
|
||||
if not raus:
|
||||
pytest.skip("keine Zusatzobjekte in tests/testdata/hundm05.json")
|
||||
return raus
|
||||
|
||||
|
||||
class TestSpecBau:
|
||||
|
||||
def test_je_spec_ein_ergebnis(self, spec_objekte, spec_ergebnisse):
|
||||
@@ -142,3 +173,78 @@ class TestSpecBau:
|
||||
f'{spec_r["spec_id"]}: Attribut {tag} ist ' \
|
||||
f'{spec_r["actual_attributes"].get(tag)!r}, ' \
|
||||
f'Journal-Pfad hatte {wert!r}'
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Weitere Objekte der Anlage (Kreisel)
|
||||
# ============================================================
|
||||
# tests/testdata/hundm05.json enthaelt neben den Ketten auch andere Objekte
|
||||
# der Anlage - Format wie tests/testdata/kreisel_tests.json (Schema in
|
||||
# tests/testdata/object_data.md Abschnitt 1). Gebaut werden sie von
|
||||
# hundm05:bau-zusatzobjekte in tests/test_hundm05.lsp.
|
||||
|
||||
class TestZusatzobjekte:
|
||||
|
||||
def test_je_objekt_ein_ergebnis(self, kreisel_objekte,
|
||||
kreisel_ergebnisse):
|
||||
soll = [o["id"] for o in kreisel_objekte]
|
||||
ist = [r["spec_id"] for r in kreisel_ergebnisse]
|
||||
assert ist == soll, f"Ergebnisse {ist}, erwartet {soll}"
|
||||
|
||||
def test_status_executed(self, kreisel_ergebnisse):
|
||||
for r in kreisel_ergebnisse:
|
||||
assert r["status"] == "executed", \
|
||||
f'{r["spec_id"]}: Status={r["status"]}, {r.get("fehler_text")}'
|
||||
|
||||
def test_block_prefix_wie_erwartet(self, kreisel_objekte,
|
||||
kreisel_ergebnisse):
|
||||
"""expect_block_prefix aus den Testdaten - bei Kreiseln KREISEL_,
|
||||
weil die Haelften zu einem Wrapper-Block zusammengefasst werden."""
|
||||
erwartet = dict((o["id"], o.get("expect_block_prefix"))
|
||||
for o in kreisel_objekte)
|
||||
for r in kreisel_ergebnisse:
|
||||
pref = erwartet.get(r["spec_id"])
|
||||
if not pref:
|
||||
continue
|
||||
assert r["block_name"].startswith(pref), \
|
||||
f'{r["spec_id"]}: Block {r["block_name"]!r} beginnt nicht ' \
|
||||
f'mit {pref!r}'
|
||||
|
||||
def test_hoehe_wie_erwartet(self, kreisel_objekte, kreisel_ergebnisse):
|
||||
erwartet = dict((o["id"], o.get("expect_hoehe"))
|
||||
for o in kreisel_objekte)
|
||||
for r in kreisel_ergebnisse:
|
||||
soll = erwartet.get(r["spec_id"])
|
||||
if soll is None:
|
||||
continue
|
||||
ist = r["actual_attributes"].get("HOEHE")
|
||||
assert ist == str(soll), \
|
||||
f'{r["spec_id"]}: HOEHE ist {ist!r}, erwartet {soll!r}'
|
||||
|
||||
def test_kreiselart_wie_erwartet(self, kreisel_objekte,
|
||||
kreisel_ergebnisse):
|
||||
erwartet = dict((o["id"], o.get("expect_kreiselart"))
|
||||
for o in kreisel_objekte)
|
||||
for r in kreisel_ergebnisse:
|
||||
soll = erwartet.get(r["spec_id"])
|
||||
if soll is None:
|
||||
continue
|
||||
ist = r["actual_attributes"].get("KREISELART")
|
||||
assert ist == str(soll), \
|
||||
f'{r["spec_id"]}: KREISELART ist {ist!r}, erwartet {soll!r}'
|
||||
|
||||
def test_einfuegepunkt_getroffen(self, kreisel_objekte,
|
||||
kreisel_ergebnisse):
|
||||
"""Der Einfuegepunkt des Wrapper-Blocks ist der in den Testdaten
|
||||
angegebene Punkt."""
|
||||
soll = dict((o["id"], [o.get("x"), o.get("y"), o.get("z")])
|
||||
for o in kreisel_objekte)
|
||||
for r in kreisel_ergebnisse:
|
||||
erwartet = soll.get(r["spec_id"])
|
||||
if not erwartet or erwartet[0] is None:
|
||||
continue
|
||||
for achse, (e, i) in enumerate(zip(erwartet, r["insert_point"])):
|
||||
if e is None:
|
||||
continue
|
||||
assert abs(float(e) - float(i)) < 1.0, \
|
||||
f'{r["spec_id"]}: Achse {achse} ist {i}, erwartet {e}'
|
||||
|
||||
Reference in New Issue
Block a user