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

1"""Unit tests for lintro/cli_utils/commands/format.py.""" 

2 

3from __future__ import annotations 

4 

5from pathlib import Path 

6from unittest.mock import MagicMock, patch 

7 

8import pytest 

9from assertpy import assert_that 

10from click.testing import CliRunner 

11 

12from lintro.cli_utils.commands.format import format_code, format_command 

13 

14# ============================================================================= 

15# Format Command Basic Tests 

16# ============================================================================= 

17 

18 

19def test_format_command_help(cli_runner: CliRunner) -> None: 

20 """Verify format command shows help. 

21 

22 Args: 

23 cli_runner: The Click CLI test runner. 

24 """ 

25 result = cli_runner.invoke(format_command, ["--help"]) 

26 

27 assert_that(result.exit_code).is_equal_to(0) 

28 assert_that(result.output).contains("Format") 

29 

30 

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. 

36 

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, []) 

43 

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(["."]) 

47 

48 

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. 

55 

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") 

63 

64 cli_runner.invoke(format_command, [str(test_file)]) 

65 

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)) 

69 

70 

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. 

76 

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, []) 

84 

85 assert_that(result.exit_code).is_equal_to(0) 

86 

87 

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. 

93 

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, []) 

101 

102 assert_that(result.exit_code).is_equal_to(1) 

103 

104 

105# ============================================================================= 

106# Format Command Options Tests 

107# ============================================================================= 

108 

109 

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. 

115 

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"]) 

122 

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") 

126 

127 

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. 

133 

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__"]) 

140 

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__") 

144 

145 

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. 

151 

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"]) 

158 

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() 

162 

163 

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. 

169 

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"]) 

176 

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") 

180 

181 

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. 

193 

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]) 

201 

202 assert_that(result.exit_code).is_equal_to(0) 

203 

204 

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. 

210 

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"]) 

217 

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") 

221 

222 

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. 

234 

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]) 

242 

243 assert_that(result.exit_code).is_equal_to(0) 

244 

245 

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. 

251 

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"]) 

258 

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() 

262 

263 

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. 

269 

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"]) 

276 

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() 

280 

281 

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. 

287 

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"]) 

294 

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() 

298 

299 

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. 

305 

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 ) 

315 

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") 

319 

320 

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. 

326 

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, []) 

333 

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") 

337 

338 

339# ============================================================================= 

340# Programmatic format_code() Function Tests 

341# ============================================================================= 

342 

343 

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 

352 

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 ) 

363 

364 mock_runner.invoke.assert_called_once() 

365 

366 

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 

376 

377 with pytest.raises(RuntimeError) as exc_info: 

378 format_code( 

379 paths=["src"], 

380 tools="ruff", 

381 ) 

382 

383 assert_that(str(exc_info.value)).contains("Format failed") 

384 

385 

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 

394 

395 # Call with only required parameters (all have defaults) 

396 format_code() 

397 

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() 

404 

405 

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 

414 

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 ) 

425 

426 mock_runner.invoke.assert_called_once() 

427 call_args = mock_runner.invoke.call_args 

428 args = call_args[0][1] 

429 

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") 

436 

437 

438# ============================================================================= 

439# Format Command Edge Cases 

440# ============================================================================= 

441 

442 

443def test_format_command_invalid_output_format(cli_runner: CliRunner) -> None: 

444 """Verify format command rejects invalid output format. 

445 

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"]) 

451 

452 assert_that(result.exit_code).is_not_equal_to(0) 

453 assert_that(result.output).contains("Invalid value") 

454 

455 

456def test_format_command_invalid_group_by(cli_runner: CliRunner) -> None: 

457 """Verify format command rejects invalid group-by option. 

458 

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"]) 

464 

465 assert_that(result.exit_code).is_not_equal_to(0) 

466 assert_that(result.output).contains("Invalid value") 

467 

468 

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. 

475 

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") 

485 

486 cli_runner.invoke(format_command, [str(file1), str(file2)]) 

487 

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)