Coverage for tests / unit / tools / test_tool_definitions.py: 100%

40 statements  

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

1"""Consolidated tests for all tool definitions. 

2 

3This module provides parametrized tests to verify that all tool plugins 

4have correct definition properties. This ensures consistency across the 

5codebase and catches definition errors early. 

6""" 

7 

8from __future__ import annotations 

9 

10from typing import Any 

11 

12import pytest 

13from assertpy import assert_that 

14 

15from lintro.enums.tool_name import ToolName 

16 

17# Tool specifications: (name, class, timeout, priority, can_fix) 

18# Some tools need special initialization (mocked dependencies) 

19TOOL_SPECS = [ 

20 # (tool_name, module_path, class_name, timeout, priority, can_fix) 

21 (ToolName.RUFF, "lintro.tools.definitions.ruff", "RuffPlugin", 30, 85, True), 

22 (ToolName.BLACK, "lintro.tools.definitions.black", "BlackPlugin", 30, 90, True), 

23 (ToolName.CLIPPY, "lintro.tools.definitions.clippy", "ClippyPlugin", 120, 85, True), 

24 (ToolName.MYPY, "lintro.tools.definitions.mypy", "MypyPlugin", 60, 82, False), 

25 ( 

26 ToolName.YAMLLINT, 

27 "lintro.tools.definitions.yamllint", 

28 "YamllintPlugin", 

29 15, 

30 40, 

31 False, 

32 ), 

33 ( 

34 ToolName.HADOLINT, 

35 "lintro.tools.definitions.hadolint", 

36 "HadolintPlugin", 

37 30, 

38 50, 

39 False, 

40 ), 

41 ( 

42 ToolName.PYTEST, 

43 "lintro.tools.definitions.pytest", 

44 "PytestPlugin", 

45 300, 

46 90, 

47 False, 

48 ), 

49 ( 

50 ToolName.MARKDOWNLINT, 

51 "lintro.tools.definitions.markdownlint", 

52 "MarkdownlintPlugin", 

53 30, 

54 30, 

55 False, 

56 ), 

57 ( 

58 ToolName.ACTIONLINT, 

59 "lintro.tools.definitions.actionlint", 

60 "ActionlintPlugin", 

61 30, 

62 40, 

63 False, 

64 ), 

65 (ToolName.BANDIT, "lintro.tools.definitions.bandit", "BanditPlugin", 30, 90, False), 

66] 

67 

68 

69def _create_plugin_instance(module_path: str, class_name: str) -> Any: 

70 """Dynamically import and instantiate a plugin class. 

71 

72 Args: 

73 module_path: Full module path to the plugin class. 

74 class_name: Name of the plugin class. 

75 

76 Returns: 

77 An instance of the plugin class. 

78 """ 

79 import importlib 

80 

81 # Safe: module_path comes from hardcoded TOOL_SPECS, not user input 

82 module = importlib.import_module(module_path) # nosemgrep: non-literal-import 

83 plugin_class = getattr(module, class_name) 

84 return plugin_class() 

85 

86 

87# ============================================================================= 

88# Tests for tool definition properties 

89# ============================================================================= 

90 

91 

92@pytest.mark.parametrize( 

93 ( 

94 "tool_name", 

95 "module_path", 

96 "class_name", 

97 "expected_timeout", 

98 "expected_priority", 

99 "expected_can_fix", 

100 ), 

101 TOOL_SPECS, 

102 ids=[spec[0] for spec in TOOL_SPECS], 

103) 

104def test_tool_definition_name( 

105 tool_name: str, 

106 module_path: str, 

107 class_name: str, 

108 expected_timeout: int, 

109 expected_priority: int, 

110 expected_can_fix: bool, 

111) -> None: 

112 """Tool has correct name in definition. 

113 

114 Args: 

115 tool_name: Name of the tool. 

116 module_path: Module path containing the tool plugin. 

117 class_name: Class name of the tool plugin. 

118 expected_timeout: Expected timeout value for the tool. 

119 expected_priority: Expected priority value for the tool. 

120 expected_can_fix: Whether the tool can perform fixes. 

121 """ 

122 plugin = _create_plugin_instance(module_path, class_name) 

123 assert_that(plugin.definition.name).is_equal_to(tool_name) 

124 

125 

126@pytest.mark.parametrize( 

127 ( 

128 "tool_name", 

129 "module_path", 

130 "class_name", 

131 "expected_timeout", 

132 "expected_priority", 

133 "expected_can_fix", 

134 ), 

135 TOOL_SPECS, 

136 ids=[spec[0] for spec in TOOL_SPECS], 

137) 

138def test_tool_definition_has_description( 

139 tool_name: str, 

140 module_path: str, 

141 class_name: str, 

142 expected_timeout: int, 

143 expected_priority: int, 

144 expected_can_fix: bool, 

145) -> None: 

146 """Tool has non-empty description in definition. 

147 

148 Args: 

149 tool_name: Name of the tool. 

150 module_path: Module path containing the tool plugin. 

151 class_name: Class name of the tool plugin. 

152 expected_timeout: Expected timeout value for the tool. 

153 expected_priority: Expected priority value for the tool. 

154 expected_can_fix: Whether the tool can perform fixes. 

155 """ 

156 plugin = _create_plugin_instance(module_path, class_name) 

157 assert_that(plugin.definition.description).is_not_empty() 

158 

159 

160@pytest.mark.parametrize( 

161 ( 

162 "tool_name", 

163 "module_path", 

164 "class_name", 

165 "expected_timeout", 

166 "expected_priority", 

167 "expected_can_fix", 

168 ), 

169 TOOL_SPECS, 

170 ids=[spec[0] for spec in TOOL_SPECS], 

171) 

