Coverage for tests / unit / tools / ruff / fix / test_timeout.py: 100%
47 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Tests for execute_ruff_fix - Timeout scenarios."""
3from __future__ import annotations
5import subprocess
6from unittest.mock import MagicMock, patch
8from assertpy import assert_that
10from lintro.tools.implementations.ruff.fix import execute_ruff_fix
13def test_execute_ruff_fix_timeout_on_initial_check(
14 mock_ruff_tool: MagicMock,
15) -> None:
16 """Return timeout result when initial check times out.
18 Args:
19 mock_ruff_tool: Mock RuffTool instance for testing.
20 """
21 with patch(
22 "lintro.tools.implementations.ruff.fix.walk_files_with_excludes",
23 ) as mock_walk:
24 mock_walk.return_value = ["test.py"]
26 mock_ruff_tool._run_subprocess.side_effect = subprocess.TimeoutExpired(
27 cmd=["ruff", "check"],
28 timeout=30,
29 )
31 result = execute_ruff_fix(mock_ruff_tool, ["test.py"])
33 assert_that(result.success).is_false()
34 assert_that(result.output).contains("timed out")
35 assert_that(result.issues_count).is_equal_to(1)
38def test_execute_ruff_fix_timeout_on_fix_command(
39 mock_ruff_tool: MagicMock,
40) -> None:
41 """Return timeout result when fix command times out.
43 Args:
44 mock_ruff_tool: Mock RuffTool instance for testing.
45 """
46 single_issue_output = """[
47 {
48 "code": "F401",
49 "message": "os imported but unused",
50 "filename": "test.py",
51 "location": {"row": 1, "column": 1},
52 "end_location": {"row": 1, "column": 10},
53 "fix": {"applicability": "safe"}
54 }
55 ]"""
57 with patch(
58 "lintro.tools.implementations.ruff.fix.walk_files_with_excludes",
59 ) as mock_walk:
60 mock_walk.return_value = ["test.py"]
62 mock_ruff_tool._run_subprocess.side_effect = [
63 (False, single_issue_output), # Initial check: 1 issue
64 subprocess.TimeoutExpired(cmd=["ruff", "check", "--fix"], timeout=30),
65 ]
67 result = execute_ruff_fix(mock_ruff_tool, ["test.py"])
69 assert_that(result.success).is_false()
70 assert_that(result.output).contains("timed out")
73def test_execute_ruff_fix_timeout_on_format_check(
74 mock_ruff_tool: MagicMock,
75) -> None:
76 """Return timeout result when format check times out.
78 Args:
79 mock_ruff_tool: Mock RuffTool instance for testing.
80 """
81 mock_ruff_tool.options["format"] = True
83 single_issue_output = """[
84 {
85 "code": "F401",
86 "message": "os imported but unused",
87 "filename": "test.py",
88 "location": {"row": 1, "column": 1},
89 "end_location": {"row": 1, "column": 10},
90 "fix": {"applicability": "safe"}
91 }
92 ]"""
94 with patch(
95 "lintro.tools.implementations.ruff.fix.walk_files_with_excludes",
96 ) as mock_walk:
97 mock_walk.return_value = ["test.py"]
99 mock_ruff_tool._run_subprocess.side_effect = [
100 (False, single_issue_output), # Initial lint check: 1 issue
101 subprocess.TimeoutExpired(cmd=["ruff", "format", "--check"], timeout=30),
102 ]
104 result = execute_ruff_fix(mock_ruff_tool, ["test.py"])
106 assert_that(result.success).is_false()
107 assert_that(result.output).contains("timed out")
110def test_execute_ruff_fix_timeout_on_format_command(
111 mock_ruff_tool: MagicMock,
112 sample_ruff_json_empty_output: str,
113) -> None:
114 """Return timeout result when format command times out.
116 Args:
117 mock_ruff_tool: Mock RuffTool instance for testing.
118 sample_ruff_json_empty_output: Sample empty JSON output from ruff.
119 """
120 mock_ruff_tool.options["format"] = True
122 # Only 1 format issue so validation passes (1 = 0 + 1)
123 single_format_issue = "Would reformat: test.py\n"
125 with patch(
126 "lintro.tools.implementations.ruff.fix.walk_files_with_excludes",
127 ) as mock_walk:
128 mock_walk.return_value = ["test.py"]
130 mock_ruff_tool._run_subprocess.side_effect = [
131 (True, sample_ruff_json_empty_output), # Initial lint check: 0 issues
132 (False, single_format_issue), # Format check: 1 file needs formatting
133 (True, sample_ruff_json_empty_output), # Lint fix
134 subprocess.TimeoutExpired(cmd=["ruff", "format"], timeout=30), # Format fix
135 ]
137 result = execute_ruff_fix(mock_ruff_tool, ["test.py"])
139 assert_that(result.success).is_false()
140 assert_that(result.output).contains("timed out")
143def test_execute_ruff_fix_timeout_on_unsafe_check_continues(
144 mock_ruff_tool: MagicMock,
145) -> None:
146 """Continue execution when unsafe fix check times out.
148 Args:
149 mock_ruff_tool: Mock RuffTool instance for testing.
150 """
151 remaining_output = """[
152 {
153 "code": "F841",
154 "message": "Local variable 'x' is assigned but never used",
155 "filename": "test.py",
156 "location": {"row": 1, "column": 1},
157 "end_location": {"row": 1, "column": 5},
158 "fix": {"applicability": "unsafe"}
159 }
160 ]"""
162 with patch(
163 "lintro.tools.implementations.ruff.fix.walk_files_with_excludes",
164 ) as mock_walk:
165 mock_walk.return_value = ["test.py"]
167 mock_ruff_tool._run_subprocess.side_effect = [
168 (False, remaining_output), # Initial check
169 (False, remaining_output), # Fix attempt
170 subprocess.TimeoutExpired(cmd=["ruff"], timeout=30), # Unsafe check timeout
171 ]
173 result = execute_ruff_fix(mock_ruff_tool, ["test.py"])
175 # Should still complete with remaining issues
176 assert_that(result.success).is_false()
177 assert_that(result.remaining_issues_count).is_equal_to(1)