"""Sanity tests for busbar_export — exercise STEP/DXF/SVG writers end-to-end.""" import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from busbar_export import to_step, to_dxf, to_svg def _payload(): return { "extrude": False, "busbars": [ { "name": "P1", "color": "#ff8800", "strip_width": 8.0, "pad_radius": 7.0, "hole_radius": 5.0, "cells": [ {"id": 1, "x": 0.0, "y": 0.0}, {"id": 2, "x": 22.8, "y": 0.0}, {"id": 3, "x": 45.6, "y": 0.0}, ], } ], } def test_step_export_is_iso_10303(): data = to_step(_payload()) text = data[:200].decode("ascii", errors="ignore") assert "ISO-10303-21" in text, f"STEP header missing, got: {text!r}" assert len(data) > 500 def test_dxf_export_is_nonempty(): data = to_dxf(_payload()) assert b"SECTION" in data[:2000] def test_svg_export_is_svg(): data = to_svg(_payload()) assert b" 500 def test_panel_grid_uses_convex_hull(): """4-cell square → 4-vertex hull → rounded rectangle.""" payload = { "busbars": [{ "name": "4P", "shape": "panel", "pad_radius": 10.0, "hole_radius": 5.0, "cells": [ {"id": 1, "x": 0.0, "y": 0.0}, {"id": 2, "x": 22.8, "y": 0.0}, {"id": 3, "x": 22.8, "y": 19.746}, {"id": 4, "x": 0.0, "y": 19.746}, ], }] } data = to_step(payload) assert b"ISO-10303-21" in data[:200] def test_panel_single_cell_is_disc_with_hole(): payload = { "busbars": [{ "name": "1P", "shape": "panel", "pad_radius": 10.0, "hole_radius": 5.0, "cells": [{"id": 1, "x": 0.0, "y": 0.0}], }] } data = to_step(payload) assert b"ISO-10303-21" in data[:200] def test_wire_shape_still_works(): payload = { "busbars": [{ "name": "wire", "shape": "wire", "strip_width": 6.0, "pad_radius": 7.0, "hole_radius": 5.0, "cells": [{"x": 0, "y": 0}, {"x": 22.8, "y": 0}], }] } data = to_step(payload) assert b"ISO-10303-21" in data[:200] def test_panel_L_shape_has_no_diagonal_bridge(): """L-shape (7 cells in column + 2 cells across top) must not bridge across non-selected cells. The convex-hull approach would have, but neighbor-edge must not — verify by checking that the area of the resulting face is close to the sum of stadium-chain segments, not the area of the L's bounding box. """ from busbar_export import parse_payload, busbar_sketch cells = [{"x": 0, "y": i * 19.75} for i in range(7)] cells += [{"x": 22.8, "y": 6 * 19.75}, {"x": 45.6, "y": 6 * 19.75}] payload = {"busbars": [{ "name": "L", "shape": "panel", "pad_radius": 10.0, "hole_radius": 6.0, "hole_shape": "cross", "slit_width": 1.8, "cells": cells, }]} busbars, *_ = parse_payload(payload) face = busbar_sketch(busbars[0]) area = face.area # Pad disc area = π·10² ≈ 314 per cell, 9 cells → 2826 max if all disjoint. # Bridges add some, holes subtract some. The L's bounding box is # 65.6 × 138.25 ≈ 9070 — convex hull would be at least ~4500. Neighbor # chain should be well under 3500. assert 2000 < area < 3500, f"area {area} suggests convex-hull bridging" def test_cross_slit_punches_through(): """Cross slit must remove area from the panel (vs. no holes baseline).""" from busbar_export import parse_payload, busbar_sketch base = { "busbars": [{ "name": "P", "shape": "panel", "pad_radius": 10.0, "hole_radius": 6.0, "hole_shape": "cross", "slit_width": 1.8, "cells": [{"x": 0, "y": 0}, {"x": 22.8, "y": 0}], }] } with_cross, *_ = parse_payload(base) area_cross = busbar_sketch(with_cross[0]).area # Same payload, tiny hole — should be nearly the same area as un-punched. base["busbars"][0]["hole_radius"] = 0.1 base["busbars"][0]["slit_width"] = 0.1 tiny, *_ = parse_payload(base) area_tiny = busbar_sketch(tiny[0]).area assert area_tiny > area_cross + 50, \ f"cross didn't punch much: tiny={area_tiny:.1f}, cross={area_cross:.1f}"