Coverage for tests / unit / config / test_config_loader.py: 100%
53 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 configuration loaders from pyproject.toml."""
3from __future__ import annotations
5from pathlib import Path
6from unittest.mock import patch
8import pytest
9from assertpy import assert_that
11from lintro.config.config_loader import _load_pyproject_fallback
12from lintro.utils.config import (
13 clear_pyproject_cache,
14 load_lintro_tool_config,
15)
18def test_load_lintro_tool_config(
19 tmp_path: Path,
20 monkeypatch: pytest.MonkeyPatch,
21) -> None:
22 """Load tool-specific config sections from pyproject.
24 Args:
25 tmp_path: Temporary directory for pyproject creation.
26 monkeypatch: Pytest monkeypatch to chdir into temp dir.
27 """
28 # Clear both LRU caches to ensure we load from the test directory
29 clear_pyproject_cache()
31 pyproject = tmp_path / "pyproject.toml"
32 pyproject.write_text(
33 (
34 "[tool.lintro]\n"
35 "[tool.lintro.ruff]\n"
36 'select = ["E", "F"]\n'
37 "line_length = 88\n"
38 "[tool.lintro.prettier]\n"
39 "single_quote = true\n"
40 ),
41 )
42 monkeypatch.chdir(tmp_path)
43 ruff_cfg = load_lintro_tool_config("ruff")
44 assert_that(ruff_cfg.get("line_length")).is_equal_to(88)
45 assert_that(ruff_cfg.get("select")).is_equal_to(["E", "F"])
46 prettier_cfg = load_lintro_tool_config("prettier")
47 assert_that(prettier_cfg.get("single_quote") is True).is_true()
48 missing_cfg = load_lintro_tool_config("yamllint")
49 assert_that(missing_cfg).is_equal_to({})
52def test_config_loader_handles_missing_and_malformed_pyproject(
53 tmp_path: Path,
54 monkeypatch: pytest.MonkeyPatch,
55) -> None:
56 """Validate loaders handle missing and malformed pyproject files.
58 Args:
59 tmp_path: Temporary directory used to simulate project roots.
60 monkeypatch: Pytest monkeypatch fixture for chdir and environment.
61 """
62 # Clear both LRU caches to ensure we load from the test directory
63 clear_pyproject_cache()
65 from lintro.utils import config as cfg
67 # 1) Missing pyproject.toml
68 monkeypatch.chdir(tmp_path)
69 assert_that(cfg.load_lintro_tool_config("ruff")).is_equal_to({})
70 assert_that(cfg.load_post_checks_config()).is_equal_to({})
72 # 2) Malformed pyproject.toml should be handled gracefully
73 (tmp_path / "pyproject.toml").write_text("not: [valid\n")
74 assert_that(cfg.load_lintro_tool_config("ruff")).is_equal_to({})
75 assert_that(cfg.load_post_checks_config()).is_equal_to({})
78# =============================================================================
79# TOML Parse Error Logging Tests
80# =============================================================================
83def test_load_pyproject_toml_parse_error_logs_warning(
84 tmp_path: Path,
85 monkeypatch: pytest.MonkeyPatch,
86) -> None:
87 """Verify TOML parse error logs warning with file path and error details.
89 Args:
90 tmp_path: Pytest temporary directory fixture.
91 monkeypatch: Pytest monkeypatch fixture for chdir.
92 """
93 clear_pyproject_cache()
95 pyproject = tmp_path / "pyproject.toml"
96 pyproject.write_text("invalid: [toml content")
97 monkeypatch.chdir(tmp_path)
99 with patch("lintro.config.config_loader.logger") as mock_logger:
100 result, path = _load_pyproject_fallback()
102 assert_that(result).is_equal_to({})
103 assert_that(path).is_none()
104 mock_logger.warning.assert_called_once()
105 warning_msg = mock_logger.warning.call_args[0][0]
106 assert_that(warning_msg).contains("Failed to parse pyproject.toml")
107 assert_that(warning_msg).contains(str(pyproject))
110def test_load_pyproject_os_error_logs_debug(
111 tmp_path: Path,
112 monkeypatch: pytest.MonkeyPatch,
113) -> None:
114 """Verify OS error reading pyproject.toml logs debug message.
116 Args:
117 tmp_path: Pytest temporary directory fixture.
118 monkeypatch: Pytest monkeypatch fixture for chdir.
119 """
120 clear_pyproject_cache()
122 pyproject = tmp_path / "pyproject.toml"
123 pyproject.write_text("[tool.lintro]")
124 monkeypatch.chdir(tmp_path)
126 with (
127 patch("lintro.config.config_loader.logger") as mock_logger,
128 patch("pathlib.Path.open", side_effect=OSError("Permission denied")),
129 ):
130 result, path = _load_pyproject_fallback()
132 assert_that(result).is_equal_to({})
133 assert_that(path).is_none()
134 mock_logger.debug.assert_called_once()
135 debug_msg = mock_logger.debug.call_args[0][0]
136 assert_that(debug_msg).contains("Could not read pyproject.toml")