""" MCP text drawing tests: SVG builder units and handler behavior. """ from unittest.mock import MagicMock, patch from xml.etree import ElementTree as ET import pytest from gns3server.agent.mcp.drawings import build_text_svg, create_text_drawing_handler BASE = "gns3server.agent.mcp" def _mock_conn(json_result=None): """Create a mocked Gns3Connector with base_url and http_call.""" conn = MagicMock() conn.base_url = "http://192.168.1.3:3080/v3" conn.http_call.return_value.json.return_value = json_result or {"status": "ok"} return conn @pytest.fixture def ctx(): return {"server_url": "http://192.168.1.3:3080", "jwt_token": "token", "jwt_username": "admin"} class TestBuildTextSvg: def test_single_line(self): svg, width, height, line_height = build_text_svg("R1", font_size=13) assert svg == ( '' 'R1' ) # 2 chars x 13 x 0.8 = 20.8 -> 21; one line of 13 x 1.9 = 24.7 -> 25 assert width == 21 assert height == 25 assert line_height == 25 def test_bold_and_color(self): svg, _, _, _ = build_text_svg("R1", font_size=13, color="#CC0000", bold=True) assert 'fill="#CC0000"' in svg assert 'font-weight="bold"' in svg def test_escapes_xml_characters(self): svg, _, _, _ = build_text_svg("a mono_w def test_empty_line_kept(self): # a blank line still occupies a line box _, _, height, line_height = build_text_svg("a\n\nb", font_size=10) assert height == 3 * line_height def test_matches_web_ui_serializer_shape(self): # byte-for-byte structural parity with the Web UI's own text output svg, width, height, _ = build_text_svg("demo", font_size=11) assert svg.startswith(f'", "a&b", ""]) def test_bad_font_family(self, ctx, font_family): result = create_text_drawing_handler({"project_id": "p1", "text": "R1", "font_family": font_family}, ctx) assert "error" in result def test_font_family_with_spaces_accepted(self, ctx): with patch(f"{BASE}.drawings._get_connector") as m: conn = _mock_conn({"drawing_id": "d1"}) m.return_value = conn result = create_text_drawing_handler( {"project_id": "p1", "text": "R1", "font_family": "DejaVu Sans Mono"}, ctx ) assert "error" not in result def test_xml_entities_survive_round_trip(self, ctx): with patch(f"{BASE}.drawings._get_connector") as m: conn = _mock_conn({"drawing_id": "d1"}) m.return_value = conn create_text_drawing_handler({"project_id": "p1", "text": "R1 & "}, ctx) svg = conn.http_call.call_args.kwargs["json_data"]["svg"] assert "R1 & <backup>" in svg ET.fromstring(svg)