Coverage for tests / unit / tools / mypy / test_mypy_plugin.py: 100%

35 statements  

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

1"""Unit tests for mypy plugin.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING 

6 

7import pytest 

8from assertpy import assert_that 

9 

10from lintro.tools.definitions.mypy import ( 

11 MYPY_DEFAULT_EXCLUDE_PATTERNS, 

12 _regex_to_glob, 

13 _split_config_values, 

14) 

15 

16if TYPE_CHECKING: 

17 from lintro.tools.definitions.mypy import MypyPlugin 

18 

19 

20# Tests for _split_config_values helper 

21 

22 

23@pytest.mark.parametrize( 

24 ("input_value", "expected"), 

25 [ 

26 ("a,b,c", ["a", "b", "c"]), 

27 ("a\nb\nc", ["a", "b", "c"]), 

28 ("a,b\nc,d", ["a", "b", "c", "d"]), 

29 (" a , b ", ["a", "b"]), 

30 ("a,,b,", ["a", "b"]), 

31 ], 

32 ids=[ 

33 "comma_separated", 

34 "newline_separated", 

35 "mixed_separators", 

36 "strips_whitespace", 

37 "filters_empty", 

38 ], 

39) 

40def test_split_config_values(input_value: str, expected: list[str]) -> None: 

41 """Split config values correctly. 

42 

43 Args: 

44 input_value: The input string to split. 

45 expected: The expected list of split values. 

46 """ 

47 result = _split_config_values(input_value) 

48 assert_that(result).is_equal_to(expected) 

49 

50 

51# Tests for _regex_to_glob helper 

52 

53 

54@pytest.mark.parametrize( 

55 ("input_pattern", "expected"), 

56 [ 

57 ("^test$", "test"), 

58 ("test.*", "test*"), 

59 ("build/", "build/**"), 

60 ("^.*/test_samples/.*$", "*/test_samples/*"), 

61 ], 

62 ids=[ 

63 "strips_anchors", 

64 "converts_wildcard", 

65 "adds_glob_for_directory", 

66 "complex_pattern", 

67 ], 

68) 

69def test_regex_to_glob(input_pattern: str, expected: str) -> None: 

70 """Convert regex patterns to glob patterns. 

71 

72 Args: 

73 input_pattern: The regex pattern to convert. 

74 expected: The expected glob pattern. 

75 """ 

76 result = _regex_to_glob(input_pattern) 

77 assert_that(result).is_equal_to(expected) 

78 

79 

80@pytest.mark.parametrize( 

81 ("option_name", "option_value"), 

82 [ 

83 ("strict", True), 

84 ("ignore_missing_imports", False), 

85 ("python_version", "3.10"), 

86 ("config_file", "mypy.ini"), 

87 ("cache_dir", ".mypy_cache"), 

88 ], 

89 ids=[ 

90 "strict", 

91 "ignore_missing_imports", 

92 "python_version", 

93 "config_file", 

94 "cache_dir", 

95 ], 

96) 

97def test_set_options_valid( 

98 mypy_plugin: MypyPlugin, 

99 option_name: str, 

100 option_value: object, 

101) -> None: 

102 """Set valid options correctly. 

103 

104 Args: 

105 mypy_plugin: The MypyPlugin instance to test. 

106 option_name: The name of the option to set. 

107 option_value: The value to set for the option. 

108 """ 

109 mypy_plugin.set_options(**{option_name: option_value}) # type: ignore[arg-type] 

110 assert_that(mypy_plugin.options.get(option_name)).is_equal_to(option_value) 

111 

112 

113# Tests for MypyPlugin.set_options method - invalid types 

114 

115 

116@pytest.mark.parametrize( 

117 ("option_name", "invalid_value", "error_match"), 

118 [ 

119 ("strict", "yes", "strict must be a boolean"), 

120 ("ignore_missing_imports", "yes", "ignore_missing_imports must be a boolean"), 

121 ("python_version", 310, "python_version must be a string"), 

122 ("config_file", 123, "config_file must be a string"), 

123 ("cache_dir", 123, "cache_dir must be a string"), 

124 ], 

125 ids=[ 

126 "invalid_strict_type", 

127 "invalid_ignore_missing_imports_type", 

128 "invalid_python_version_type", 

129 "invalid_config_file_type", 

130 "invalid_cache_dir_type", 

131 ], 

132) 

133def test_set_options_invalid_type( 

134 mypy_plugin: MypyPlugin, 

135 option_name: str, 

136 invalid_value: object, 

137 error_match: str, 

138) -> None: 

139 """Raise ValueError for invalid option types. 

140 

141 Args: 

142 mypy_plugin: The MypyPlugin instance to test. 

143 option_name: The name of the option to test. 

144 invalid_value: An invalid value for the option. 

145 error_match: The expected error message pattern. 

146 """ 

147 with pytest.raises(ValueError, match=error_match): 

148 mypy_plugin.set_options(**{option_name: invalid_value}) # type: ignore[arg-type] 

149 

150 

151# Tests for MypyPlugin._build_effective_excludes method 

152 

153 

154def test_build_effective_excludes_includes_defaults(mypy_plugin: MypyPlugin) -> None: 

155 """Include default exclude patterns. 

156 

157 Args: 

158 mypy_plugin: The MypyPlugin instance to test. 

159 """ 

160 result = mypy_plugin._build_effective_excludes(None) 

161 

162 for pattern in MYPY_DEFAULT_EXCLUDE_PATTERNS: 

163 assert_that(pattern in result).is_true() 

164 

165 

166def test_build_effective_excludes_adds_configured(mypy_plugin: MypyPlugin) -> None: 

167 """Add configured exclude patterns. 

168 

169 Args: 

170 mypy_plugin: The MypyPlugin instance to test. 

171 """ 

172 result = mypy_plugin._build_effective_excludes("custom_dir/") 

173 

174 assert_that("custom_dir/**" in result).is_true() 

175 

176 

177def test_build_effective_excludes_handles_list(mypy_plugin: MypyPlugin) -> None: 

178 """Handle list of exclude patterns. 

179 

180 Args: 

181 mypy_plugin: The MypyPlugin instance to test. 

182 """ 

183 result = mypy_plugin._build_effective_excludes(["dir1/", "dir2/"]) 

184 

185 assert_that("dir1/**" in result).is_true() 

186 assert_that("dir2/**" in result).is_true() 

187 

188 

189def test_build_effective_excludes_converts_regex(mypy_plugin: MypyPlugin) -> None: 

190 """Convert regex patterns to globs. 

191 

192 Args: 

193 mypy_plugin: The MypyPlugin instance to test. 

194 """ 

195 result = mypy_plugin._build_effective_excludes(["^tests/.*$"]) 

196 

197 assert_that("tests/*" in result).is_true()