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'}