Coverage for tests / integration / tools / test_mypy_integration.py: 100%
46 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"""Integration tests for Mypy tool definition.
3These tests require mypy to be installed and available in PATH.
4They verify the MypyPlugin definition, check command, and set_options method.
5"""
7from __future__ import annotations
9import shutil
10from collections.abc import Callable
11from pathlib import Path
12from typing import TYPE_CHECKING
14import pytest
15from assertpy import assert_that
17if TYPE_CHECKING:
18 from lintro.plugins.base import BaseToolPlugin
20# Skip all tests if mypy is not installed
21pytestmark = pytest.mark.skipif(
22 shutil.which("mypy") is None,
23 reason="mypy not installed",
24)
27@pytest.fixture
28def temp_python_file_with_type_errors(tmp_path: Path) -> str:
29 """Create a temporary Python file with type errors.
31 Creates a file containing code with deliberate type annotation violations
32 that mypy should detect, including:
33 - Passing string arguments where int is expected
34 - Assigning int to a str-typed variable
36 Args:
37 tmp_path: Pytest fixture providing a temporary directory.
39 Returns:
40 Path to the created file as a string.
41 """
42 file_path = tmp_path / "type_errors.py"
43 file_path.write_text(
44 """\
45def add(a: int, b: int) -> int:
46 return a + b
48# Type error: passing string instead of int
49result: int = add("hello", "world")
51def greet(name: str) -> str:
52 return "Hello, " + name
54# Type error: assigning int to str variable
55greeting: str = 42
56""",
57 )
58 return str(file_path)
61@pytest.fixture
62def temp_python_file_type_correct(tmp_path: Path) -> str:
63 """Create a temporary Python file with correct types.
65 Creates a file containing properly typed Python code that should
66 pass mypy type checking without errors.
68 Args:
69 tmp_path: Pytest fixture providing a temporary directory.
71 Returns:
72 Path to the created file as a string.
73 """
74 file_path = tmp_path / "type_correct.py"
75 file_path.write_text(
76 """\
77def add(a: int, b: int) -> int:
78 return a + b
81result: int = add(1, 2)
84def greet(name: str) -> str:
85 return "Hello, " + name
88greeting: str = greet("World")
89""",
90 )
91 return str(file_path)
94# --- Tests for MypyPlugin definition ---
97@pytest.mark.parametrize(
98 ("attr", "expected"),
99 [
100 ("name", "mypy"),
101 ("can_fix", False),
102 ],
103 ids=["name", "can_fix"],
104)
105def test_definition_attributes(
106 get_plugin: Callable[[str], BaseToolPlugin],
107 attr: str,
108 expected: object,
109) -> None:
110 """Verify MypyPlugin definition has correct attribute values.
112 Tests that the plugin definition exposes the expected values for
113 name and can_fix attributes.
115 Args:
116 get_plugin: Fixture factory to get plugin instances.
117 attr: The attribute name to check on the definition.
118 expected: The expected value of the attribute.
119 """
120 mypy_plugin = get_plugin("mypy")
121 assert_that(getattr(mypy_plugin.definition, attr)).is_equal_to(expected)
124def test_definition_file_patterns(get_plugin: Callable[[str], BaseToolPlugin]) -> None:
125 """Verify MypyPlugin definition includes Python file patterns.
127 Tests that the plugin is configured to handle Python files (*.py).
129 Args:
130 get_plugin: Fixture factory to get plugin instances.
131 """
132 mypy_plugin = get_plugin("mypy")
133 assert_that(mypy_plugin.definition.file_patterns).contains("*.py")
136# --- Integration tests for mypy check command ---
139def test_check_file_with_type_errors(
140 get_plugin: Callable[[str], BaseToolPlugin],
141 temp_python_file_with_type_errors: str,
142) -> None:
143 """Verify mypy check detects type errors in problematic files.
145 Runs mypy on a file containing deliberate type violations and verifies
146 that issues are found.
148 Args:
149 get_plugin: Fixture factory to get plugin instances.
150 temp_python_file_with_type_errors: Path to file with type errors.
151 """
152 mypy_plugin = get_plugin("mypy")
153 result = mypy_plugin.check([temp_python_file_with_type_errors], {})
155 assert_that(result).is_not_none()
156 assert_that(result.name).is_equal_to("mypy")
157 assert_that(result.issues_count).is_greater_than(0)
160def test_check_type_correct_file(
161 get_plugin: Callable[[str], BaseToolPlugin],
162 temp_python_file_type_correct: str,
163) -> None:
164 """Verify mypy check passes on type-correct files.
166 Runs mypy on a properly typed file and verifies no issues are found.
168 Args:
169 get_plugin: Fixture factory to get plugin instances.
170 temp_python_file_type_correct: Path to file with correct types.
171 """
172 mypy_plugin = get_plugin("mypy")
173 result = mypy_plugin.check([temp_python_file_type_correct], {})
175 assert_that(result).is_not_none()
176 assert_that(result.name).is_equal_to("mypy")
177 assert_that(result.issues_count).is_equal_to(0)
180def test_check_empty_directory(
181 get_plugin: Callable[[str], BaseToolPlugin],
182 tmp_path: Path,
183) -> None:
184 """Verify mypy check handles empty directories gracefully.
186 Runs mypy on an empty directory and verifies a result is returned
187 without errors.
189 Args:
190 get_plugin: Fixture factory to get plugin instances.
191 tmp_path: Pytest fixture providing a temporary directory.
192 """
193 mypy_plugin = get_plugin("mypy")
194 result = mypy_plugin.check([str(tmp_path)], {})
196 assert_that(result).is_not_none()
199# --- Tests for MypyPlugin.set_options method ---
202@pytest.mark.parametrize(
203 ("option_name", "option_value", "expected"),
204 [
205 ("strict", True, True),
206 ("ignore_missing_imports", True, True),
207 ],
208 ids=["strict", "ignore_missing_imports"],
209)
210def test_set_options(
211 get_plugin: Callable[[str], BaseToolPlugin],
212 option_name: str,
213 option_value: object,
214 expected: object,
215) -> None:
216 """Verify MypyPlugin.set_options correctly sets various options.
218 Tests that plugin options can be set and retrieved correctly.
220 Args:
221 get_plugin: Fixture factory to get plugin instances.
222 option_name: Name of the option to set.
223 option_value: Value to set for the option.
224 expected: Expected value when retrieving the option.
225 """
226 mypy_plugin = get_plugin("mypy")
227 mypy_plugin.set_options(**{option_name: option_value})
228 assert_that(mypy_plugin.options.get(option_name)).is_equal_to(expected)