Ports the foundational board classes: Unit (mil/inch/mm/um with micrometer scaling), Layer/LayerStructure (the layer stack with name and signal-layer lookups), CoordinateTransform (DSN<->board scaling by the resolution), Net/Nets (connectivity keyed by (name, subnet) and a board- unique net number), and ClearanceMatrix (class x class spacing with a reserved null class and a default class). The per-layer axis of ClearanceMatrix is simplified to a single value per class pair (DSN default clearance rules are layer-independent for the boards we build); the router phase can add the layer dimension. Unit-tested: unit scaling/parsing, layer lookups, transform round-trip, net registration/lookup, and clearance default/append/symmetry.
70 lines
2.1 KiB
Python
70 lines
2.1 KiB
Python
"""Unit tests for the board data model (layers, units, transform, nets, clearance)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from freeroute.board import (
|
|
ClearanceMatrix,
|
|
CoordinateTransform,
|
|
Layer,
|
|
LayerStructure,
|
|
Nets,
|
|
Unit,
|
|
)
|
|
|
|
|
|
def test_unit_scale_and_parse():
|
|
assert Unit.from_string("um") is Unit.UM
|
|
assert Unit.from_string("MM") is Unit.MM
|
|
assert Unit.from_string("bogus") is None
|
|
assert Unit.scale(1.0, Unit.MM, Unit.UM) == 1000.0
|
|
assert Unit.scale(1.0, Unit.INCH, Unit.MIL) == 1000.0
|
|
assert str(Unit.MIL) == "mil"
|
|
|
|
|
|
def test_layer_structure_lookup():
|
|
ls = LayerStructure([Layer("F.Cu", True), Layer("In1", False), Layer("B.Cu", True)])
|
|
assert len(ls) == 3
|
|
assert ls.get_no("F.Cu") == 0
|
|
assert ls.get_no("B.Cu") == 2
|
|
assert ls.get_no("missing") == -1
|
|
assert ls.signal_layer_count() == 2
|
|
assert ls.get_signal_layer(1).name == "B.Cu"
|
|
|
|
|
|
def test_coordinate_transform_roundtrip():
|
|
t = CoordinateTransform(10)
|
|
assert t.dsn_to_board(5) == 50
|
|
assert t.board_to_dsn(50) == 5
|
|
p = t.dsn_to_board_point(100, -200)
|
|
assert (p.x, p.y) == (1000, -2000)
|
|
back = t.board_to_dsn_point(p)
|
|
assert (back.x, back.y) == (100.0, -200.0)
|
|
|
|
|
|
def test_nets_add_and_lookup():
|
|
nets = Nets()
|
|
a = nets.add("GND")
|
|
b = nets.add("VCC", subnet_number=1)
|
|
assert a.net_number == 1
|
|
assert b.net_number == 2
|
|
assert nets.max_net_no() == 2
|
|
assert nets.get("GND") is a
|
|
assert nets.get_by_number(2) is b
|
|
assert nets.get("missing") is None
|
|
assert nets.names() == {"GND", "VCC"}
|
|
assert len(nets) == 2
|
|
|
|
|
|
def test_clearance_matrix_default_and_classes():
|
|
cm = ClearanceMatrix.default_instance(200)
|
|
assert cm.get_class_count() == 2 # null + default
|
|
assert cm.get_name(0) == "null"
|
|
assert cm.get_name(1) == "default"
|
|
assert cm.get_value(1, 1) == 200
|
|
assert cm.get_value(0, 1) == 0 # null class has no clearance
|
|
via = cm.append_class("via")
|
|
assert cm.get_no("via") == via
|
|
cm.set_value(1, via, 300)
|
|
assert cm.get_value(via, 1) == 300 # symmetric
|
|
assert cm.get_value(1, 1, add_safety_margin=True) == 216 # +16 margin
|