Coverage for tests / unit / utils / console / summary / test_delegation.py: 100%
107 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 ThreadSafeConsoleLogger summary delegation methods.
3This module tests the delegation functionality of ThreadSafeConsoleLogger summary
4methods,
5including summary table, final status, and ASCII art delegation.
6"""
8from __future__ import annotations
10from typing import TYPE_CHECKING
11from unittest.mock import patch
13import pytest
14from assertpy import assert_that
16from lintro.enums.action import Action
17from lintro.utils.console.logger import ThreadSafeConsoleLogger
19if TYPE_CHECKING:
20 from collections.abc import Callable
22 from tests.unit.utils.conftest import FakeToolResult
25# =============================================================================
26# Summary Table Delegation Tests
27# =============================================================================
30def test_print_summary_table_delegates_to_module_function(
31 fake_tool_result_factory: Callable[..., FakeToolResult],
32) -> None:
33 """Verify _print_summary_table delegates to print_summary_table function.
35 The method should pass through all parameters to the module-level
36 print_summary_table function.
39 Args:
40 fake_tool_result_factory: Factory for creating FakeToolResult instances.
41 """
42 logger = ThreadSafeConsoleLogger()
43 results = [fake_tool_result_factory()]
45 with patch("lintro.utils.summary_tables.print_summary_table") as mock_print:
46 logger._print_summary_table(Action.CHECK, results)
47 mock_print.assert_called_once()
50def test_print_summary_table_converts_string_action(
51 fake_tool_result_factory: Callable[..., FakeToolResult],
52) -> None:
53 """Verify _print_summary_table converts string action to Action enum.
55 String action values should be normalized to Action enum instances
56 before being passed to the underlying function.
59 Args:
60 fake_tool_result_factory: Factory for creating FakeToolResult instances.
61 """
62 logger = ThreadSafeConsoleLogger()
63 results = [fake_tool_result_factory()]
65 with patch("lintro.utils.summary_tables.print_summary_table") as mock_print:
66 logger._print_summary_table("check", results)
67 mock_print.assert_called_once()
68 call_kwargs = mock_print.call_args.kwargs
69 assert_that(call_kwargs["action"]).is_equal_to(Action.CHECK)
72@pytest.mark.parametrize(
73 ("action_str", "expected_action"),
74 [
75 ("check", Action.CHECK),
76 ("fix", Action.FIX),
77 ("fmt", Action.FIX),
78 ("test", Action.TEST),
79 ],
80)
81def test_print_summary_table_action_normalization(
82 fake_tool_result_factory: Callable[..., FakeToolResult],
83 action_str: str,
84 expected_action: Action,
85) -> None:
86 """Verify _print_summary_table normalizes various action string formats.
88 Different string representations of actions should all be correctly
89 converted to their corresponding Action enum values.
92 Args:
93 fake_tool_result_factory: Factory for creating FakeToolResult instances.
94 action_str: String representation of the action.
95 expected_action: Expected Action enum value.
96 """
97 logger = ThreadSafeConsoleLogger()
98 results = [fake_tool_result_factory()]
100 with patch("lintro.utils.summary_tables.print_summary_table") as mock_print:
101 logger._print_summary_table(action_str, results)
102 call_kwargs = mock_print.call_args.kwargs
103 assert_that(call_kwargs["action"]).is_equal_to(expected_action)
106# =============================================================================
107# Totals Table Delegation Tests
108# =============================================================================
111def test_print_totals_table_delegates_to_module_function() -> None:
112 """Verify _print_totals_table delegates to print_totals_table function.
114 The method should pass through all parameters to the module-level
115 print_totals_table function.
116 """
117 logger = ThreadSafeConsoleLogger()
119 with patch("lintro.utils.summary_tables.print_totals_table") as mock_print:
120 logger._print_totals_table(
121 action=Action.CHECK,
122 total_issues=5,
123 affected_files=2,
124 )
125 mock_print.assert_called_once_with(
126 console_output_func=logger.console_output,
127 action=Action.CHECK,
128 total_issues=5,
129 total_fixed=0,
130 total_remaining=0,
131 affected_files=2,
132 severity_errors=0,
133 severity_warnings=0,
134 severity_info=0,
135 total_ai_applied=0,
136 total_ai_verified=0,
137 )
140def test_print_totals_table_delegates_fix_mode() -> None:
141 """Verify _print_totals_table delegates FIX mode parameters correctly.
143 FIX mode should pass total_fixed and total_remaining to the
144 underlying function.
145 """
146 logger = ThreadSafeConsoleLogger()
148 with patch("lintro.utils.summary_tables.print_totals_table") as mock_print:
149 logger._print_totals_table(
150 action=Action.FIX,
151 total_fixed=10,
152 total_remaining=3,
153 affected_files=5,
154 total_ai_applied=2,
155 total_ai_verified=1,
156 )
157 mock_print.assert_called_once_with(
158 console_output_func=logger.console_output,
159 action=Action.FIX,
160 total_issues=0,
161 total_fixed=10,
162 total_remaining=3,
163 affected_files=5,
164 severity_errors=0,
165 severity_warnings=0,
166 severity_info=0,
167 total_ai_applied=2,
168 total_ai_verified=1,
169 )
172@pytest.mark.parametrize(
173 ("action", "kwargs"),
174 [
175 (Action.CHECK, {"total_issues": 0, "affected_files": 0}),
176 (Action.CHECK, {"total_issues": 10, "affected_files": 5}),
177 (Action.FIX, {"total_fixed": 5, "total_remaining": 2, "affected_files": 3}),
178 (Action.TEST, {"total_issues": 4, "affected_files": 1}),
179 ],
180)
181def test_print_totals_table_various_inputs(
182 action: Action,
183 kwargs: dict[str, int],
184) -> None:
185 """Verify _print_totals_table handles various action and parameter combos.
187 Args:
188 action: Action type to test.
189 kwargs: Keyword arguments to pass to the method.
190 """
191 logger = ThreadSafeConsoleLogger()
193 with patch("lintro.utils.summary_tables.print_totals_table") as mock_print:
194 logger._print_totals_table(action=action, **kwargs)
195 mock_print.assert_called_once()
198# =============================================================================
199# Final Status Delegation Tests
200# =============================================================================
203def test_print_final_status_delegates_to_module_function() -> None:
204 """Verify _print_final_status delegates to print_final_status function.
206 The method should pass the console output function, action, and
207 total issues to the module-level function.
208 """
209 logger = ThreadSafeConsoleLogger()
211 with patch("lintro.utils.console.logger.print_final_status") as mock_print:
212 logger._print_final_status(Action.CHECK, 5)
213 mock_print.assert_called_once()
216def test_print_final_status_converts_string_action() -> None:
217 """Verify _print_final_status accepts string action values.
219 String actions should be passed through and handled by the underlying
220 function's normalization logic.
221 """
222 logger = ThreadSafeConsoleLogger()
224 with patch("lintro.utils.console.logger.print_final_status") as mock_print:
225 logger._print_final_status("fmt", 3)
226 mock_print.assert_called_once()
229@pytest.mark.parametrize(
230 ("action", "total_issues"),
231 [
232 (Action.CHECK, 0),
233 (Action.CHECK, 10),
234 (Action.FIX, 0),
235 (Action.FIX, 5),
236 ("check", 3),
237 ("fmt", 7),
238 ],
239)
240def test_print_final_status_various_inputs(
241 action: Action | str,
242 total_issues: int,
243) -> None:
244 """Verify _print_final_status handles various action and issue combinations.
246 Both enum and string action values with different issue counts should
247 be properly delegated.
250 Args:
251 action: Action type (enum or string).
252 total_issues: Number of total issues.
253 """
254 logger = ThreadSafeConsoleLogger()
256 with patch("lintro.utils.console.logger.print_final_status") as mock_print:
257 logger._print_final_status(action, total_issues)
258 mock_print.assert_called_once()
261# =============================================================================
262# Final Status Format Delegation Tests
263# =============================================================================
266def test_print_final_status_format_delegates_correctly() -> None:
267 """Verify _print_final_status_format delegates with correct parameters.
269 The method should pass the console output function, total fixed,
270 and total remaining to the module-level function.
271 """
272 logger = ThreadSafeConsoleLogger()
274 with patch("lintro.utils.console.logger.print_final_status_format") as mock_print:
275 logger._print_final_status_format(10, 2)
276 mock_print.assert_called_once_with(
277 console_output_func=logger.console_output,
278 total_fixed=10,
279 total_remaining=2,
280 )
283@pytest.mark.parametrize(
284 ("total_fixed", "total_remaining"),
285 [
286 (0, 0),
287 (5, 0),
288 (0, 3),
289 (10, 5),
290 (100, 50),
291 ],
292)
293def test_print_final_status_format_various_counts(
294 total_fixed: int,
295 total_remaining: int,
296) -> None:
297 """Verify _print_final_status_format handles various count combinations.
299 Different fixed and remaining combinations should be properly passed
300 to the underlying function.
303 Args:
304 total_fixed: Number of fixed issues.
305 total_remaining: Number of remaining issues.
306 """
307 logger = ThreadSafeConsoleLogger()
309 with patch("lintro.utils.console.logger.print_final_status_format") as mock_print:
310 logger._print_final_status_format(total_fixed, total_remaining)
311 mock_print.assert_called_once_with(
312 console_output_func=logger.console_output,
313 total_fixed=total_fixed,
314 total_remaining=total_remaining,
315 )
318# =============================================================================
319# ASCII Art Delegation Tests
320# =============================================================================
323def test_print_ascii_art_delegates_correctly() -> None:
324 """Verify _print_ascii_art delegates with correct parameters.
326 The method should pass the console output function and issue count
327 to the module-level print_ascii_art function.
328 """
329 logger = ThreadSafeConsoleLogger()
331 with patch("lintro.utils.console.logger.print_ascii_art") as mock_print:
332 logger._print_ascii_art(5)
333 mock_print.assert_called_once_with(
334 console_output_func=logger.console_output,
335 issue_count=5,
336 )
339@pytest.mark.parametrize("issue_count", [0, 1, 5, 10, 100])
340def test_print_ascii_art_various_counts(issue_count: int) -> None:
341 """Verify _print_ascii_art handles various issue counts.
343 Different issue counts should be properly passed to display
344 either success or failure ASCII art.
347 Args:
348 issue_count: Number of issues to display.
349 """
350 logger = ThreadSafeConsoleLogger()
352 with patch("lintro.utils.console.logger.print_ascii_art") as mock_print:
353 logger._print_ascii_art(issue_count)
354 mock_print.assert_called_once_with(
355 console_output_func=logger.console_output,
356 issue_count=issue_count,
357 )
360# =============================================================================
361# Integration Tests - Full Execution Summary Flow
362# =============================================================================
365def test_execution_summary_outputs_header_and_border(
366 fake_tool_result_factory: Callable[..., FakeToolResult],
367) -> None:
368 """Verify print_execution_summary outputs properly styled header.
370 The execution summary should begin with a styled header including
371 the section title and border for visual clarity.
374 Args:
375 fake_tool_result_factory: Factory for creating FakeToolResult instances.
376 """
377 logger = ThreadSafeConsoleLogger()
378 results = [fake_tool_result_factory(success=True, issues_count=0)]
380 with (
381 patch.object(logger, "console_output") as mock_output,
382 patch.object(logger, "_print_summary_table"),
383 patch.object(logger, "_print_ascii_art"),
384 ):
385 logger.print_execution_summary(Action.CHECK, results)
386 # Should have multiple output calls including header
387 assert_that(mock_output.call_count).is_greater_than(0)
390def test_execution_summary_calls_all_components(
391 fake_tool_result_factory: Callable[..., FakeToolResult],
392) -> None:
393 """Verify print_execution_summary invokes all required components.
395 The method should call summary table and ASCII art display as part
396 of the complete execution summary output.
399 Args:
400 fake_tool_result_factory: Factory for creating FakeToolResult instances.
401 """
402 logger = ThreadSafeConsoleLogger()
403 results = [fake_tool_result_factory(success=True, issues_count=3)]
405 with (
406 patch.object(logger, "console_output"),
407 patch.object(logger, "_print_summary_table") as mock_table,
408 patch.object(logger, "_print_ascii_art") as mock_art,
409 ):
410 logger.print_execution_summary(Action.CHECK, results)
411 mock_table.assert_called_once()
412 mock_art.assert_called_once()
415def test_execution_summary_empty_results_handled(
416 console_capture: tuple[Callable[[str], None], list[str]],
417) -> None:
418 """Verify print_execution_summary handles empty results list gracefully.
420 Even with no tool results, the summary should complete without errors
421 and show appropriate totals (zero).
424 Args:
425 console_capture: Fixture for capturing console output.
426 """
427 logger = ThreadSafeConsoleLogger()
429 with (
430 patch.object(logger, "console_output"),
431 patch.object(logger, "_print_summary_table"),
432 patch.object(logger, "_print_ascii_art") as mock_art,
433 ):
434 logger.print_execution_summary(Action.CHECK, [])
435 mock_art.assert_called_once_with(total_issues=0)
438@pytest.mark.parametrize(
439 "action",
440 [Action.CHECK, Action.FIX, Action.TEST],
441)
442def test_execution_summary_all_action_types(
443 fake_tool_result_factory: Callable[..., FakeToolResult],
444 action: Action,
445) -> None:
446 """Verify print_execution_summary handles all action types.
448 CHECK, FIX, and TEST actions should all produce valid summary output
449 without errors.
452 Args:
453 fake_tool_result_factory: Factory for creating FakeToolResult instances.
454 action: Action type to test.
455 """
456 logger = ThreadSafeConsoleLogger()
457 results = [fake_tool_result_factory(success=True, issues_count=0)]
459 with (
460 patch.object(logger, "console_output"),
461 patch.object(logger, "_print_summary_table"),
462 patch.object(logger, "_print_ascii_art"),
463 ):
464 # Should not raise for any action type
465 logger.print_execution_summary(action, results)