189 lines
5.3 KiB
Python
189 lines
5.3 KiB
Python
import pytest
|
|
from numpy.testing import assert_equal, assert_allclose
|
|
from numpy import pi
|
|
|
|
from ..ports import Port, PortList
|
|
from ..error import PortError
|
|
|
|
|
|
def test_port_init() -> None:
|
|
p = Port(offset=(10, 20), rotation=pi / 2, ptype="test")
|
|
assert_equal(p.offset, [10, 20])
|
|
assert p.rotation == pi / 2
|
|
assert p.ptype == "test"
|
|
|
|
|
|
def test_port_transform() -> None:
|
|
p = Port(offset=(10, 0), rotation=0)
|
|
p.rotate_around((0, 0), pi / 2)
|
|
assert_allclose(p.offset, [0, 10], atol=1e-10)
|
|
assert p.rotation is not None
|
|
assert_allclose(p.rotation, pi / 2, atol=1e-10)
|
|
|
|
p.mirror(0) # Mirror across x axis (axis 0): in-place relative to offset
|
|
assert_allclose(p.offset, [0, 10], atol=1e-10)
|
|
# rotation was pi/2 (90 deg), mirror across x (0 deg) -> -pi/2 == 3pi/2
|
|
assert p.rotation is not None
|
|
assert_allclose(p.rotation, 3 * pi / 2, atol=1e-10)
|
|
|
|
|
|
def test_port_flip_across() -> None:
|
|
p = Port(offset=(10, 0), rotation=0)
|
|
p.flip_across(axis=1) # Mirror across x=0: flips x-offset
|
|
assert_equal(p.offset, [-10, 0])
|
|
# rotation was 0, mirrored(1) -> pi
|
|
assert p.rotation is not None
|
|
assert_allclose(p.rotation, pi, atol=1e-10)
|
|
|
|
|
|
def test_port_measure_travel() -> None:
|
|
p1 = Port((0, 0), 0)
|
|
p2 = Port((10, 5), pi) # Facing each other
|
|
|
|
(travel, jog), rotation = p1.measure_travel(p2)
|
|
assert travel == 10
|
|
assert jog == 5
|
|
assert rotation == pi
|
|
|
|
|
|
def test_port_describe_any_rotation() -> None:
|
|
p = Port((0, 0), None)
|
|
assert p.describe() == "pos=(0, 0), rot=any"
|
|
|
|
|
|
def test_port_list_rename() -> None:
|
|
class MyPorts(PortList):
|
|
def __init__(self) -> None:
|
|
self._ports = {"A": Port((0, 0), 0)}
|
|
|
|
@property
|
|
def ports(self) -> dict[str, Port]:
|
|
return self._ports
|
|
|
|
@ports.setter
|
|
def ports(self, val: dict[str, Port]) -> None:
|
|
self._ports = val
|
|
|
|
pl = MyPorts()
|
|
pl.rename_ports({"A": "B"})
|
|
assert "A" not in pl.ports
|
|
assert "B" in pl.ports
|
|
|
|
|
|
def test_port_list_rename_missing_port_raises() -> None:
|
|
class MyPorts(PortList):
|
|
def __init__(self) -> None:
|
|
self._ports = {"A": Port((0, 0), 0)}
|
|
|
|
@property
|
|
def ports(self) -> dict[str, Port]:
|
|
return self._ports
|
|
|
|
@ports.setter
|
|
def ports(self, val: dict[str, Port]) -> None:
|
|
self._ports = val
|
|
|
|
pl = MyPorts()
|
|
with pytest.raises(PortError, match="Ports to rename were not found"):
|
|
pl.rename_ports({"missing": "B"})
|
|
assert set(pl.ports) == {"A"}
|
|
|
|
|
|
def test_port_list_add_port_pair_requires_distinct_names() -> None:
|
|
class MyPorts(PortList):
|
|
def __init__(self) -> None:
|
|
self._ports: dict[str, Port] = {}
|
|
|
|
@property
|
|
def ports(self) -> dict[str, Port]:
|
|
return self._ports
|
|
|
|
@ports.setter
|
|
def ports(self, val: dict[str, Port]) -> None:
|
|
self._ports = val
|
|
|
|
pl = MyPorts()
|
|
with pytest.raises(PortError, match="Port names must be distinct"):
|
|
pl.add_port_pair(names=("A", "A"))
|
|
assert not pl.ports
|
|
|
|
|
|
def test_port_list_plugged() -> None:
|
|
class MyPorts(PortList):
|
|
def __init__(self) -> None:
|
|
self._ports = {"A": Port((10, 10), 0), "B": Port((10, 10), pi)}
|
|
|
|
@property
|
|
def ports(self) -> dict[str, Port]:
|
|
return self._ports
|
|
|
|
@ports.setter
|
|
def ports(self, val: dict[str, Port]) -> None:
|
|
self._ports = val
|
|
|
|
pl = MyPorts()
|
|
pl.plugged({"A": "B"})
|
|
assert not pl.ports # Both should be removed
|
|
|
|
|
|
def test_port_list_plugged_empty_raises() -> None:
|
|
class MyPorts(PortList):
|
|
def __init__(self) -> None:
|
|
self._ports = {"A": Port((10, 10), 0), "B": Port((10, 10), pi)}
|
|
|
|
@property
|
|
def ports(self) -> dict[str, Port]:
|
|
return self._ports
|
|
|
|
@ports.setter
|
|
def ports(self, val: dict[str, Port]) -> None:
|
|
self._ports = val
|
|
|
|
pl = MyPorts()
|
|
with pytest.raises(PortError, match="Must provide at least one port connection"):
|
|
pl.plugged({})
|
|
assert set(pl.ports) == {"A", "B"}
|
|
|
|
|
|
def test_port_list_plugged_missing_port_raises() -> None:
|
|
class MyPorts(PortList):
|
|
def __init__(self) -> None:
|
|
self._ports = {"A": Port((10, 10), 0), "B": Port((10, 10), pi)}
|
|
|
|
@property
|
|
def ports(self) -> dict[str, Port]:
|
|
return self._ports
|
|
|
|
@ports.setter
|
|
def ports(self, val: dict[str, Port]) -> None:
|
|
self._ports = val
|
|
|
|
pl = MyPorts()
|
|
with pytest.raises(PortError, match="Connection source ports were not found"):
|
|
pl.plugged({"missing": "B"})
|
|
assert set(pl.ports) == {"A", "B"}
|
|
|
|
with pytest.raises(PortError, match="Connection destination ports were not found"):
|
|
pl.plugged({"A": "missing"})
|
|
assert set(pl.ports) == {"A", "B"}
|
|
|
|
|
|
def test_port_list_plugged_mismatch() -> None:
|
|
class MyPorts(PortList):
|
|
def __init__(self) -> None:
|
|
self._ports = {
|
|
"A": Port((10, 10), 0),
|
|
"B": Port((11, 10), pi), # Offset mismatch
|
|
}
|
|
|
|
@property
|
|
def ports(self) -> dict[str, Port]:
|
|
return self._ports
|
|
|
|
@ports.setter
|
|
def ports(self, val: dict[str, Port]) -> None:
|
|
self._ports = val
|
|
|
|
pl = MyPorts()
|
|
with pytest.raises(PortError):
|
|
pl.plugged({"A": "B"})
|