Coverage for tests / unit / tools / rustfmt / test_execution.py: 100%
82 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"""Unit tests for rustfmt plugin execution."""
3from __future__ import annotations
5from pathlib import Path
6from unittest.mock import patch
8from assertpy import assert_that
10from lintro.tools.definitions.rustfmt import RustfmtPlugin
12# =============================================================================
13# Tests for RustfmtPlugin.check method
14# =============================================================================
17def test_check_no_cargo_toml(
18 rustfmt_plugin: RustfmtPlugin,
19 tmp_path: Path,
20) -> None:
21 """Check skips gracefully when no Cargo.toml found.
23 Args:
24 rustfmt_plugin: The RustfmtPlugin instance to test.
25 tmp_path: Temporary directory path for test files.
26 """
27 test_file = tmp_path / "test.rs"
28 test_file.write_text("fn main() {}")
30 with patch(
31 "lintro.plugins.execution_preparation.verify_tool_version",
32 return_value=None,
33 ):
34 result = rustfmt_plugin.check([str(test_file)], {})
36 assert_that(result.success).is_true()
37 assert_that(result.output).contains("No Cargo.toml found")
40def test_check_with_mocked_subprocess_success(
41 rustfmt_plugin: RustfmtPlugin,
42 tmp_path: Path,
43) -> None:
44 """Check returns success when no issues found.
46 Args:
47 rustfmt_plugin: The RustfmtPlugin instance to test.
48 tmp_path: Temporary directory path for test files.
49 """
50 # Create Cargo.toml to enable rustfmt check
51 cargo_toml = tmp_path / "Cargo.toml"
52 cargo_toml.write_text('[package]\nname = "test"\nversion = "0.1.0"')
54 test_file = tmp_path / "src" / "main.rs"
55 test_file.parent.mkdir(parents=True, exist_ok=True)
56 test_file.write_text("fn main() {}\n")
58 with patch(
59 "lintro.plugins.execution_preparation.verify_tool_version",
60 return_value=None,
61 ):
62 with patch.object(
63 rustfmt_plugin,
64 "_run_subprocess",
65 return_value=(True, ""),
66 ):
67 result = rustfmt_plugin.check([str(test_file)], {})
69 assert_that(result.success).is_true()
70 assert_that(result.issues_count).is_equal_to(0)
73def test_check_with_mocked_subprocess_issues(
74 rustfmt_plugin: RustfmtPlugin,
75 tmp_path: Path,
76) -> None:
77 """Check returns issues when formatting problems found.
79 Args:
80 rustfmt_plugin: The RustfmtPlugin instance to test.
81 tmp_path: Temporary directory path for test files.
82 """
83 cargo_toml = tmp_path / "Cargo.toml"
84 cargo_toml.write_text('[package]\nname = "test"\nversion = "0.1.0"')
86 test_file = tmp_path / "src" / "main.rs"
87 test_file.parent.mkdir(parents=True, exist_ok=True)
88 test_file.write_text("fn main(){let x=1;}")
90 mock_output = (
91 "Diff in src/main.rs:1:\n"
92 "-fn main(){let x=1;}\n"
93 "+fn main() {\n"
94 "+ let x = 1;\n"
95 "+}"
96 )
98 with patch(
99 "lintro.plugins.execution_preparation.verify_tool_version",
100 return_value=None,
101 ):
102 with patch.object(
103 rustfmt_plugin,
104 "_run_subprocess",
105 return_value=(False, mock_output),
106 ):
107 result = rustfmt_plugin.check([str(test_file)], {})
109 assert_that(result.success).is_false()
110 assert_that(result.issues_count).is_greater_than(0)
113def test_check_with_no_rust_files(
114 rustfmt_plugin: RustfmtPlugin,
115 tmp_path: Path,
116) -> None:
117 """Check returns success when no Rust files found.
119 Args:
120 rustfmt_plugin: The RustfmtPlugin instance to test.
121 tmp_path: Temporary directory path for test files.
122 """
123 non_rs_file = tmp_path / "test.txt"
124 non_rs_file.write_text("Not a Rust file")
126 with patch(
127 "lintro.plugins.execution_preparation.verify_tool_version",
128 return_value=None,
129 ):
130 result = rustfmt_plugin.check([str(non_rs_file)], {})
132 assert_that(result.success).is_true()
133 assert_that(result.output).contains("No")
136# =============================================================================
137# Tests for RustfmtPlugin.fix method
138# =============================================================================
141def test_fix_no_cargo_toml(
142 rustfmt_plugin: RustfmtPlugin,
143 tmp_path: Path,
144) -> None:
145 """Fix skips gracefully when no Cargo.toml found.
147 Args:
148 rustfmt_plugin: The RustfmtPlugin instance to test.
149 tmp_path: Temporary directory path for test files.
150 """
151 test_file = tmp_path / "test.rs"
152 test_file.write_text("fn main() {}")
154 with patch(
155 "lintro.plugins.execution_preparation.verify_tool_version",
156 return_value=None,
157 ):
158 result = rustfmt_plugin.fix([str(test_file)], {})
160 assert_that(result.success).is_true()
161 assert_that(result.output).contains("No Cargo.toml found")
162 assert_that(result.fixed_issues_count).is_equal_to(0)
165def test_fix_with_mocked_subprocess_success(
166 rustfmt_plugin: RustfmtPlugin,
167 tmp_path: Path,
168) -> None:
169 """Fix returns success when fixes are applied.
171 Args:
172 rustfmt_plugin: The RustfmtPlugin instance to test.
173 tmp_path: Temporary directory path for test files.
174 """
175 cargo_toml = tmp_path / "Cargo.toml"
176 cargo_toml.write_text('[package]\nname = "test"\nversion = "0.1.0"')
178 test_file = tmp_path / "src" / "main.rs"
179 test_file.parent.mkdir(parents=True, exist_ok=True)
180 test_file.write_text("fn main(){}")
182 call_count = 0
184 def mock_run(
185 cmd: list[str],
186 timeout: int,
187 cwd: str | None = None,
188 ) -> tuple[bool, str]:
189 """Mock subprocess that returns diff on check, success on fix.
191 Args:
192 cmd: Command list.
193 timeout: Timeout in seconds.
194 cwd: Working directory.
196 Returns:
197 Tuple of (success, output).
198 """
199 nonlocal call_count
200 call_count += 1
201 if call_count == 1:
202 # First check - issues found
203 return (False, "Diff in src/main.rs:1:")
204 elif call_count == 2:
205 # Fix command
206 return (True, "")
207 else:
208 # Verification - no issues
209 return (True, "")
211 with patch(
212 "lintro.plugins.execution_preparation.verify_tool_version",
213 return_value=None,
214 ):
215 with patch.object(rustfmt_plugin, "_run_subprocess", side_effect=mock_run):
216 result = rustfmt_plugin.fix([str(test_file)], {})
218 assert_that(result.success).is_true()
219 assert_that(result.fixed_issues_count).is_equal_to(1)
220 # Verify the mock was called expected number of times (check + fix + verify)
221 assert_that(call_count).is_equal_to(3)
224def test_fix_with_nothing_to_fix(
225 rustfmt_plugin: RustfmtPlugin,
226 tmp_path: Path,
227) -> None:
228 """Fix returns success when no fixes needed.
230 Args:
231 rustfmt_plugin: The RustfmtPlugin instance to test.
232 tmp_path: Temporary directory path for test files.
233 """
234 cargo_toml = tmp_path / "Cargo.toml"
235 cargo_toml.write_text('[package]\nname = "test"\nversion = "0.1.0"')
237 test_file = tmp_path / "src" / "main.rs"
238 test_file.parent.mkdir(parents=True, exist_ok=True)
239 test_file.write_text("fn main() {}\n")
241 with patch(
242 "lintro.plugins.execution_preparation.verify_tool_version",
243 return_value=None,
244 ):
245 with patch.object(
246 rustfmt_plugin,
247 "_run_subprocess",
248 return_value=(True, ""),
249 ):
250 result = rustfmt_plugin.fix([str(test_file)], {})
252 assert_that(result.success).is_true()
253 assert_that(result.issues_count).is_equal_to(0)
254 assert_that(result.fixed_issues_count).is_equal_to(0)