Coverage for tests / unit / tools / conftest.py: 47%
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"""Shared fixtures for tool unit tests.
3Note: This file contains core fixtures only. Additional fixtures and tests
4have been split into separate files:
5- tests/unit/tools/assertions/conftest.py - Assertion helper fixtures
6- tests/unit/tools/test_plugin_definitions.py - Parametrized definition tests
7- tests/unit/tools/test_common_behaviors.py - Common tool behavior tests
8"""
10from __future__ import annotations
12from collections.abc import Callable, Generator
13from typing import TYPE_CHECKING, Any
14from unittest.mock import MagicMock, Mock, patch
16import pytest
18from lintro.enums.tool_name import ToolName
19from lintro.models.core.tool_result import ToolResult
20from lintro.plugins.base import BaseToolPlugin, ExecutionContext
22if TYPE_CHECKING:
23 from lintro.tools.definitions.clippy import ClippyPlugin
24 from lintro.tools.definitions.mypy import MypyPlugin
25 from lintro.tools.definitions.tsc import TscPlugin
28@pytest.fixture
29def mock_subprocess_run() -> Generator[MagicMock, None, None]:
30 """Mock subprocess.run for tool testing.
32 Yields:
33 MagicMock: Configured mock for subprocess operations.
34 """
35 with patch("subprocess.run") as mock_run:
36 mock_process = Mock()
37 mock_process.returncode = 0
38 mock_process.stdout = ""
39 mock_process.stderr = ""
40 mock_run.return_value = mock_process
41 yield mock_run
44@pytest.fixture
45def mock_tool_config() -> dict[str, Any]:
46 """Provide a mock tool configuration.
48 Returns:
49 dict: Sample tool configuration dictionary.
50 """
51 return {
52 "priority": 50,
53 "file_patterns": ["*.py"],
54 "tool_type": "linter",
55 "options": {
56 "timeout": 30,
57 "line_length": 88,
58 },
59 }
62@pytest.fixture
63def mock_tool_result() -> Mock:
64 """Provide a mock tool result.
66 Returns:
67 Mock: Configured mock tool result with default values.
68 """
69 result = Mock()
70 result.name = "test_tool"
71 result.success = True
72 result.output = ""
73 result.issues_count = 0
74 result.issues = []
75 return result
78@pytest.fixture
79def mypy_plugin() -> MypyPlugin:
80 """Provide a MypyPlugin instance for testing.
82 Returns:
83 A MypyPlugin instance.
84 """
85 from lintro.tools.definitions.mypy import MypyPlugin
87 return MypyPlugin()
90@pytest.fixture
91def clippy_plugin() -> ClippyPlugin:
92 """Provide a ClippyPlugin instance for testing.
94 Returns:
95 A ClippyPlugin instance.
96 """
97 from lintro.tools.definitions.clippy import ClippyPlugin
99 return ClippyPlugin()
102@pytest.fixture
103def tsc_plugin() -> TscPlugin:
104 """Provide a TscPlugin instance for testing.
106 Returns:
107 A TscPlugin instance.
108 """
109 from lintro.tools.definitions.tsc import TscPlugin
111 return TscPlugin()
114# -----------------------------------------------------------------------------
115# Shared patch fixtures for subprocess and tool availability
116# -----------------------------------------------------------------------------
119@pytest.fixture
120def patch_subprocess_success() -> Callable[[str, int], Any]:
121 """Factory for patching subprocess with success result.
123 Returns:
124 A factory function that creates a context manager to patch subprocess.
126 Example:
127 def test_something(patch_subprocess_success):
128 with patch_subprocess_success(output="OK"):
129 # subprocess.run will return success with "OK" output
130 """
131 from contextlib import contextmanager
133 @contextmanager
134 def _patch(output: str = "", returncode: int = 0) -> Generator[MagicMock]:
135 mock_result = MagicMock()
136 mock_result.stdout = output
137 mock_result.stderr = ""
138 mock_result.returncode = returncode
139 with patch("subprocess.run", return_value=mock_result) as mock_run:
140 yield mock_run
142 return _patch
145@pytest.fixture
146def patch_tool_available() -> Callable[[], Any]:
147 """Factory for patching tool availability to return True.
149 Returns:
150 A factory function that creates a context manager for patching.
152 Example:
153 def test_something(patch_tool_available):
154 with patch_tool_available():
155 # _check_tool_available will return True
156 """
157 from contextlib import contextmanager
159 @contextmanager
160 def _patch() -> Generator[MagicMock]:
161 with patch.object(
162 BaseToolPlugin,
163 "_check_tool_available",
164 return_value=True,
165 ) as mock_check:
166 yield mock_check
168 return _patch
171# -----------------------------------------------------------------------------
172# Mock tool factory fixtures
173# -----------------------------------------------------------------------------
176@pytest.fixture
177def mock_tool_factory() -> Callable[..., MagicMock]:
178 """Factory for creating mock tool plugin instances.
180 Returns:
181 A factory function that creates configured MagicMock objects
182 that behave like tool plugins.
184 Example:
185 def test_something(mock_tool_factory):
186 mock_tool = mock_tool_factory(
187 name=ToolName.RUFF,
188 file_patterns=["*.py"],
189 can_fix=True,
190 )
191 assert mock_tool.definition.name == ToolName.RUFF
192 """
194 def _create(
195 name: ToolName = ToolName.RUFF,
196 file_patterns: list[str] | None = None,
197 can_fix: bool = True,
198 timeout: int = 30,
199 options: dict[str, Any] | None = None,
200 exclude_patterns: list[str] | None = None,
201 include_venv: bool = False,
202 executable_command: list[str] | None = None,
203 cwd: str = "/test/project",
204 ) -> MagicMock:
205 tool = MagicMock()
206 tool.definition.name = name
207 tool.definition.file_patterns = file_patterns or ["*.py"]
208 tool.definition.can_fix = can_fix
209 tool.options = options or {"timeout": timeout}
210 tool.exclude_patterns = exclude_patterns or []
211 tool.include_venv = include_venv
212 tool._default_timeout = timeout
214 # Mock common methods
215 tool._get_executable_command.return_value = executable_command or [
216 str(name).lower(),
217 ]
218 tool._verify_tool_version.return_value = None
219 tool._validate_paths.return_value = None
220 tool._get_cwd.return_value = cwd
221 tool._build_config_args.return_value = []
222 tool._get_enforced_settings.return_value = {}
224 return tool
226 return _create
229# -----------------------------------------------------------------------------
230# Mock execution context fixtures
231# -----------------------------------------------------------------------------
234@pytest.fixture
235def mock_execution_context_factory() -> Callable[..., MagicMock]:
236 """Factory for creating mock ExecutionContext instances.
238 Returns:
239 A factory function that creates configured MagicMock objects
240 that behave like ExecutionContext.
242 Example:
243 def test_something(mock_execution_context_factory):
244 ctx = mock_execution_context_factory(files=["test.py"])
245 assert ctx.files == ["test.py"]
246 """
248 def _create(
249 files: list[str] | None = None,
250 rel_files: list[str] | None = None,
251 cwd: str | None = None,
252 early_result: ToolResult | None = None,
253 timeout: int | None = None,
254 should_skip: bool = False,
255 ) -> MagicMock:
256 ctx = MagicMock(spec=ExecutionContext)
257 ctx.files = files if files is not None else []
258 ctx.rel_files = rel_files if rel_files is not None else []
259 ctx.cwd = cwd
260 ctx.early_result = early_result
261 ctx.timeout = timeout if timeout is not None else 30
262 # should_skip is True if explicitly set OR if early_result is provided
263 ctx.should_skip = should_skip or (early_result is not None)
264 return ctx
266 return _create
269@pytest.fixture
270def mock_execution_context_for_tool(
271 mock_execution_context_factory: Callable[..., MagicMock],
272) -> Callable[..., MagicMock]:
273 """Alias for mock_execution_context_factory for tool tests.
275 This provides backward compatibility for tests using the old fixture name.
277 Args:
278 mock_execution_context_factory: Factory function for creating mock execution contexts.
280 Returns:
281 The same factory function as mock_execution_context_factory.
282 """
283 return mock_execution_context_factory