122 lines
3.7 KiB
Python
122 lines
3.7 KiB
Python
from typing import Any
|
|
|
|
import pytest
|
|
import numpy
|
|
from numpy import pi
|
|
|
|
from masque import Pather, Library, Pattern, Port
|
|
from masque.builder.tools import PathTool, Tool
|
|
from masque.error import BuildError, PortError, PatternError
|
|
|
|
|
|
def test_pather_place_treeview_resolves_once() -> None:
|
|
lib = Library()
|
|
tool = PathTool(layer='M1', width=1000)
|
|
p = Pather(lib, tools=tool)
|
|
|
|
tree = {'child': Pattern(ports={'B': Port((1, 0), pi)})}
|
|
|
|
p.place(tree)
|
|
|
|
assert len(lib) == 1
|
|
assert 'child' in lib
|
|
assert 'child' in p.pattern.refs
|
|
assert 'B' in p.pattern.ports
|
|
|
|
def test_pather_plug_treeview_resolves_once() -> None:
|
|
lib = Library()
|
|
tool = PathTool(layer='M1', width=1000)
|
|
p = Pather(lib, tools=tool)
|
|
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
|
|
|
tree = {'child': Pattern(ports={'B': Port((0, 0), pi)})}
|
|
|
|
p.plug(tree, {'A': 'B'})
|
|
|
|
assert len(lib) == 1
|
|
assert 'child' in lib
|
|
assert 'child' in p.pattern.refs
|
|
assert 'A' not in p.pattern.ports
|
|
|
|
def test_pather_failed_plug_does_not_add_break_marker() -> None:
|
|
lib = Library()
|
|
tool = PathTool(layer='M1', width=1000)
|
|
p = Pather(lib, tools=tool, auto_render=False)
|
|
p.pattern.annotations = {'k': [1]}
|
|
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
|
|
|
p.at('A').trace(None, 5000)
|
|
assert [step.opcode for step in p.paths['A']] == ['L']
|
|
|
|
other = Pattern(
|
|
annotations={'k': [2]},
|
|
ports={'X': Port((0, 0), pi), 'Y': Port((5, 0), 0)},
|
|
)
|
|
|
|
with pytest.raises(PatternError, match='Annotation keys overlap'):
|
|
p.plug(other, {'A': 'X'}, map_out={'Y': 'Z'}, append=True)
|
|
|
|
assert [step.opcode for step in p.paths['A']] == ['L']
|
|
assert set(p.pattern.ports) == {'A'}
|
|
|
|
def test_pather_place_reused_deleted_name_keeps_break_marker() -> None:
|
|
lib = Library()
|
|
tool = PathTool(layer='M1', width=1000)
|
|
p = Pather(lib, tools=tool, auto_render=False)
|
|
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
|
|
|
p.at('A').straight(5000)
|
|
p.rename_ports({'A': None})
|
|
|
|
other = Pattern(ports={'X': Port((-5000, 0), rotation=0)})
|
|
p.place(other, port_map={'X': 'A'}, append=True)
|
|
p.at('A').straight(2000)
|
|
|
|
assert [step.opcode for step in p.paths['A']] == ['L', 'P', 'L']
|
|
|
|
p.render()
|
|
assert p.pattern.has_shapes()
|
|
assert 'A' in p.pattern.ports
|
|
assert numpy.allclose(p.pattern.ports['A'].offset, (-7000, 0))
|
|
|
|
def test_pather_plug_reused_deleted_name_keeps_break_marker() -> None:
|
|
lib = Library()
|
|
tool = PathTool(layer='M1', width=1000)
|
|
p = Pather(lib, tools=tool, auto_render=False)
|
|
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
|
p.pattern.ports['B'] = Port((0, 0), rotation=0)
|
|
|
|
p.at('A').straight(5000)
|
|
p.rename_ports({'A': None})
|
|
|
|
other = Pattern(
|
|
ports={
|
|
'X': Port((0, 0), rotation=pi),
|
|
'Y': Port((-5000, 0), rotation=0),
|
|
},
|
|
)
|
|
p.plug(other, {'B': 'X'}, map_out={'Y': 'A'}, append=True)
|
|
p.at('A').straight(2000)
|
|
|
|
assert [step.opcode for step in p.paths['A']] == ['L', 'P', 'L']
|
|
|
|
p.render()
|
|
assert p.pattern.has_shapes()
|
|
assert 'A' in p.pattern.ports
|
|
assert 'B' not in p.pattern.ports
|
|
assert numpy.allclose(p.pattern.ports['A'].offset, (-7000, 0))
|
|
|
|
def test_pather_failed_plugged_does_not_add_break_marker() -> None:
|
|
lib = Library()
|
|
tool = PathTool(layer='M1', width=1000)
|
|
p = Pather(lib, tools=tool, auto_render=False)
|
|
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
|
|
|
p.at('A').straight(5000)
|
|
assert [step.opcode for step in p.paths['A']] == ['L']
|
|
|
|
with pytest.raises(PortError, match='Connection destination ports were not found'):
|
|
p.plugged({'A': 'missing'})
|
|
|
|
assert [step.opcode for step in p.paths['A']] == ['L']
|
|
assert set(p.paths) == {'A'}
|