Coverage for tests / config / test_config_loader.py: 100%
95 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"""Tests for config_loader module."""
3from pathlib import Path
5from assertpy import assert_that
7from lintro.config.config_loader import (
8 _convert_pyproject_to_config,
9 _parse_defaults,
10 _parse_enforce_config,
11 _parse_execution_config,
12 _parse_tool_config,
13 _parse_tools_config,
14 clear_config_cache,
15 get_default_config,
16 load_config,
17)
20def test_empty_data() -> None:
21 """Should return EnforceConfig with None values."""
22 config = _parse_enforce_config({})
24 assert_that(config.line_length).is_none()
25 assert_that(config.target_python).is_none()
28def test_execution_config_empty_data() -> None:
29 """Should return execution config defaults."""
30 config = _parse_execution_config({})
32 assert_that(config.enabled_tools).is_equal_to([])
33 assert_that(config.tool_order).is_equal_to("priority")
34 assert_that(config.fail_fast).is_false()
35 assert_that(config.parallel).is_true()
38def test_string_enabled_tools() -> None:
39 """Should convert single tool string to list."""
40 data = {"enabled_tools": "ruff"}
42 config = _parse_execution_config(data)
44 assert_that(config.enabled_tools).is_equal_to(["ruff"])
47def test_tool_config_empty_data() -> None:
48 """Should return default ToolConfig."""
49 config = _parse_tool_config({})
51 assert_that(config.enabled).is_true()
52 assert_that(config.config_source).is_none()
55def test_disabled_tool() -> None:
56 """Should parse enabled=False."""
57 data = {"enabled": False}
59 config = _parse_tool_config(data)
61 assert_that(config.enabled).is_false()
64def test_tools_config_empty_data() -> None:
65 """Should return empty dict for tools config."""
66 config = _parse_tools_config({})
68 assert_that(config).is_equal_to({})
71def test_with_bool_values() -> None:
72 """Should handle bool as enabled flag."""
73 data = {
74 "ruff": True,
75 "prettier": False,
76 }
78 config = _parse_tools_config(data)
80 assert_that(config["ruff"].enabled).is_true()
81 assert_that(config["prettier"].enabled).is_false()
84def test_defaults_empty_data() -> None:
85 """Should return empty dict for defaults."""
86 defaults = _parse_defaults({})
88 assert_that(defaults).is_equal_to({})
91def test_case_normalization() -> None:
92 """Tool names should be lowercased."""
93 data = {"PRETTIER": {"singleQuote": True}}
95 defaults = _parse_defaults(data)
97 assert_that(defaults).contains("prettier")
98 assert_that(defaults).does_not_contain("PRETTIER")
101def test_convert_pyproject_empty_data() -> None:
102 """Should return structure with empty sections."""
103 result = _convert_pyproject_to_config({})
105 assert_that(result).contains("enforce")
106 assert_that(result).contains("execution")
107 assert_that(result).contains("defaults")
108 assert_that(result).contains("tools")
111def test_enforce_settings() -> None:
112 """Should extract enforce settings."""
113 data = {
114 "line_length": 88,
115 "target_python": "py313",
116 }
118 result = _convert_pyproject_to_config(data)
120 assert_that(result["enforce"]["line_length"]).is_equal_to(88)
121 assert_that(result["enforce"]["target_python"]).is_equal_to("py313")
124def test_tool_sections() -> None:
125 """Should extract tool-specific sections."""
126 data = {
127 "ruff": {"enabled": True},
128 "markdownlint": {"enabled": False},
129 }
131 result = _convert_pyproject_to_config(data)
133 assert_that(result["tools"]["ruff"]).is_equal_to({"enabled": True})
134 assert_that(result["tools"]["markdownlint"]).is_equal_to({"enabled": False})
137def test_execution_settings() -> None:
138 """Should extract execution settings."""
139 data = {
140 "tool_order": "alphabetical",
141 "fail_fast": True,
142 }
144 result = _convert_pyproject_to_config(data)
146 assert_that(result["execution"]["tool_order"]).is_equal_to("alphabetical")
147 assert_that(result["execution"]["fail_fast"]).is_true()
150def test_load_yaml_config_with_defaults(tmp_path: Path) -> None:
151 """Should load .lintro-config.yaml file with defaults section.
153 Args:
154 tmp_path: Temporary directory path for test files.
155 """
156 config_content = """\
157defaults:
158 prettier:
159 singleQuote: true
160 tabWidth: 2
161"""
162 config_file = tmp_path / ".lintro-config.yaml"
163 config_file.write_text(config_content)
165 import os
167 original_cwd = os.getcwd()
168 try:
169 os.chdir(tmp_path)
170 clear_config_cache()
172 config = load_config()
174 assert_that(config.get_tool_defaults("prettier")["singleQuote"]).is_true()
175 assert_that(config.get_tool_defaults("prettier")["tabWidth"]).is_equal_to(2)
176 finally:
177 os.chdir(original_cwd)
180def test_load_explicit_path(tmp_path: Path) -> None:
181 """Should load from explicit path.
183 Args:
184 tmp_path: Temporary directory path for test files.
185 """
186 config_content = """\
187enforce:
188 line_length: 120
189"""
190 config_file = tmp_path / "custom-config.yaml"
191 config_file.write_text(config_content)
193 config = load_config(config_path=str(config_file))
195 assert_that(config.enforce.line_length).is_equal_to(120)
198def test_returns_default_when_no_config(tmp_path: Path) -> None:
199 """Should return default config when no file found.
201 Args:
202 tmp_path: Temporary directory path for test files.
203 """
204 import os
206 original_cwd = os.getcwd()
207 try:
208 os.chdir(tmp_path)
209 clear_config_cache()
211 config = load_config(allow_pyproject_fallback=False)
213 # Should get default empty config
214 assert_that(config.enforce.line_length).is_none()
215 finally:
216 os.chdir(original_cwd)
219def test_returns_sensible_defaults() -> None:
220 """Should return config with sensible defaults."""
221 config = get_default_config()
223 assert_that(config.enforce.line_length).is_equal_to(88)
224 # target_python is None to let tools infer from requires-python
225 assert_that(config.enforce.target_python).is_none()
226 assert_that(config.execution.tool_order).is_equal_to("priority")