Coverage for tests / unit / utils / config / test_manager_configuration.py: 100%
74 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 UnifiedConfigManager apply_config, reporting, and integration."""
3from __future__ import annotations
5from unittest.mock import MagicMock, patch
7import pytest
8from assertpy import assert_that
10from lintro.utils.unified_config import UnifiedConfigManager
12# =============================================================================
13# Tests for apply_config_to_tool method
14# =============================================================================
17def test_manager_apply_config_does_nothing_for_tool_without_name(
18 manager: UnifiedConfigManager,
19) -> None:
20 """Verify apply_config_to_tool skips tools without a name.
22 When tool.name is empty, set_options should not be called.
25 Args:
26 manager: Configuration manager instance.
27 """
28 mock_tool = MagicMock()
29 mock_tool.name = ""
31 manager.apply_config_to_tool(mock_tool)
33 mock_tool.set_options.assert_not_called()
36def test_manager_apply_config_calls_set_options_with_effective_config(
37 manager: UnifiedConfigManager,
38 mock_tool: MagicMock,
39) -> None:
40 """Verify apply_config_to_tool calls set_options on the tool.
42 The tool's set_options method should be called with merged config
43 from all sources.
45 mock_tool: Mock tool instance.
47 mock_tool: Mock tool instance.
50 Args:
51 manager: Configuration manager instance.
52 mock_tool: Mock tool instance.
53 """
54 with (
55 patch(
56 "lintro.utils.unified_config_manager.is_tool_injectable",
57 return_value=True,
58 ),
59 patch.object(manager, "get_effective_line_length", return_value=100),
60 patch(
61 "lintro.utils.unified_config_manager.load_lintro_tool_config",
62 return_value={"strict": True},
63 ),
64 ):
65 manager.apply_config_to_tool(mock_tool, cli_overrides={"debug": True})
67 mock_tool.set_options.assert_called_once()
70def test_manager_apply_config_includes_line_length_for_injectable_tools(
71 manager: UnifiedConfigManager,
72 mock_tool: MagicMock,
73) -> None:
74 """Verify line_length is included for injectable tools.
76 When is_tool_injectable returns True, line_length should be passed
77 to set_options.
79 mock_tool: Mock tool instance.
81 mock_tool: Mock tool instance.
84 Args:
85 manager: Configuration manager instance.
86 mock_tool: Mock tool instance.
87 """
88 with (
89 patch(
90 "lintro.utils.unified_config_manager.is_tool_injectable",
91 return_value=True,
92 ),
93 patch.object(manager, "get_effective_line_length", return_value=100),
94 patch(
95 "lintro.utils.unified_config_manager.load_lintro_tool_config",
96 return_value={},
97 ),
98 ):
99 manager.apply_config_to_tool(mock_tool)
101 call_kwargs = mock_tool.set_options.call_args[1]
102 assert_that(call_kwargs).contains_key("line_length")
103 assert_that(call_kwargs["line_length"]).is_equal_to(100)
106def test_manager_apply_config_cli_overrides_take_precedence(
107 manager: UnifiedConfigManager,
108 mock_tool: MagicMock,
109) -> None:
110 """Verify CLI overrides have highest priority.
112 When cli_overrides conflict with other config sources, CLI values
113 should win.
115 mock_tool: Mock tool instance.
117 mock_tool: Mock tool instance.
120 Args:
121 manager: Configuration manager instance.
122 mock_tool: Mock tool instance.
123 """
124 with (
125 patch(
126 "lintro.utils.unified_config_manager.is_tool_injectable",
127 return_value=True,
128 ),
129 patch.object(manager, "get_effective_line_length", return_value=100),
130 patch(
131 "lintro.utils.unified_config_manager.load_lintro_tool_config",
132 return_value={"line_length": 80},
133 ),
134 ):
135 manager.apply_config_to_tool(mock_tool, cli_overrides={"line_length": 120})
137 call_kwargs = mock_tool.set_options.call_args[1]
138 assert_that(call_kwargs["line_length"]).is_equal_to(120)
141def test_manager_apply_config_raises_value_error_from_tool(
142 manager: UnifiedConfigManager,
143 mock_tool: MagicMock,
144) -> None:
145 """Verify ValueError from tool.set_options is re-raised.
147 Configuration errors (ValueError, TypeError) should propagate to the caller.
149 mock_tool: Mock tool instance.
151 mock_tool: Mock tool instance.
154 Args:
155 manager: Configuration manager instance.
156 mock_tool: Mock tool instance.
157 """
158 mock_tool.set_options.side_effect = ValueError("Invalid value")
160 with (
161 patch(
162 "lintro.utils.unified_config_manager.is_tool_injectable",
163 return_value=True,
164 ),
165 patch.object(manager, "get_effective_line_length", return_value=100),
166 patch(
167 "lintro.utils.unified_config_manager.load_lintro_tool_config",
168 return_value={},
169 ),
170 ):
171 with pytest.raises(ValueError, match="Invalid value"):
172 manager.apply_config_to_tool(mock_tool)
175def test_manager_apply_config_raises_type_error_from_tool(
176 manager: UnifiedConfigManager,
177 mock_tool: MagicMock,
178) -> None:
179 """Verify TypeError from tool.set_options is re-raised.
181 Configuration errors (ValueError, TypeError) should propagate to the caller.
183 mock_tool: Mock tool instance.
185 mock_tool: Mock tool instance.
188 Args:
189 manager: Configuration manager instance.
190 mock_tool: Mock tool instance.
191 """
192 mock_tool.set_options.side_effect = TypeError("Type mismatch")
194 with (
195 patch(
196 "lintro.utils.unified_config_manager.is_tool_injectable",
197 return_value=True,
198 ),
199 patch.object(manager, "get_effective_line_length", return_value=100),
200 patch(
201 "lintro.utils.unified_config_manager.load_lintro_tool_config",
202 return_value={},
203 ),
204 ):
205 with pytest.raises(TypeError, match="Type mismatch"):
206 manager.apply_config_to_tool(mock_tool)
209def test_manager_apply_config_handles_other_errors_gracefully(
210 manager: UnifiedConfigManager,
211 mock_tool: MagicMock,
212) -> None:
213 """Verify non-config errors are caught and logged.
215 Unexpected errors (not ValueError/TypeError) should be caught and
216 logged as warnings, not re-raised.
218 mock_tool: Mock tool instance.
220 mock_tool: Mock tool instance.
223 Args:
224 manager: Configuration manager instance.
225 mock_tool: Mock tool instance.
226 """
227 mock_tool.set_options.side_effect = RuntimeError("Unexpected")
229 with (
230 patch(
231 "lintro.utils.unified_config_manager.is_tool_injectable",
232 return_value=True,
233 ),
234 patch.object(manager, "get_effective_line_length", return_value=100),
235 patch(
236 "lintro.utils.unified_config_manager.load_lintro_tool_config",
237 return_value={},
238 ),
239 ):
240 # Should not raise
241 manager.apply_config_to_tool(mock_tool)
244def test_manager_apply_config_skips_non_injectable_line_length(
245 manager: UnifiedConfigManager,
246 mock_tool: MagicMock,
247) -> None:
248 """Verify line_length is not set for non-injectable tools.
250 When is_tool_injectable returns False, line_length should not be
251 included in the options.
253 mock_tool: Mock tool instance.
255 mock_tool: Mock tool instance.
258 Args:
259 manager: Configuration manager instance.
260 mock_tool: Mock tool instance.
261 """
262 with (
263 patch(
264 "lintro.utils.unified_config_manager.is_tool_injectable",
265 return_value=False,
266 ),
267 patch.object(manager, "get_effective_line_length", return_value=100),
268 patch(
269 "lintro.utils.unified_config_manager.load_lintro_tool_config",
270 return_value={"other_option": True},
271 ),
272 ):
273 manager.apply_config_to_tool(mock_tool)
275 call_kwargs = mock_tool.set_options.call_args[1]
276 assert_that(call_kwargs).does_not_contain_key("line_length")
277 assert_that(call_kwargs).contains_key("other_option")
280# =============================================================================
281# Tests for get_report method
282# =============================================================================
285def test_manager_get_report_returns_string(manager: UnifiedConfigManager) -> None:
286 """Verify get_report returns a string.
288 The report should be a formatted string containing configuration info.
291 Args:
292 manager: Configuration manager instance.
293 """
294 with patch(
295 "lintro.utils.config_reporting.get_config_report",
296 return_value="Report",
297 ):
298 result = manager.get_report()
300 assert_that(result).is_equal_to("Report")
303def test_manager_get_report_delegates_to_config_reporting(
304 manager: UnifiedConfigManager,
305) -> None:
306 """Verify get_report calls the config_reporting module.
308 The report generation is delegated to get_config_report function.
311 Args:
312 manager: Configuration manager instance.
313 """
314 with patch(
315 "lintro.utils.config_reporting.get_config_report",
316 return_value="Detailed Report",
317 ) as mock_report:
318 manager.get_report()
320 mock_report.assert_called_once()
323# =============================================================================
324# Tests for print_report method
325# =============================================================================
328def test_manager_print_report_calls_config_reporting(
329 manager: UnifiedConfigManager,
330) -> None:
331 """Verify print_report delegates to print_config_report.
333 The print_report method should call the print_config_report function
334 from the config_reporting module.
337 Args:
338 manager: Configuration manager instance.
339 """
340 with patch(
341 "lintro.utils.config_reporting.print_config_report",
342 ) as mock_print:
343 manager.print_report()
345 mock_print.assert_called_once()
348def test_manager_print_report_does_not_return_value(
349 manager: UnifiedConfigManager,
350) -> None:
351 """Verify print_report can be called successfully.
353 The method prints to console but doesn't return a value.
356 Args:
357 manager: Configuration manager instance.
358 """
359 with patch("lintro.utils.config_reporting.print_config_report"):
360 manager.print_report() # Should complete without error
363# =============================================================================
364# Integration-style tests for UnifiedConfigManager
365# =============================================================================
368def test_manager_is_dataclass_instance(manager: UnifiedConfigManager) -> None:
369 """Verify UnifiedConfigManager is a proper dataclass instance.
371 The manager should be a dataclass with the expected fields.
374 Args:
375 manager: Configuration manager instance.
376 """
377 import dataclasses
379 assert_that(dataclasses.is_dataclass(manager)).is_true()
380 assert_that(dataclasses.fields(manager)).is_length(3)
383def test_manager_fields_are_accessible(manager: UnifiedConfigManager) -> None:
384 """Verify all manager fields are accessible after initialization.
386 The global_config, tool_configs, and warnings fields should be accessible.
389 Args:
390 manager: Configuration manager instance.
391 """
392 assert_that(manager.global_config).is_instance_of(dict)
393 assert_that(manager.tool_configs).is_instance_of(dict)
394 assert_that(manager.warnings).is_instance_of(list)
397def test_manager_can_be_created_with_default_factory_values() -> None:
398 """Verify manager can be created and has default factory values.
400 The dataclass default_factory functions should create empty containers.
401 """
402 with (
403 patch(
404 "lintro.utils.unified_config_manager.load_lintro_global_config",
405 return_value={},
406 ),
407 patch(
408 "lintro.utils.unified_config_manager.get_tool_config_summary",
409 return_value={},
410 ),
411 patch(
412 "lintro.utils.unified_config_manager.validate_config_consistency",
413 return_value=[],
414 ),
415 ):
416 manager = UnifiedConfigManager()
418 assert_that(manager.global_config).is_empty()
419 assert_that(manager.tool_configs).is_empty()
420 assert_that(manager.warnings).is_empty()