#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ test_kreisel.py - Validiert ILS Kreisel Testergebnisse. Prueft: 1. Attributwerte aus results.json gegen Testdefinitionen 2. DXF-Geometrie mit ezdxf (Block-Existenz, Radien, Linien) 3. Referenz-Vergleich gegen abgenommene DXF """ import pytest # ============================================================ # Attribut-Pruefung (results.json vs. testdata) # ============================================================ class TestKreiselAttributes: """Prueft ob Attribute korrekt gesetzt wurden.""" 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} result_ids = {r["test_id"] for r in kreisel_results} missing = expected_ids - result_ids assert not missing, f"Nicht ausgefuehrte Tests: {missing}" def test_all_executed_successfully(self, kreisel_results): """Alle Ergebnisse muessen Status 'executed' haben.""" for result in kreisel_results: assert result["status"] == "executed", \ f'{result["test_id"]}: Status={result["status"]}' 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: result = results_by_id.get(test["id"]) if not result: continue 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: result = results_by_id.get(test["id"]) if not result: continue prefix = test.get("expect_block_prefix", "KREISEL_") assert result["block_name"].startswith(prefix), \ f'{test["id"]}: Block "{result["block_name"]}" beginnt nicht mit "{prefix}"' # ============================================================ # DXF Geometrie-Pruefung (ezdxf) # ============================================================ class TestKreiselGeometry: """Prueft DXF-Geometrie mit ezdxf.""" def test_blocks_in_modelspace(self, kreisel_dxf, kreisel_results): """Alle erzeugten Bloecke muessen im Modelspace vorhanden sein.""" msp = kreisel_dxf.modelspace() inserts = [e for e in msp if e.dxftype() == "INSERT"] insert_handles = {e.dxf.handle for e in inserts} for result in kreisel_results: assert result["block_handle"] in insert_handles, \ f'{result["test_id"]}: Block-Handle {result["block_handle"]} nicht im Modelspace' def test_kr_block_count(self, kreisel_dxf, kreisel_testdata): """Anzahl KR_-Bloecke muss Testfall-Anzahl entsprechen.""" 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) assert len(kr_inserts) >= expected_count, \ f"Erwartet mind. {expected_count} KR_-Bloecke, gefunden: {len(kr_inserts)}" def test_circle_radius(self, kreisel_dxf): """AN8/SP8 Kreise in KR_-Bloecken muessen Radius 400mm haben.""" for block in kreisel_dxf.blocks: if not block.name.startswith("KR_"): continue circles = [e for e in block if e.dxftype() == "CIRCLE"] for c in circles: assert abs(c.dxf.radius - 400.0) < 0.1, \ f'Block {block.name}: Kreis-Radius={c.dxf.radius}, erwartet=400.0' def test_insert_positions(self, kreisel_dxf, kreisel_results): """Insertionspunkte muessen mit results.json uebereinstimmen.""" msp = kreisel_dxf.modelspace() inserts_by_handle = {e.dxf.handle: e for e in msp if e.dxftype() == "INSERT"} for result in kreisel_results: insert = inserts_by_handle.get(result["block_handle"]) if not insert: continue expected = result["insert_point"] actual = insert.dxf.insert assert abs(actual.x - expected[0]) < 1.0, \ f'{result["test_id"]}: X={actual.x}, erwartet={expected[0]}' assert abs(actual.y - expected[1]) < 1.0, \ f'{result["test_id"]}: Y={actual.y}, erwartet={expected[1]}' # ============================================================ # Referenz-Vergleich # ============================================================ class TestKreiselReference: """Vergleicht Ergebnis gegen abgenommene Referenz-DXF.""" def test_block_count_matches_reference(self, kreisel_dxf, kreisel_ref_dxf): """Anzahl KR_-Bloecke muss mit Referenz uebereinstimmen.""" output_kr = sum(1 for e in kreisel_dxf.modelspace() if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_")) ref_kr = sum(1 for e in kreisel_ref_dxf.modelspace() if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_")) assert output_kr == ref_kr, \ f"Block-Anzahl: output={output_kr}, referenz={ref_kr}" def test_block_types_match_reference(self, kreisel_dxf, kreisel_ref_dxf): """Block-Typen muessen mit Referenz uebereinstimmen.""" output_names = sorted(e.dxf.name for e in kreisel_dxf.modelspace() if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_")) ref_names = sorted(e.dxf.name for e in kreisel_ref_dxf.modelspace() if e.dxftype() == "INSERT" and e.dxf.name.startswith("KR_")) assert output_names == ref_names, \ f"Block-Typen unterschiedlich:\n output: {output_names}\n referenz: {ref_names}"