Files
metabuilder/pcbgenerator/tests/test_boardforge.py
2026-01-21 17:18:12 +00:00

130 lines
4.4 KiB
Python

import sys
from pathlib import Path
import zipfile
import pytest
EXPECTED_DIR = Path(__file__).resolve().parent / "expected"
# Add the repository root to sys.path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from boardforge import Pin, Component, PCB, Layer
def test_pin_rotation():
pin = Pin("A", (10, 20), 1, 0, rotation=90)
assert pytest.approx(pin.x, rel=1e-6) == 10
assert pytest.approx(pin.y, rel=1e-6) == 21
def test_pad_rotation():
comp = Component("R1", "RES", at=(0, 0), rotation=90)
pad = comp.add_pad("P1", 1, 0, w=1, h=1)
assert pytest.approx(pad.x, rel=1e-6) == 0
assert pytest.approx(pad.y, rel=1e-6) == 1
def test_export_creates_zip_and_files(tmp_path):
board = PCB(width=10, height=10)
board.set_layer_stack([
Layer.TOP_COPPER.value,
Layer.BOTTOM_COPPER.value,
Layer.TOP_SILK.value,
Layer.BOTTOM_SILK.value,
])
comp = board.add_component("TEST", ref="C1", at=(2, 2))
comp.add_pin("A", dx=0, dy=0)
comp.add_pin("B", dx=1, dy=0)
board.route_trace("C1:A", "C1:B", layer=Layer.TOP_COPPER.value)
via = board.add_via(5, 5, from_layer=Layer.TOP_COPPER.value, to_layer=Layer.BOTTOM_COPPER.value)
zone = board.add_filled_zone(net="GND", layer=Layer.BOTTOM_COPPER.value)
assert via in board.vias
assert zone in board.zones
zip_path = tmp_path / "out.zip"
board.export_gerbers(zip_path)
assert zip_path.exists()
with zipfile.ZipFile(zip_path) as z:
names = set(z.namelist())
gtl_data = z.read("GTL.gbr").decode()
gbl_data = z.read("GBL.gbr").decode()
gto_data = z.read("GTO.gbr").decode()
gbo_data = z.read("GBO.gbr").decode()
top_png = z.read("preview_top.png") if "preview_top.png" in names else b""
expected_gtl = (EXPECTED_DIR / "simple1_GTL.gbr").read_text()
expected_gbl = (EXPECTED_DIR / "simple1_GBL.gbr").read_text()
expected_gto = (EXPECTED_DIR / "simple1_GTO.gbr").read_text()
expected_gbo = (EXPECTED_DIR / "simple1_GBO.gbr").read_text()
# Validate that the PNG preview is a valid image with expected dimensions
from io import BytesIO
from PIL import Image
if top_png:
with Image.open(BytesIO(top_png)) as img:
assert img.size == (board.width * 10, board.height * 10)
# Verify board colour and trace colour at known points
assert img.getpixel((30, 30)) == (93, 34, 146, 255)
assert img.getpixel((25, 20)) == (255, 193, 0, 255)
assert "GTL.gbr" in names
assert "GTO.gbr" in names
assert "preview_top.svg" in names
assert "preview_top.png" in names
assert len(top_png) > 0
assert gtl_data == expected_gtl
assert gbl_data == expected_gbl
assert gto_data == expected_gto
assert gbo_data == expected_gbo
exploded_dir = tmp_path / "out"
assert exploded_dir.exists()
assert (exploded_dir / "GTL.gbr").read_text() == expected_gtl
assert (exploded_dir / "preview_top.svg").exists()
def test_sample_circuit_gerber_contains_trace(tmp_path):
board = PCB(width=5, height=5)
board.set_layer_stack([
Layer.TOP_COPPER.value,
Layer.BOTTOM_COPPER.value,
Layer.TOP_SILK.value,
Layer.BOTTOM_SILK.value,
])
r1 = board.add_component("RES", ref="R1", at=(1, 1))
r1.add_pin("A", dx=-0.5, dy=0)
r1.add_pin("B", dx=0.5, dy=0)
r1.add_pad("A", dx=-0.5, dy=0, w=1, h=1)
r1.add_pad("B", dx=0.5, dy=0, w=1, h=1)
r2 = board.add_component("RES", ref="R2", at=(3.3, 1))
r2.add_pin("A", dx=-0.5, dy=0)
r2.add_pin("B", dx=0.5, dy=0)
r2.add_pad("A", dx=-0.5, dy=0, w=1, h=1)
r2.add_pad("B", dx=0.5, dy=0, w=1, h=1)
board.route_trace("R1:B", "R2:A")
zip_path = tmp_path / "circuit.zip"
board.export_gerbers(zip_path)
assert zip_path.exists()
with zipfile.ZipFile(zip_path) as z:
gtl_data = z.read("GTL.gbr").decode()
gbl_data = z.read("GBL.gbr").decode()
gto_data = z.read("GTO.gbr").decode()
gbo_data = z.read("GBO.gbr").decode()
expected_gtl = (EXPECTED_DIR / "simple2_GTL.gbr").read_text()
expected_gbl = (EXPECTED_DIR / "simple2_GBL.gbr").read_text()
expected_gto = (EXPECTED_DIR / "simple2_GTO.gbr").read_text()
expected_gbo = (EXPECTED_DIR / "simple2_GBO.gbr").read_text()
assert gtl_data == expected_gtl
assert gbl_data == expected_gbl
assert gto_data == expected_gto
assert gbo_data == expected_gbo