172def test_tool_definition_timeout( 

173 tool_name: str, 

174 module_path: str, 

175 class_name: str, 

176 expected_timeout: int, 

177 expected_priority: int, 

178 expected_can_fix: bool, 

179) -> None: 

180 """Tool has correct default timeout. 

181 

182 Args: 

183 tool_name: Name of the tool. 

184 module_path: Module path containing the tool plugin. 

185 class_name: Class name of the tool plugin. 

186 expected_timeout: Expected timeout value for the tool. 

187 expected_priority: Expected priority value for the tool. 

188 expected_can_fix: Whether the tool can perform fixes. 

189 """ 

190 plugin = _create_plugin_instance(module_path, class_name) 

191 assert_that(plugin.definition.default_timeout).is_equal_to(expected_timeout) 

192 

193 

194@pytest.mark.parametrize( 

195 ( 

196 "tool_name", 

197 "module_path", 

198 "class_name", 

199 "expected_timeout", 

200 "expected_priority", 

201 "expected_can_fix", 

202 ), 

203 TOOL_SPECS, 

204 ids=[spec[0] for spec in TOOL_SPECS], 

205) 

206def test_tool_definition_priority( 

207 tool_name: str, 

208 module_path: str, 

209 class_name: str, 

210 expected_timeout: int, 

211 expected_priority: int, 

212 expected_can_fix: bool, 

213) -> None: 

214 """Tool has correct priority. 

215 

216 Args: 

217 tool_name: Name of the tool. 

218 module_path: Module path containing the tool plugin. 

219 class_name: Class name of the tool plugin. 

220 expected_timeout: Expected timeout value for the tool. 

221 expected_priority: Expected priority value for the tool. 

222 expected_can_fix: Whether the tool can perform fixes. 

223 """ 

224 plugin = _create_plugin_instance(module_path, class_name) 

225 assert_that(plugin.definition.priority).is_equal_to(expected_priority) 

226 

227 

228@pytest.mark.parametrize( 

229 ( 

230 "tool_name", 

231 "module_path", 

232 "class_name", 

233 "expected_timeout", 

234 "expected_priority", 

235 "expected_can_fix", 

236 ), 

237 TOOL_SPECS, 

238 ids=[spec[0] for spec in TOOL_SPECS], 

239) 

240def test_tool_definition_can_fix( 

241 tool_name: str, 

242 module_path: str, 

243 class_name: str, 

244 expected_timeout: int, 

245 expected_priority: int, 

246 expected_can_fix: bool, 

247) -> None: 

248 """Tool has correct can_fix value. 

249 

250 Args: 

251 tool_name: Name of the tool. 

252 module_path: Module path containing the tool plugin. 

253 class_name: Class name of the tool plugin. 

254 expected_timeout: Expected timeout value for the tool. 

255 expected_priority: Expected priority value for the tool. 

256 expected_can_fix: Whether the tool can perform fixes. 

257 """ 

258 plugin = _create_plugin_instance(module_path, class_name) 

259 assert_that(plugin.definition.can_fix).is_equal_to(expected_can_fix) 

260 

261 

262# ============================================================================= 

263# Tests for tool definition validation 

264# ============================================================================= 

265 

266 

267@pytest.mark.parametrize( 

268 ( 

269 "tool_name", 

270 "module_path", 

271 "class_name", 

272 "expected_timeout", 

273 "expected_priority", 

274 "expected_can_fix", 

275 ), 

276 TOOL_SPECS, 

277 ids=[spec[0] for spec in TOOL_SPECS], 

278) 

279def test_tool_has_file_patterns( 

280 tool_name: str, 

281 module_path: str, 

282 class_name: str, 

283 expected_timeout: int, 

284 expected_priority: int, 

285 expected_can_fix: bool, 

286) -> None: 

287 """Tool has non-empty file patterns. 

288 

289 Args: 

290 tool_name: Name of the tool. 

291 module_path: Module path containing the tool plugin. 

292 class_name: Class name of the tool plugin. 

293 expected_timeout: Expected timeout value for the tool. 

294 expected_priority: Expected priority value for the tool. 

295 expected_can_fix: Whether the tool can perform fixes. 

296 """ 

297 plugin = _create_plugin_instance(module_path, class_name) 

298 assert_that(plugin.definition.file_patterns).is_not_empty() 

299 

300 

301@pytest.mark.parametrize( 

302 ( 

303 "tool_name", 

304 "module_path", 

305 "class_name", 

306 "expected_timeout", 

307 "expected_priority", 

308 "expected_can_fix", 

309 ), 

310 TOOL_SPECS, 

311 ids=[spec[0] for spec in TOOL_SPECS], 

312) 

313def test_tool_has_default_options( 

314 tool_name: str, 

315 module_path: str, 

316 class_name: str, 

317 expected_timeout: int, 

318 expected_priority: int, 

319 expected_can_fix: bool, 

320) -> None: 

321 """Tool has default options dictionary. 

322 

323 Args: 

324 tool_name: Name of the tool. 

325 module_path: Module path containing the tool plugin. 

326 class_name: Class name of the tool plugin. 

327 expected_timeout: Expected timeout value for the tool. 

328 expected_priority: Expected priority value for the tool. 

329 expected_can_fix: Whether the tool can perform fixes. 

330 """ 

331 plugin = _create_plugin_instance(module_path, class_name) 

332 assert_that(plugin.definition.default_options).is_not_none() 

333 assert_that(plugin.definition.default_options).contains_key("timeout")