Coverage for tests / integration / test_mypy_integration.py: 98%

54 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Integration tests for Mypy tool.""" 

2 

3from __future__ import annotations 

4 

5import contextlib 

6import os 

7import shutil 

8import tempfile 

9from collections.abc import Iterator 

10from pathlib import Path 

11from typing import TYPE_CHECKING 

12 

13import pytest 

14from assertpy import assert_that 

15 

16from lintro.plugins import ToolRegistry 

17 

18if TYPE_CHECKING: 

19 from lintro.plugins.base import BaseToolPlugin 

20 

21 

22@pytest.fixture(autouse=True) 

23def set_lintro_test_mode_env(lintro_test_mode: object) -> Iterator[None]: 

24 """Disable config injection for predictable CLI args in tests. 

25 

26 Args: 

27 lintro_test_mode: Pytest fixture that enables lintro test mode. 

28 

29 Yields: 

30 None: Allows the test to run with modified environment. 

31 """ 

32 yield 

33 

34 

35@pytest.fixture 

36def mypy_tool() -> BaseToolPlugin: 

37 """Create a mypy tool plugin instance for testing. 

38 

39 Returns: 

40 BaseToolPlugin: Configured tool plugin instance for assertions. 

41 """ 

42 tool = ToolRegistry.get("mypy") 

43 assert tool is not None, "mypy tool not found in registry" 

44 return tool 

45 

46 

47@pytest.fixture 

48def mypy_violation_file() -> Iterator[str]: 

49 """Copy the mypy_violations.py sample to a temp directory for testing. 

50 

51 Yields: 

52 str: Path to the temporary file containing known mypy violations. 

53 """ 

54 repo_root = Path(__file__).resolve().parent.parent.parent 

55 src = ( 

56 repo_root / "test_samples" / "tools" / "python" / "mypy" / "mypy_violations.py" 

57 ) 

58 if not src.exists(): 

59 pytest.skip(f"Sample file {src} does not exist") 

60 with tempfile.TemporaryDirectory() as tmpdir: 

61 dst = os.path.join(tmpdir, "mypy_violations.py") 

62 shutil.copy(src, dst) 

63 yield dst 

64 

65 

66@pytest.fixture 

67def mypy_clean_file() -> Iterator[str]: 

68 """Create a temporary clean Python file for mypy. 

69 

70 Yields: 

71 str: Path to a temporary Python file without mypy violations. 

72 """ 

73 content = ( 

74 "from typing import Annotated\n\n" 

75 "def add(a: int, b: int) -> int:\n" 

76 " return a + b\n" 

77 ) 

78 with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: 

79 f.write(content) 

80 file_path = f.name 

81 try: 

82 yield file_path 

83 finally: 

84 with contextlib.suppress(FileNotFoundError): 

85 os.unlink(file_path) 

86 

87 

88def test_mypy_tool_available(mypy_tool: BaseToolPlugin) -> None: 

89 """Test that mypy tool is registered and available. 

90 

91 Args: 

92 mypy_tool: Pytest fixture providing the mypy tool instance. 

93 """ 

94 assert_that(mypy_tool).is_not_none() 

95 assert_that(mypy_tool.definition.name).is_equal_to("mypy") 

96 

97 

98def test_mypy_check_finds_violations( 

99 mypy_tool: BaseToolPlugin, 

100 mypy_violation_file: str, 

101) -> None: 

102 """Test that mypy check finds type errors in violation file. 

103 

104 Args: 

105 mypy_tool: Pytest fixture providing the mypy tool instance. 

106 mypy_violation_file: Pytest fixture providing file with type errors. 

107 """ 

108 result = mypy_tool.check([mypy_violation_file], {}) 

109 

110 assert_that(result).is_not_none() 

111 # Mypy should find type errors in the violations file 

112 assert_that( 

113 result.success is False 

114 or (result.issues is not None and len(result.issues) > 0), 

115 ).is_true() 

116 

117 

118def test_mypy_check_clean_file( 

119 mypy_tool: BaseToolPlugin, 

120 mypy_clean_file: str, 

121) -> None: 

122 """Test that mypy check passes on clean file. 

123 

124 Args: 

125 mypy_tool: Pytest fixture providing the mypy tool instance. 

126 mypy_clean_file: Pytest fixture providing path to clean file. 

127 """ 

128 result = mypy_tool.check([mypy_clean_file], {}) 

129 

130 assert_that(result).is_not_none() 

131 assert_that(result.success).is_true() 

132 assert_that(result.issues is None or len(result.issues) == 0).is_true() 

133 

134 

135def test_mypy_handles_empty_path_list(mypy_tool: BaseToolPlugin) -> None: 

136 """Test that mypy handles empty path list gracefully. 

137 

138 Args: 

139 mypy_tool: Pytest fixture providing the mypy tool instance. 

140 """ 

141 result = mypy_tool.check([], {}) 

142 

143 # Should complete without crashing 

144 assert_that(result).is_not_none()