Coverage for tests / unit / views / test_plantuml.py: 100%
110 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-16 21:32 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-16 21:32 +0000
1from pathlib import Path
2from subprocess import CalledProcessError
3from unittest.mock import MagicMock, mock_open, patch
5from pytest import fixture, raises
7from graphable.graph import Graph
8from graphable.graphable import Graphable
9from graphable.views.plantuml import (
10 PlantUmlStylingConfig,
11 _check_plantuml_on_path,
12 create_topology_plantuml,
13 export_topology_plantuml,
14 export_topology_plantuml_image,
15)
18class TestPlantUML:
19 @fixture
20 def graph_fixture(self):
21 a = Graphable("A")
22 b = Graphable("B")
23 g = Graph()
24 g.add_edge(a, b)
25 return g, a, b
27 def test_create_topology_plantuml_default(self, graph_fixture):
28 g, a, b = graph_fixture
29 puml = create_topology_plantuml(g)
31 assert "@startuml" in puml
32 assert 'node "A" as' in puml
33 assert 'node "B" as' in puml
34 assert "-->" in puml
35 assert "@enduml" in puml
37 def test_create_topology_plantuml_custom_config(self, graph_fixture):
38 g, a, b = graph_fixture
39 config = PlantUmlStylingConfig(
40 node_ref_fnc=lambda n: n.reference,
41 node_type="component",
42 direction="left to right direction",
43 )
44 puml = create_topology_plantuml(g, config)
46 assert "left to right" in puml
47 assert 'component "A" as A' in puml
48 assert "A --> B" in puml
50 def test_export_topology_plantuml(self, graph_fixture):
51 g, _, _ = graph_fixture
52 output_path = Path("output.puml")
54 with patch("builtins.open", mock_open()) as mock_file:
55 export_topology_plantuml(g, output_path)
57 mock_file.assert_called_with(output_path, "w+")
58 mock_file().write.assert_called()
60 @patch("graphable.views.plantuml.which")
61 def test_check_plantuml_on_path_success(self, mock_which):
62 mock_which.return_value = "/usr/bin/plantuml"
63 _check_plantuml_on_path() # Should not raise
65 @patch("graphable.views.plantuml.which")
66 def test_check_plantuml_on_path_failure(self, mock_which):
67 mock_which.return_value = None
68 with raises(FileNotFoundError):
69 _check_plantuml_on_path()
71 @patch("graphable.views.plantuml.run")
72 @patch("graphable.views.plantuml._check_plantuml_on_path")
73 @patch("builtins.open", new_callable=mock_open)
74 def test_export_topology_plantuml_image_svg_success(
75 self, mock_file, mock_check, mock_run, graph_fixture
76 ):
77 g, _, _ = graph_fixture
78 output_path = Path("output.svg")
80 mock_run.return_value = MagicMock()
82 export_topology_plantuml_image(g, output_path)
84 mock_check.assert_called_once()
85 mock_run.assert_called_once()
86 args, kwargs = mock_run.call_args
87 assert "plantuml" in args[0]
88 assert "-tsvg" in args[0]
90 @patch("graphable.views.plantuml.run")
91 @patch("graphable.views.plantuml._check_plantuml_on_path")
92 @patch("builtins.open", new_callable=mock_open)
93 def test_export_topology_plantuml_image_png_success(
94 self, mock_file, mock_check, mock_run, graph_fixture
95 ):
96 g, _, _ = graph_fixture
97 output_path = Path("output.png")
99 mock_run.return_value = MagicMock()
101 export_topology_plantuml_image(g, output_path)
103 mock_check.assert_called_once()
104 mock_run.assert_called_once()
105 args, kwargs = mock_run.call_args
106 assert "plantuml" in args[0]
107 assert "-tpng" in args[0]
109 @patch("graphable.views.plantuml.run")
110 @patch("graphable.views.plantuml._check_plantuml_on_path")
111 @patch("builtins.open", new_callable=mock_open)
112 def test_export_topology_plantuml_image_failure(
113 self, mock_file, mock_check, mock_run, graph_fixture
114 ):
115 g, _, _ = graph_fixture
116 output_path = Path("output.svg")
118 mock_run.side_effect = CalledProcessError(1, "plantuml", stderr="error")
120 with raises(CalledProcessError):
121 export_topology_plantuml_image(g, output_path)
123 @patch("graphable.views.plantuml.run")
124 @patch("graphable.views.plantuml._check_plantuml_on_path")
125 @patch("builtins.open", new_callable=mock_open)
126 def test_export_topology_plantuml_image_generic_exception(
127 self, mock_file, mock_check, mock_run, graph_fixture
128 ):
129 g, _, _ = graph_fixture
130 output_path = Path("output.svg")
132 mock_run.side_effect = Exception("generic error")
134 with raises(Exception):
135 export_topology_plantuml_image(g, output_path)
137 def test_create_topology_plantuml_clustering(self):
138 a = Graphable("A")
139 a.add_tag("group1")
140 b = Graphable("B")
141 b.add_tag("group1")
142 c = Graphable("C")
143 c.add_tag("group2")
145 g = Graph()
146 g.add_edge(a, b)
147 g.add_edge(b, c)
149 from graphable.views.plantuml import PlantUmlStylingConfig
151 config = PlantUmlStylingConfig(
152 cluster_by_tag=True, node_ref_fnc=lambda n: n.reference
153 )
155 puml = create_topology_plantuml(g, config)
157 assert 'package "group1" {' in puml
158 assert 'package "group2" {' in puml
159 assert 'node "A" as A' in puml
160 assert 'node "B" as B' in puml
161 assert 'node "C" as C' in puml
162 assert "A --> B" in puml
163 assert "B --> C" in puml