Coverage for tests / unit / plugins / conftest.py: 89%
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"""Pytest configuration for plugin unit tests."""
3from __future__ import annotations
5from dataclasses import dataclass, field
6from typing import TYPE_CHECKING, Any
8import pytest
10from lintro.models.core.tool_result import ToolResult
11from lintro.plugins.base import BaseToolPlugin
12from lintro.plugins.discovery import reset_discovery
13from lintro.plugins.protocol import ToolDefinition
14from lintro.plugins.registry import ToolRegistry
16if TYPE_CHECKING:
17 from collections.abc import Generator
20@dataclass
21class FakeToolPlugin(BaseToolPlugin):
22 """Fake tool plugin for testing."""
24 _definition: ToolDefinition = field(
25 default_factory=lambda: ToolDefinition(
26 name="fake-tool",
27 description="Fake tool for testing",
28 file_patterns=["*.py"],
29 can_fix=True,
30 default_timeout=30,
31 ),
32 )
34 @property
35 def definition(self) -> ToolDefinition:
36 """Return the tool definition.
38 Returns:
39 The tool definition.
40 """
41 return self._definition
43 def check(self, paths: list[str], options: dict[str, object]) -> ToolResult:
44 """Fake check implementation.
46 Args:
47 paths: List of file paths to check.
48 options: Dictionary of options for the check.
50 Returns:
51 A ToolResult indicating success.
52 """
53 return ToolResult(name="fake-tool", success=True, output="OK", issues_count=0)
56@pytest.fixture
57def fake_tool_plugin() -> FakeToolPlugin:
58 """Provide a FakeToolPlugin instance for testing.
60 Returns:
61 A FakeToolPlugin instance.
62 """
63 return FakeToolPlugin()
66@pytest.fixture
67def clean_registry() -> Generator[None]:
68 """Save and restore registry state for test isolation.
70 This fixture saves the current registry state before the test
71 and restores it after, ensuring tests don't pollute each other.
73 Yields:
74 None: Saves and restores registry state.
75 """
76 original_tools = dict(ToolRegistry._tools)
77 original_instances = dict(ToolRegistry._instances)
78 try:
79 yield
80 finally:
81 ToolRegistry._tools = original_tools
82 ToolRegistry._instances = original_instances
85@pytest.fixture
86def empty_registry() -> Generator[None]:
87 """Provide an empty registry for testing.
89 Clears the registry before the test and restores it after.
91 Yields:
92 None: Clears and restores registry state.
93 """
94 original_tools = dict(ToolRegistry._tools)
95 original_instances = dict(ToolRegistry._instances)
96 ToolRegistry.clear()
97 try:
98 yield
99 finally:
100 ToolRegistry._tools = original_tools
101 ToolRegistry._instances = original_instances
104@pytest.fixture
105def reset_discovery_state() -> Generator[None]:
106 """Reset discovery state before and after test.
108 Yields:
109 None: Resets discovery state.
110 """
111 reset_discovery()
112 try:
113 yield
114 finally:
115 reset_discovery()
118def create_fake_plugin(
119 name: str = "fake-tool",
120 description: str = "Fake tool for testing",
121 file_patterns: list[str] | None = None,
122 can_fix: bool = True,
123) -> type[BaseToolPlugin]:
124 """Factory function to create fake plugin classes with custom attributes.
126 Args:
127 name: Tool name.
128 description: Tool description.
129 file_patterns: File patterns the tool handles.
130 can_fix: Whether the tool can fix issues.
132 Returns:
133 A new FakePlugin class with the specified attributes.
134 """
135 patterns: list[str] = file_patterns if file_patterns is not None else ["*.py"]
137 @dataclass
138 class DynamicFakePlugin(BaseToolPlugin):
139 @property
140 def definition(self) -> ToolDefinition:
141 return ToolDefinition(
142 name=name,
143 description=description,
144 file_patterns=patterns,
145 can_fix=can_fix,
146 )
148 def check(self, paths: list[str], options: dict[str, Any]) -> ToolResult:
149 return ToolResult(name=name, success=True, output="OK", issues_count=0)
151 return DynamicFakePlugin