Coverage for tests / unit / cli / test_format_command.py: 100%
172 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 lintro/cli_utils/commands/format.py."""
3from __future__ import annotations
5from pathlib import Path
6from unittest.mock import MagicMock, patch
8import pytest
9from assertpy import assert_that
10from click.testing import CliRunner
12from lintro.cli_utils.commands.format import format_code, format_command
14# =============================================================================
15# Format Command Basic Tests
16# =============================================================================
19def test_format_command_help(cli_runner: CliRunner) -> None:
20 """Verify format command shows help.
22 Args:
23 cli_runner: The Click CLI test runner.
24 """
25 result = cli_runner.invoke(format_command, ["--help"])
27 assert_that(result.exit_code).is_equal_to(0)
28 assert_that(result.output).contains("Format")
31def test_format_command_default_paths(
32 cli_runner: CliRunner,
33 mock_run_lint_tools_format: MagicMock,
34) -> None:
35 """Verify format command uses default paths when none provided.
37 Args:
38 cli_runner: The Click CLI test runner.
39 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
40 """
41 with cli_runner.isolated_filesystem():
42 cli_runner.invoke(format_command, [])
44 mock_run_lint_tools_format.assert_called_once()
45 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
46 assert_that(call_kwargs["paths"]).is_equal_to(["."])
49def test_format_command_with_paths(
50 cli_runner: CliRunner,
51 mock_run_lint_tools_format: MagicMock,
52 tmp_path: Path,
53) -> None:
54 """Verify format command passes provided paths.
56 Args:
57 cli_runner: The Click CLI test runner.
58 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
59 tmp_path: Temporary directory path for testing.
60 """
61 test_file = tmp_path / "test.py"
62 test_file.write_text("# test")
64 cli_runner.invoke(format_command, [str(test_file)])
66 mock_run_lint_tools_format.assert_called_once()
67 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
68 assert_that(call_kwargs["paths"]).contains(str(test_file))
71def test_format_command_exit_code_zero_on_success(
72 cli_runner: CliRunner,
73 mock_run_lint_tools_format: MagicMock,
74) -> None:
75 """Verify format command exits with 0 on success.
77 Args:
78 cli_runner: The Click CLI test runner.
79 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
80 """
81 mock_run_lint_tools_format.return_value = 0
82 with cli_runner.isolated_filesystem():
83 result = cli_runner.invoke(format_command, [])
85 assert_that(result.exit_code).is_equal_to(0)
88def test_format_command_exit_code_nonzero_on_error(
89 cli_runner: CliRunner,
90 mock_run_lint_tools_format: MagicMock,
91) -> None:
92 """Verify format command exits with non-zero on error.
94 Args:
95 cli_runner: The Click CLI test runner.
96 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
97 """
98 mock_run_lint_tools_format.return_value = 1
99 with cli_runner.isolated_filesystem():
100 result = cli_runner.invoke(format_command, [])
102 assert_that(result.exit_code).is_equal_to(1)
105# =============================================================================
106# Format Command Options Tests
107# =============================================================================
110def test_format_command_tools_option(
111 cli_runner: CliRunner,
112 mock_run_lint_tools_format: MagicMock,
113) -> None:
114 """Verify --tools option is passed correctly.
116 Args:
117 cli_runner: The Click CLI test runner.
118 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
119 """
120 with cli_runner.isolated_filesystem():
121 cli_runner.invoke(format_command, ["--tools", "ruff,black"])
123 mock_run_lint_tools_format.assert_called_once()
124 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
125 assert_that(call_kwargs["tools"]).is_equal_to("ruff,black")
128def test_format_command_exclude_option(
129 cli_runner: CliRunner,
130 mock_run_lint_tools_format: MagicMock,
131) -> None:
132 """Verify --exclude option is passed correctly.
134 Args:
135 cli_runner: The Click CLI test runner.
136 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
137 """
138 with cli_runner.isolated_filesystem():
139 cli_runner.invoke(format_command, ["--exclude", "*.pyc,__pycache__"])
141 mock_run_lint_tools_format.assert_called_once()
142 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
143 assert_that(call_kwargs["exclude"]).is_equal_to("*.pyc,__pycache__")
146def test_format_command_include_venv_flag(
147 cli_runner: CliRunner,
148 mock_run_lint_tools_format: MagicMock,
149) -> None:
150 """Verify --include-venv flag is passed correctly.
152 Args:
153 cli_runner: The Click CLI test runner.
154 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
155 """
156 with cli_runner.isolated_filesystem():
157 cli_runner.invoke(format_command, ["--include-venv"])
159 mock_run_lint_tools_format.assert_called_once()
160 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
161 assert_that(call_kwargs["include_venv"]).is_true()
164def test_format_command_output_format_option(
165 cli_runner: CliRunner,
166 mock_run_lint_tools_format: MagicMock,
167) -> None:
168 """Verify --output-format option is passed correctly.
170 Args:
171 cli_runner: The Click CLI test runner.
172 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
173 """
174 with cli_runner.isolated_filesystem():
175 cli_runner.invoke(format_command, ["--output-format", "json"])
177 mock_run_lint_tools_format.assert_called_once()
178 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
179 assert_that(call_kwargs["output_format"]).is_equal_to("json")
182@pytest.mark.parametrize(
183 "format_option",
184 ["plain", "grid", "markdown", "html", "json", "csv"],
185 ids=["plain", "grid", "markdown", "html", "json", "csv"],
186)
187def test_format_command_output_format_valid_choices(
188 cli_runner: CliRunner,
189 mock_run_lint_tools_format: MagicMock,
190 format_option: str,
191) -> None:
192 """Verify all valid output format choices are accepted.
194 Args:
195 cli_runner: The Click CLI test runner.
196 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
197 format_option: The output format option being tested.
198 """
199 with cli_runner.isolated_filesystem():
200 result = cli_runner.invoke(format_command, ["--output-format", format_option])
202 assert_that(result.exit_code).is_equal_to(0)
205def test_format_command_group_by_option(
206 cli_runner: CliRunner,
207 mock_run_lint_tools_format: MagicMock,
208) -> None:
209 """Verify --group-by option is passed correctly.
211 Args:
212 cli_runner: The Click CLI test runner.
213 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
214 """
215 with cli_runner.isolated_filesystem():
216 cli_runner.invoke(format_command, ["--group-by", "code"])
218 mock_run_lint_tools_format.assert_called_once()
219 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
220 assert_that(call_kwargs["group_by"]).is_equal_to("code")
223@pytest.mark.parametrize(
224 "group_by_option",
225 ["file", "code", "none", "auto"],
226 ids=["file", "code", "none", "auto"],
227)
228def test_format_command_group_by_valid_choices(
229 cli_runner: CliRunner,
230 mock_run_lint_tools_format: MagicMock,
231 group_by_option: str,
232) -> None:
233 """Verify all valid group-by choices are accepted.
235 Args:
236 cli_runner: The Click CLI test runner.
237 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
238 group_by_option: The group-by option being tested.
239 """
240 with cli_runner.isolated_filesystem():
241 result = cli_runner.invoke(format_command, ["--group-by", group_by_option])
243 assert_that(result.exit_code).is_equal_to(0)
246def test_format_command_verbose_flag(
247 cli_runner: CliRunner,
248 mock_run_lint_tools_format: MagicMock,
249) -> None:
250 """Verify --verbose flag is passed correctly.
252 Args:
253 cli_runner: The Click CLI test runner.
254 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
255 """
256 with cli_runner.isolated_filesystem():
257 cli_runner.invoke(format_command, ["--verbose"])
259 mock_run_lint_tools_format.assert_called_once()
260 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
261 assert_that(call_kwargs["verbose"]).is_true()
264def test_format_command_verbose_short_flag(
265 cli_runner: CliRunner,
266 mock_run_lint_tools_format: MagicMock,
267) -> None:
268 """Verify -v short flag works for verbose.
270 Args:
271 cli_runner: The Click CLI test runner.
272 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
273 """
274 with cli_runner.isolated_filesystem():
275 cli_runner.invoke(format_command, ["-v"])
277 mock_run_lint_tools_format.assert_called_once()
278 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
279 assert_that(call_kwargs["verbose"]).is_true()
282def test_format_command_raw_output_flag(
283 cli_runner: CliRunner,
284 mock_run_lint_tools_format: MagicMock,
285) -> None:
286 """Verify --raw-output flag is passed correctly.
288 Args:
289 cli_runner: The Click CLI test runner.
290 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
291 """
292 with cli_runner.isolated_filesystem():
293 cli_runner.invoke(format_command, ["--raw-output"])
295 mock_run_lint_tools_format.assert_called_once()
296 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
297 assert_that(call_kwargs["raw_output"]).is_true()
300def test_format_command_tool_options(
301 cli_runner: CliRunner,
302 mock_run_lint_tools_format: MagicMock,
303) -> None:
304 """Verify --tool-options is passed correctly.
306 Args:
307 cli_runner: The Click CLI test runner.
308 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
309 """
310 with cli_runner.isolated_filesystem():
311 cli_runner.invoke(
312 format_command,
313 ["--tool-options", "ruff:line-length=120"],
314 )
316 mock_run_lint_tools_format.assert_called_once()
317 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
318 assert_that(call_kwargs["tool_options"]).is_equal_to("ruff:line-length=120")
321def test_format_command_uses_fmt_action(
322 cli_runner: CliRunner,
323 mock_run_lint_tools_format: MagicMock,
324) -> None:
325 """Verify format command uses 'fmt' action.
327 Args:
328 cli_runner: The Click CLI test runner.
329 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
330 """
331 with cli_runner.isolated_filesystem():
332 cli_runner.invoke(format_command, [])
334 mock_run_lint_tools_format.assert_called_once()
335 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
336 assert_that(call_kwargs["action"]).is_equal_to("fmt")
339# =============================================================================
340# Programmatic format_code() Function Tests
341# =============================================================================
344def test_format_code_function_calls_command() -> None:
345 """Verify format_code() function invokes the format_command."""
346 with patch("lintro.cli_utils.commands.format.CliRunner") as mock_runner_cls:
347 mock_runner = MagicMock()
348 mock_result = MagicMock()
349 mock_result.exit_code = 0
350 mock_runner.invoke.return_value = mock_result
351 mock_runner_cls.return_value = mock_runner
353 format_code(
354 paths=["src"],
355 tools="ruff",
356 tool_options=None,
357 exclude=None,
358 include_venv=False,
359 group_by="auto",
360 output_format="grid",
361 verbose=False,
362 )
364 mock_runner.invoke.assert_called_once()
367def test_format_code_function_raises_on_failure() -> None:
368 """Verify format_code() function raises RuntimeError on failure."""
369 with patch("lintro.cli_utils.commands.format.CliRunner") as mock_runner_cls:
370 mock_runner = MagicMock()
371 mock_result = MagicMock()
372 mock_result.exit_code = 1
373 mock_result.output = "Error occurred"
374 mock_runner.invoke.return_value = mock_result
375 mock_runner_cls.return_value = mock_runner
377 with pytest.raises(RuntimeError) as exc_info:
378 format_code(
379 paths=["src"],
380 tools="ruff",
381 )
383 assert_that(str(exc_info.value)).contains("Format failed")
386def test_format_code_function_default_parameters() -> None:
387 """Verify format_code() function uses default parameters."""
388 with patch("lintro.cli_utils.commands.format.CliRunner") as mock_runner_cls:
389 mock_runner = MagicMock()
390 mock_result = MagicMock()
391 mock_result.exit_code = 0
392 mock_runner.invoke.return_value = mock_result
393 mock_runner_cls.return_value = mock_runner
395 # Call with only required parameters (all have defaults)
396 format_code()
398 mock_runner.invoke.assert_called_once()
399 # Verify defaults were used (no paths means empty args)
400 call_args = mock_runner.invoke.call_args
401 args = call_args[0][1] # Second positional arg is the args list
402 # Should not contain --tools if tools=None
403 assert_that("--tools" not in args).is_true()
406def test_format_code_function_with_all_options() -> None:
407 """Verify format_code() passes all options correctly."""
408 with patch("lintro.cli_utils.commands.format.CliRunner") as mock_runner_cls:
409 mock_runner = MagicMock()
410 mock_result = MagicMock()
411 mock_result.exit_code = 0
412 mock_runner.invoke.return_value = mock_result
413 mock_runner_cls.return_value = mock_runner
415 format_code(
416 paths=["src", "tests"],
417 tools="ruff,black",
418 tool_options="ruff:line-length=100",
419 exclude="*.pyc",
420 include_venv=True,
421 group_by="file",
422 output_format="json",
423 verbose=True,
424 )
426 mock_runner.invoke.assert_called_once()
427 call_args = mock_runner.invoke.call_args
428 args = call_args[0][1]
430 assert_that(args).contains("src")
431 assert_that(args).contains("tests")
432 assert_that(args).contains("--tools")
433 assert_that(args).contains("ruff,black")
434 assert_that(args).contains("--include-venv")
435 assert_that(args).contains("--verbose")
438# =============================================================================
439# Format Command Edge Cases
440# =============================================================================
443def test_format_command_invalid_output_format(cli_runner: CliRunner) -> None:
444 """Verify format command rejects invalid output format.
446 Args:
447 cli_runner: The Click CLI test runner.
448 """
449 with cli_runner.isolated_filesystem():
450 result = cli_runner.invoke(format_command, ["--output-format", "invalid"])
452 assert_that(result.exit_code).is_not_equal_to(0)
453 assert_that(result.output).contains("Invalid value")
456def test_format_command_invalid_group_by(cli_runner: CliRunner) -> None:
457 """Verify format command rejects invalid group-by option.
459 Args:
460 cli_runner: The Click CLI test runner.
461 """
462 with cli_runner.isolated_filesystem():
463 result = cli_runner.invoke(format_command, ["--group-by", "invalid"])
465 assert_that(result.exit_code).is_not_equal_to(0)
466 assert_that(result.output).contains("Invalid value")
469def test_format_command_multiple_paths(
470 cli_runner: CliRunner,
471 mock_run_lint_tools_format: MagicMock,
472 tmp_path: Path,
473) -> None:
474 """Verify format command handles multiple paths.
476 Args:
477 cli_runner: The Click CLI test runner.
478 mock_run_lint_tools_format: Mock for the run_lint_tools_format function.
479 tmp_path: Temporary directory path for testing.
480 """
481 file1 = tmp_path / "file1.py"
482 file2 = tmp_path / "file2.py"
483 file1.write_text("# file1")
484 file2.write_text("# file2")
486 cli_runner.invoke(format_command, [str(file1), str(file2)])
488 mock_run_lint_tools_format.assert_called_once()
489 call_kwargs = mock_run_lint_tools_format.call_args.kwargs
490 assert_that(len(call_kwargs["paths"])).is_equal_to(2)