1+ """
2+ Tests for quality_tools module.
3+ """
4+ import os
5+ import subprocess
6+ import pytest
7+ from unittest .mock import patch , MagicMock
8+
9+ # Direct import for coverage tracking
10+ import src .cli_code .tools .quality_tools
11+ from src .cli_code .tools .quality_tools import (
12+ _run_quality_command ,
13+ LinterCheckerTool ,
14+ FormatterTool
15+ )
16+
17+
18+ def test_linter_checker_tool_init ():
19+ """Test LinterCheckerTool initialization."""
20+ tool = LinterCheckerTool ()
21+ assert tool .name == "linter_checker"
22+ assert "Runs a code linter" in tool .description
23+
24+
25+ def test_formatter_tool_init ():
26+ """Test FormatterTool initialization."""
27+ tool = FormatterTool ()
28+ assert tool .name == "formatter"
29+ assert "Runs a code formatter" in tool .description
30+
31+
32+ @patch ("subprocess.run" )
33+ def test_run_quality_command_success (mock_run ):
34+ """Test _run_quality_command with successful command execution."""
35+ # Setup mock
36+ mock_process = MagicMock ()
37+ mock_process .returncode = 0
38+ mock_process .stdout = "Command output"
39+ mock_process .stderr = ""
40+ mock_run .return_value = mock_process
41+
42+ # Execute function
43+ result = _run_quality_command (["test" , "command" ], "TestTool" )
44+
45+ # Verify results
46+ assert "TestTool Result (Exit Code: 0)" in result
47+ assert "Command output" in result
48+ assert "-- Errors --" not in result
49+ mock_run .assert_called_once_with (
50+ ["test" , "command" ],
51+ capture_output = True ,
52+ text = True ,
53+ check = False ,
54+ timeout = 120
55+ )
56+
57+
58+ @patch ("subprocess.run" )
59+ def test_run_quality_command_with_errors (mock_run ):
60+ """Test _run_quality_command with command that outputs errors."""
61+ # Setup mock
62+ mock_process = MagicMock ()
63+ mock_process .returncode = 1
64+ mock_process .stdout = "Command output"
65+ mock_process .stderr = "Error message"
66+ mock_run .return_value = mock_process
67+
68+ # Execute function
69+ result = _run_quality_command (["test" , "command" ], "TestTool" )
70+
71+ # Verify results
72+ assert "TestTool Result (Exit Code: 1)" in result
73+ assert "Command output" in result
74+ assert "-- Errors --" in result
75+ assert "Error message" in result
76+
77+
78+ @patch ("subprocess.run" )
79+ def test_run_quality_command_no_output (mock_run ):
80+ """Test _run_quality_command with command that produces no output."""
81+ # Setup mock
82+ mock_process = MagicMock ()
83+ mock_process .returncode = 0
84+ mock_process .stdout = ""
85+ mock_process .stderr = ""
86+ mock_run .return_value = mock_process
87+
88+ # Execute function
89+ result = _run_quality_command (["test" , "command" ], "TestTool" )
90+
91+ # Verify results
92+ assert "TestTool Result (Exit Code: 0)" in result
93+ assert "(No output)" in result
94+
95+
96+ @patch ("subprocess.run" )
97+ def test_run_quality_command_long_output (mock_run ):
98+ """Test _run_quality_command with command that produces very long output."""
99+ # Setup mock
100+ mock_process = MagicMock ()
101+ mock_process .returncode = 0
102+ mock_process .stdout = "A" * 3000 # Longer than 2000 char limit
103+ mock_process .stderr = ""
104+ mock_run .return_value = mock_process
105+
106+ # Execute function
107+ result = _run_quality_command (["test" , "command" ], "TestTool" )
108+
109+ # Verify results
110+ assert "... (output truncated)" in result
111+ assert len (result ) < 3000
112+
113+
114+ def test_run_quality_command_file_not_found ():
115+ """Test _run_quality_command with non-existent command."""
116+ # Set up side effect
117+ with patch ("subprocess.run" , side_effect = FileNotFoundError ("No such file or directory: 'nonexistent'" )):
118+ # Execute function
119+ result = _run_quality_command (["nonexistent" ], "TestTool" )
120+
121+ # Verify results
122+ assert "Error: Command 'nonexistent' not found" in result
123+ assert "Is 'nonexistent' installed and in PATH?" in result
124+
125+
126+ def test_run_quality_command_timeout ():
127+ """Test _run_quality_command with command that times out."""
128+ # Set up side effect
129+ with patch ("subprocess.run" , side_effect = subprocess .TimeoutExpired (cmd = "slow_command" , timeout = 120 )):
130+ # Execute function
131+ result = _run_quality_command (["slow_command" ], "TestTool" )
132+
133+ # Verify results
134+ assert "Error: TestTool run timed out" in result
135+ assert "2 minutes" in result
136+
137+
138+ def test_run_quality_command_unexpected_error ():
139+ """Test _run_quality_command with unexpected error."""
140+ # Set up side effect
141+ with patch ("subprocess.run" , side_effect = Exception ("Unexpected error" )):
142+ # Execute function
143+ result = _run_quality_command (["command" ], "TestTool" )
144+
145+ # Verify results
146+ assert "Error running TestTool" in result
147+ assert "Unexpected error" in result
148+
149+
150+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
151+ def test_linter_checker_with_defaults (mock_run_command ):
152+ """Test LinterCheckerTool with default parameters."""
153+ # Setup mock
154+ mock_run_command .return_value = "Linter output"
155+
156+ # Execute tool
157+ tool = LinterCheckerTool ()
158+ result = tool .execute ()
159+
160+ # Verify results
161+ assert result == "Linter output"
162+ mock_run_command .assert_called_once ()
163+ args , kwargs = mock_run_command .call_args
164+ assert args [0 ] == ["ruff" , "check" , os .path .abspath ("." )]
165+ assert args [1 ] == "Linter"
166+
167+
168+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
169+ def test_linter_checker_with_custom_path (mock_run_command ):
170+ """Test LinterCheckerTool with custom path."""
171+ # Setup mock
172+ mock_run_command .return_value = "Linter output"
173+
174+ # Execute tool
175+ tool = LinterCheckerTool ()
176+ result = tool .execute (path = "src" )
177+
178+ # Verify results
179+ assert result == "Linter output"
180+ mock_run_command .assert_called_once ()
181+ args , kwargs = mock_run_command .call_args
182+ assert args [0 ] == ["ruff" , "check" , os .path .abspath ("src" )]
183+
184+
185+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
186+ def test_linter_checker_with_custom_command (mock_run_command ):
187+ """Test LinterCheckerTool with custom linter command."""
188+ # Setup mock
189+ mock_run_command .return_value = "Linter output"
190+
191+ # Execute tool
192+ tool = LinterCheckerTool ()
193+ result = tool .execute (linter_command = "flake8" )
194+
195+ # Verify results
196+ assert result == "Linter output"
197+ mock_run_command .assert_called_once ()
198+ args , kwargs = mock_run_command .call_args
199+ assert args [0 ] == ["flake8" , os .path .abspath ("." )]
200+
201+
202+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
203+ def test_linter_checker_with_complex_command (mock_run_command ):
204+ """Test LinterCheckerTool with complex command including arguments."""
205+ # Setup mock
206+ mock_run_command .return_value = "Linter output"
207+
208+ # Execute tool
209+ tool = LinterCheckerTool ()
210+ result = tool .execute (linter_command = "flake8 --max-line-length=100" )
211+
212+ # Verify results
213+ assert result == "Linter output"
214+ mock_run_command .assert_called_once ()
215+ args , kwargs = mock_run_command .call_args
216+ assert args [0 ] == ["flake8" , "--max-line-length=100" , os .path .abspath ("." )]
217+
218+
219+ def test_linter_checker_with_parent_directory_traversal ():
220+ """Test LinterCheckerTool with path containing parent directory traversal."""
221+ tool = LinterCheckerTool ()
222+ result = tool .execute (path = "../dangerous" )
223+
224+ # Verify results
225+ assert "Error: Invalid path" in result
226+ assert "Cannot access parent directories" in result
227+
228+
229+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
230+ def test_formatter_with_defaults (mock_run_command ):
231+ """Test FormatterTool with default parameters."""
232+ # Setup mock
233+ mock_run_command .return_value = "Formatter output"
234+
235+ # Execute tool
236+ tool = FormatterTool ()
237+ result = tool .execute ()
238+
239+ # Verify results
240+ assert result == "Formatter output"
241+ mock_run_command .assert_called_once ()
242+ args , kwargs = mock_run_command .call_args
243+ assert args [0 ] == ["black" , os .path .abspath ("." )]
244+ assert args [1 ] == "Formatter"
245+
246+
247+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
248+ def test_formatter_with_custom_path (mock_run_command ):
249+ """Test FormatterTool with custom path."""
250+ # Setup mock
251+ mock_run_command .return_value = "Formatter output"
252+
253+ # Execute tool
254+ tool = FormatterTool ()
255+ result = tool .execute (path = "src" )
256+
257+ # Verify results
258+ assert result == "Formatter output"
259+ mock_run_command .assert_called_once ()
260+ args , kwargs = mock_run_command .call_args
261+ assert args [0 ] == ["black" , os .path .abspath ("src" )]
262+
263+
264+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
265+ def test_formatter_with_custom_command (mock_run_command ):
266+ """Test FormatterTool with custom formatter command."""
267+ # Setup mock
268+ mock_run_command .return_value = "Formatter output"
269+
270+ # Execute tool
271+ tool = FormatterTool ()
272+ result = tool .execute (formatter_command = "prettier" )
273+
274+ # Verify results
275+ assert result == "Formatter output"
276+ mock_run_command .assert_called_once ()
277+ args , kwargs = mock_run_command .call_args
278+ assert args [0 ] == ["prettier" , os .path .abspath ("." )]
279+
280+
281+ @patch ("src.cli_code.tools.quality_tools._run_quality_command" )
282+ def test_formatter_with_complex_command (mock_run_command ):
283+ """Test FormatterTool with complex command including arguments."""
284+ # Setup mock
285+ mock_run_command .return_value = "Formatter output"
286+
287+ # Execute tool
288+ tool = FormatterTool ()
289+ result = tool .execute (formatter_command = "prettier --write" )
290+
291+ # Verify results
292+ assert result == "Formatter output"
293+ mock_run_command .assert_called_once ()
294+ args , kwargs = mock_run_command .call_args
295+ assert args [0 ] == ["prettier" , "--write" , os .path .abspath ("." )]
296+
297+
298+ def test_formatter_with_parent_directory_traversal ():
299+ """Test FormatterTool with path containing parent directory traversal."""
300+ tool = FormatterTool ()
301+ result = tool .execute (path = "../dangerous" )
302+
303+ # Verify results
304+ assert "Error: Invalid path" in result
305+ assert "Cannot access parent directories" in result
0 commit comments