clone

a browser-first diagram editor with live svg previews, local drafts and encrypted, accountless sharing

main
diagramzip / renderers / python / symbolator / test / test_render.py
test_render.py 3.6K
1import re23import pytest45import render6from protocol import ProtocolError, parse_render_input7from render import parse_components, render_svg8910VERILOG = """module demo_device #(11parameter SIZE = 812) (13//# {{clocks|Clocking}}14input wire clock,15//# {{control|Control signals}}16input wire reset,17input wire enable,18//# {{data|Data ports}}19input wire [SIZE-1:0] data_in,20output wire [SIZE-1:0] data_out21); endmodule"""222324VHDL = """entity demo is25generic (26 SIZE : positive27);28port (29 clock : in std_logic;30 data_in : in std_logic_vector(7 downto 0);31 data_out : out std_logic_vector(7 downto 0)32);33end entity demo;"""343536def test_verilog_ports_groups_and_svg():37 components = parse_components(VERILOG)38 assert components[-1].name == "demo_device"39 assert [port.name for port in components[-1].ports] == ["clock", "reset", "enable", "data_in", "data_out"]40 svg, version = render_svg(VERILOG, {"title": "", "scale": "1.5"})41 assert version.startswith("1.2.2")42 assert 'class="fnt1"' in svg43 assert "data_in" in svg and "Clocking" in svg44 assert "stroke-width=\"3\"" in svg45 assert 'x1="-35"' in svg46 # Inputs terminate at the component's left edge; outputs start at its47 # right edge. Avoid tying this to font metrics or a particular scale.48 assert 'x1="-35"' in svg and 'x2="0"' in svg49 assert re.search(r'<line x1="[\d.]+"[^>]+x2="[\d.]+"', svg)505152def test_direction_bubbles_and_presentation_are_applied():53 source = """module m(54input wire reset_n,55output wire done56); endmodule"""57 svg, _ = render_svg(58 source,59 {"title": "", "library-name": "lib"},60 title_text="Hardware",61 description="A component",62 presentation_background="#112233",63 presentation_padding=24,64 presentation_frame=True,65 )66 assert 'cx="-35"' in svg67 assert 'fill="#112233"' in svg68 assert "Hardware" in svg and "A component" in svg69 assert "stroke=\"#000\"" in svg70 assert re.search(r'viewBox="-7[45] -59 ', svg)717273def test_compact_ansi_header_keeps_both_directions():74 components = parse_components("module m(input wire reset_n, output wire done); endmodule")75 assert [(port.name, port.direction) for port in components[-1].ports] == [76 ("reset_n", "in"),77 ("done", "out"),78 ]798081def test_protocol_rejects_unknown_and_invalid_options():82 def parse(options):83 import json84 return parse_render_input(json.dumps({"source": "module m; endmodule", "options": options}))8586 with pytest.raises(ProtocolError, match="Unknown renderer option"):87 parse({"bogus": "1"})88 with pytest.raises(ProtocolError, match="finite"):89 parse({"scale": "nan"})90 with pytest.raises(ProtocolError, match="finite"):91 parse({"scale": "inf"})92 with pytest.raises(ProtocolError, match="requires"):93 parse({"library-name": "lib"})949596def test_render_size_is_bounded(monkeypatch):97 monkeypatch.setattr(render, "MAX_SVG_LENGTH", 100)98 with pytest.raises(ProtocolError, match="too large"):99 render_svg("module m(input wire clock); endmodule")100101102def test_vhdl_generics_and_bus_types():103 components = parse_components(VHDL)104 assert components[-1].generics[0].name == "SIZE"105 svg, _ = render_svg(VHDL, {"no-type": "true", "transparent": "true"})106 assert "data_out" in svg107 assert "fill=\"white\"" not in svg108109110def test_component_filter_and_missing_component():111 svg, _ = render_svg(VERILOG, {"component": "demo_device"})112 assert "demo_device" not in svg or "data_out" in svg113 try:114 render_svg(VERILOG, {"component": "missing"})115 except Exception as error:116 assert "not found" in str(error)