Coverage for tests / unit / cli / test_rich_cli.py: 100%
161 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 unittest.mock import patch
4from typer.testing import CliRunner
6from graphable.cli.rich_cli import app
7from graphable.enums import Engine
9runner = CliRunner()
12@patch("graphable.cli.rich_cli.info_command")
13def test_rich_cli_info(mock_info):
14 """Verify info command in Rich CLI."""
15 mock_info.return_value = {
16 "nodes": 2,
17 "edges": 1,
18 "sources": ["A"],
19 "sinks": ["B"],
20 "project_duration": 10.0,
21 "critical_path_length": 2,
22 }
23 result = runner.invoke(app, ["info", "test.json"])
24 assert result.exit_code == 0
25 assert "Nodes" in result.stdout
26 assert "Edges" in result.stdout
27 assert "Sources" in result.stdout
28 assert "Sinks" in result.stdout
29 assert "Project Duration" in result.stdout
30 assert "Critical Path Length" in result.stdout
31 mock_info.assert_called_once_with(
32 Path("test.json"), tag=None, upstream_of=None, downstream_of=None
33 )
36@patch("graphable.cli.rich_cli.info_command")
37def test_rich_cli_info_error(mock_info):
38 """Verify info command handles error in Rich CLI."""
39 mock_info.side_effect = Exception("Test error")
40 result = runner.invoke(app, ["info", "test.json"])
41 assert result.exit_code == 1
42 assert "Error:" in result.stdout
43 assert "Test error" in result.stdout
46@patch("graphable.cli.rich_cli.check_command")
47def test_rich_cli_check_valid(mock_check):
48 """Verify check command (valid) in Rich CLI."""
49 mock_check.return_value = {"valid": True, "error": None}
50 result = runner.invoke(app, ["check", "test.json"])
51 assert result.exit_code == 0
52 assert "Graph is valid!" in result.stdout
55@patch("graphable.cli.rich_cli.check_command")
56def test_rich_cli_check_invalid(mock_check):
57 """Verify check command (invalid) in Rich CLI."""
58 mock_check.return_value = {"valid": False, "error": "Test error"}
59 result = runner.invoke(app, ["check", "test.json"])
60 assert result.exit_code == 1
61 assert "Graph is invalid:" in result.stdout
62 assert "Test error" in result.stdout
65@patch("graphable.cli.rich_cli.reduce_command")
66def test_rich_cli_reduce(mock_reduce):
67 """Verify reduce command in Rich CLI."""
68 result = runner.invoke(app, ["reduce", "input.json", "output.json"])
69 assert result.exit_code == 0
70 assert "Successfully reduced graph" in result.stdout
71 mock_reduce.assert_called_once_with(
72 Path("input.json"),
73 Path("output.json"),
74 embed_checksum=False,
75 tag=None,
76 upstream_of=None,
77 downstream_of=None,
78 )
81@patch("graphable.cli.rich_cli.convert_command")
82def test_rich_cli_convert(mock_convert):
83 """Verify convert command in Rich CLI."""
84 result = runner.invoke(app, ["convert", "input.json", "output.yaml"])
85 assert result.exit_code == 0
86 assert "Successfully converted" in result.stdout
87 mock_convert.assert_called_once_with(
88 Path("input.json"),
89 Path("output.yaml"),
90 embed_checksum=False,
91 tag=None,
92 upstream_of=None,
93 downstream_of=None,
94 )
97@patch("graphable.cli.rich_cli.render_command")
98def test_rich_cli_render(mock_render):
99 """Verify render command in Rich CLI."""
100 result = runner.invoke(app, ["render", "i.json", "o.png", "--engine", "mermaid"])
101 assert result.exit_code == 0
102 assert "Successfully rendered" in result.stdout
103 mock_render.assert_called_once()
104 # Check that engine is passed correctly
105 args, kwargs = mock_render.call_args
106 assert kwargs["engine"] == Engine.MERMAID
109@patch("graphable.cli.rich_cli.render_command")
110def test_rich_cli_render_error(mock_render):
111 """Verify render command error handling in Rich CLI."""
112 mock_render.side_effect = Exception("Render error")
113 result = runner.invoke(app, ["render", "i.json", "o.png"])
114 assert result.exit_code == 1
115 assert "Error:" in result.stdout
116 assert "Render error" in result.stdout
119@patch("graphable.cli.rich_cli.checksum_command")
120def test_rich_cli_checksum(mock_checksum):
121 """Verify checksum command in Rich CLI."""
122 mock_checksum.return_value = "abcdef123456"
123 result = runner.invoke(app, ["checksum", "test.json"])
124 assert result.exit_code == 0
125 assert "abcdef123456" in result.stdout
128@patch("graphable.cli.rich_cli.checksum_command")
129def test_rich_cli_checksum_error(mock_checksum):
130 """Verify checksum command error handling in Rich CLI."""
131 mock_checksum.side_effect = Exception("Checksum error")
132 result = runner.invoke(app, ["checksum", "test.json"])
133 assert result.exit_code == 1
134 assert "Error:" in result.stdout
135 assert "Checksum error" in result.stdout
138@patch("graphable.cli.rich_cli.verify_command")
139def test_rich_cli_verify_success(mock_verify):
140 """Verify verify command (success) in Rich CLI."""
141 mock_verify.return_value = {"valid": True, "actual": "abc", "expected": "abc"}
142 result = runner.invoke(app, ["verify", "test.json"])
143 assert result.exit_code == 0
144 assert "Checksum verified successfully." in result.stdout
145 mock_verify.assert_called_once_with(
146 Path("test.json"), None, tag=None, upstream_of=None, downstream_of=None
147 )
150@patch("graphable.cli.rich_cli.verify_command")
151def test_rich_cli_verify_mismatch(mock_verify):
152 """Verify verify command (mismatch) in Rich CLI."""
153 mock_verify.return_value = {"valid": False, "actual": "abc", "expected": "def"}
154 result = runner.invoke(app, ["verify", "test.json"])
155 assert result.exit_code == 1
156 assert "Checksum mismatch!" in result.stdout
159@patch("graphable.cli.rich_cli.verify_command")
160def test_rich_cli_verify_no_checksum(mock_verify):
161 """Verify verify command (no checksum) in Rich CLI."""
162 mock_verify.return_value = {"valid": None, "actual": "abc", "expected": None}
163 result = runner.invoke(app, ["verify", "test.json"])
164 assert result.exit_code == 0
165 assert "No checksum found to verify." in result.stdout
168@patch("graphable.cli.rich_cli.verify_command")
169def test_rich_cli_verify_error(mock_verify):
170 """Verify verify command error handling in Rich CLI."""
171 mock_verify.side_effect = Exception("Verify error")
172 result = runner.invoke(app, ["verify", "test.json"])
173 assert result.exit_code == 1
174 assert "Error:" in result.stdout
175 assert "Verify error" in result.stdout
178@patch("graphable.cli.rich_cli.write_checksum_command")
179def test_rich_cli_write_checksum(mock_write):
180 """Verify write-checksum command in Rich CLI."""
181 result = runner.invoke(app, ["write-checksum", "test.json", "test.blake2b"])
182 assert result.exit_code == 0
183 assert "Checksum written to" in result.stdout
184 mock_write.assert_called_once_with(
185 Path("test.json"),
186 Path("test.blake2b"),
187 tag=None,
188 upstream_of=None,
189 downstream_of=None,
190 )
193@patch("graphable.cli.rich_cli.write_checksum_command")
194def test_rich_cli_write_checksum_error(mock_write):
195 """Verify write-checksum command error handling in Rich CLI."""
196 mock_write.side_effect = Exception("Write error")
197 result = runner.invoke(app, ["write-checksum", "test.json", "test.blake2b"])
198 assert result.exit_code == 1
199 assert "Error:" in result.stdout
200 assert "Write error" in result.stdout
203@patch("graphable.cli.rich_cli.diff_command")
204def test_rich_cli_diff(mock_diff):
205 """Verify diff command in Rich CLI."""
206 mock_diff.return_value = {
207 "added_nodes": ["C"],
208 "removed_nodes": ["A"],
209 "modified_nodes": ["B"],
210 "added_edges": [("B", "C")],
211 "removed_edges": [("A", "B")],
212 "modified_edges": [("X", "Y")],
213 }
214 result = runner.invoke(app, ["diff", "v1.json", "v2.json"])
215 assert result.exit_code == 0
216 assert "Graph Diff" in result.stdout
217 assert "Added Nodes" in result.stdout
218 assert "Removed Nodes" in result.stdout
219 assert "Modified Nodes" in result.stdout
220 assert "Added Edges" in result.stdout
221 assert "Removed Edges" in result.stdout
222 assert "Modified Edges" in result.stdout
225@patch("graphable.cli.rich_cli.diff_visual_command")
226def test_rich_cli_diff_visual(mock_diff_visual):
227 """Verify diff command with output (visual) in Rich CLI."""
228 result = runner.invoke(app, ["diff", "v1.json", "v2.json", "--output", "diff.svg"])
229 assert result.exit_code == 0
230 assert "Visual diff saved to" in result.stdout
231 mock_diff_visual.assert_called_once_with(
232 Path("v1.json"), Path("v2.json"), Path("diff.svg"), tag=None
233 )
236@patch("graphable.cli.rich_cli.diff_command")
237def test_rich_cli_diff_identical(mock_diff):
238 """Verify diff command (identical) in Rich CLI."""
239 mock_diff.return_value = {
240 "added_nodes": set(),
241 "removed_nodes": set(),
242 "modified_nodes": set(),
243 "added_edges": set(),
244 "removed_edges": set(),
245 "modified_edges": set(),
246 }
247 result = runner.invoke(app, ["diff", "v1.json", "v2.json"])
248 assert result.exit_code == 0
249 assert "Graphs are identical." in result.stdout
252@patch("graphable.cli.rich_cli.diff_command")
253def test_rich_cli_diff_error(mock_diff):
254 """Verify diff command error handling in Rich CLI."""
255 mock_diff.side_effect = Exception("Diff error")
256 result = runner.invoke(app, ["diff", "v1.json", "v2.json"])
257 assert result.exit_code == 1
258 assert "Error:" in result.stdout
259 assert "Diff error" in result.stdout
262@patch("graphable.cli.rich_cli.serve_command")
263def test_rich_cli_serve(mock_serve):
264 """Verify serve command in Rich CLI."""
265 result = runner.invoke(app, ["serve", "test.json", "--port", "8080"])
266 assert result.exit_code == 0
267 assert "Serving" in result.stdout
268 mock_serve.assert_called_once_with(Path("test.json"), port=8080)
271@patch("graphable.cli.rich_cli.serve_command")
272def test_rich_cli_serve_error(mock_serve):
273 """Verify serve command error handling in Rich CLI."""
274 mock_serve.side_effect = Exception("Serve error")
275 result = runner.invoke(app, ["serve", "test.json"])
276 assert result.exit_code == 1
277 assert "Error:" in result.stdout
278 assert "Serve error" in result.stdout