Coverage for tests / unit / tools / shellcheck / test_options.py: 100%

77 statements  

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

1"""Unit tests for shellcheck plugin options and command building.""" 

2 

3from __future__ import annotations 

4 

5import pytest 

6from assertpy import assert_that 

7 

8from lintro.tools.definitions.shellcheck import ( 

9 SHELLCHECK_DEFAULT_FORMAT, 

10 SHELLCHECK_DEFAULT_SEVERITY, 

11 SHELLCHECK_DEFAULT_TIMEOUT, 

12 SHELLCHECK_SEVERITY_LEVELS, 

13 SHELLCHECK_SHELL_DIALECTS, 

14 ShellcheckPlugin, 

15) 

16 

17# Tests for default option values 

18 

19 

20@pytest.mark.parametrize( 

21 ("option_name", "expected_value"), 

22 [ 

23 ("timeout", SHELLCHECK_DEFAULT_TIMEOUT), 

24 ("severity", SHELLCHECK_DEFAULT_SEVERITY), 

25 ("exclude", None), 

26 ("shell", None), 

27 ], 

28 ids=[ 

29 "timeout_equals_default", 

30 "severity_equals_default", 

31 "exclude_is_none", 

32 "shell_is_none", 

33 ], 

34) 

35def test_default_options_values( 

36 shellcheck_plugin: ShellcheckPlugin, 

37 option_name: str, 

38 expected_value: object, 

39) -> None: 

40 """Default options have correct values. 

41 

42 Args: 

43 shellcheck_plugin: The ShellcheckPlugin instance to test. 

44 option_name: The name of the option to check. 

45 expected_value: The expected value for the option. 

46 """ 

47 assert_that( 

48 shellcheck_plugin.definition.default_options[option_name], 

49 ).is_equal_to(expected_value) 

50 

51 

52# Tests for ShellcheckPlugin.set_options method - valid options 

53 

54 

55@pytest.mark.parametrize( 

56 ("option_name", "option_value"), 

57 [ 

58 ("severity", "error"), 

59 ("severity", "warning"), 

60 ("severity", "info"), 

61 ("severity", "style"), 

62 ("exclude", ["SC2086", "SC2046"]), 

63 ("shell", "bash"), 

64 ("shell", "sh"), 

65 ("shell", "dash"), 

66 ("shell", "ksh"), 

67 ], 

68 ids=[ 

69 "severity_error", 

70 "severity_warning", 

71 "severity_info", 

72 "severity_style", 

73 "exclude_list", 

74 "shell_bash", 

75 "shell_sh", 

76 "shell_dash", 

77 "shell_ksh", 

78 ], 

79) 

80def test_set_options_valid( 

81 shellcheck_plugin: ShellcheckPlugin, 

82 option_name: str, 

83 option_value: object, 

84) -> None: 

85 """Set valid options correctly. 

86 

87 Args: 

88 shellcheck_plugin: The ShellcheckPlugin instance to test. 

89 option_name: The name of the option to set. 

90 option_value: The value to set for the option. 

91 """ 

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

93 assert_that(shellcheck_plugin.options.get(option_name)).is_equal_to(option_value) 

94 

95 

96def test_set_options_severity_case_insensitive( 

97 shellcheck_plugin: ShellcheckPlugin, 

98) -> None: 

99 """Set severity option is case insensitive. 

100 

101 Args: 

102 shellcheck_plugin: The ShellcheckPlugin instance to test. 

103 """ 

104 shellcheck_plugin.set_options(severity="WARNING") 

105 assert_that(shellcheck_plugin.options.get("severity")).is_equal_to("warning") 

106 

107 

108def test_set_options_shell_case_insensitive( 

109 shellcheck_plugin: ShellcheckPlugin, 

110) -> None: 

111 """Set shell option is case insensitive. 

112 

113 Args: 

114 shellcheck_plugin: The ShellcheckPlugin instance to test. 

115 """ 

116 shellcheck_plugin.set_options(shell="BASH") # nosec B604 

117 assert_that(shellcheck_plugin.options.get("shell")).is_equal_to("bash") 

118 

119 

120# Tests for ShellcheckPlugin.set_options method - invalid types 

121 

122 

123@pytest.mark.parametrize( 

124 ("option_name", "invalid_value", "error_match"), 

125 [ 

126 ("severity", "critical", "Invalid severity level"), 

127 ("severity", "warn", "Invalid severity level"), 

128 ("shell", "fish", "Invalid shell dialect"), 

129 ("shell", "powershell", "Invalid shell dialect"), 

130 ("exclude", "SC2086", "exclude must be a list"), 

131 ("exclude", 123, "exclude must be a list"), 

132 ], 

133 ids=[ 

134 "invalid_severity_critical", 

135 "invalid_severity_warn", 

136 "invalid_shell_fish", 

137 "invalid_shell_powershell", 

138 "invalid_exclude_string", 

139 "invalid_exclude_integer", 

140 ], 

141) 

142def test_set_options_invalid_type( 

143 shellcheck_plugin: ShellcheckPlugin, 

144 option_name: str, 

145 invalid_value: object, 

146 error_match: str, 

147) -> None: 

148 """Raise ValueError for invalid option types. 

149 

150 Args: 

151 shellcheck_plugin: The ShellcheckPlugin instance to test. 

152 option_name: The name of the option being tested. 

153 invalid_value: An invalid value for the option. 

154 error_match: Pattern expected in the error message. 

155 """ 

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

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

158 

159 

160# Tests for ShellcheckPlugin._build_command method 

161 

162 

163def test_build_command_basic(shellcheck_plugin: ShellcheckPlugin) -> None: 

164 """Build basic command without extra options. 

165 

166 Args: 

167 shellcheck_plugin: The ShellcheckPlugin instance to test. 

168 """ 

169 cmd = shellcheck_plugin._build_command() 

170 assert_that(cmd).contains("shellcheck") 

171 # Default format and severity should be included 

172 assert_that(cmd).contains("--format") 

173 assert_that(cmd).contains(SHELLCHECK_DEFAULT_FORMAT) 

174 assert_that(cmd).contains("--severity") 

175 assert_that(cmd).contains(SHELLCHECK_DEFAULT_SEVERITY) 

176 

177 

178def test_build_command_with_severity(shellcheck_plugin: ShellcheckPlugin) -> None: 

179 """Build command with severity option. 

180 

181 Args: 

182 shellcheck_plugin: The ShellcheckPlugin instance to test. 

183 """ 

184 shellcheck_plugin.set_options(severity="error") 

185 cmd = shellcheck_plugin._build_command() 

186 

187 assert_that(cmd).contains("--severity") 

188 severity_idx = cmd.index("--severity") 

189 assert_that(cmd[severity_idx + 1]).is_equal_to("error") 

190 

191 

192def test_build_command_with_exclude_codes(shellcheck_plugin: ShellcheckPlugin) -> None: 

193 """Build command with exclude option. 

194 

195 Args: 

196 shellcheck_plugin: The ShellcheckPlugin instance to test. 

197 """ 

198 shellcheck_plugin.set_options(exclude=["SC2086", "SC2046"]) 

199 cmd = shellcheck_plugin._build_command() 

200 

201 assert_that(cmd).contains("--exclude") 

202 # Each exclude code should be passed separately 

203 exclude_indices = [i for i, x in enumerate(cmd) if x == "--exclude"] 

204 assert_that(exclude_indices).is_length(2) 

205 assert_that(cmd[exclude_indices[0] + 1]).is_equal_to("SC2086") 

206 assert_that(cmd[exclude_indices[1] + 1]).is_equal_to("SC2046") 

207 

208 

209def test_build_command_with_shell_dialect(shellcheck_plugin: ShellcheckPlugin) -> None: 

210 """Build command with shell dialect option. 

211 

212 Args: 

213 shellcheck_plugin: The ShellcheckPlugin instance to test. 

214 """ 

215 shellcheck_plugin.set_options(shell="bash") # nosec B604 

216 cmd = shellcheck_plugin._build_command() 

217 

218 assert_that(cmd).contains("--shell") 

219 shell_idx = cmd.index("--shell") 

220 assert_that(cmd[shell_idx + 1]).is_equal_to("bash") 

221 

222 

223def test_build_command_with_all_options(shellcheck_plugin: ShellcheckPlugin) -> None: 

224 """Build command with all options set. 

225 

226 Args: 

227 shellcheck_plugin: The ShellcheckPlugin instance to test. 

228 """ 

229 shellcheck_plugin.set_options( 

230 severity="warning", 

231 exclude=["SC2086"], 

232 shell="ksh", # nosec B604 

233 ) 

234 cmd = shellcheck_plugin._build_command() 

235 

236 assert_that(cmd).contains("--format") 

237 assert_that(cmd).contains("--severity") 

238 assert_that(cmd).contains("--exclude") 

239 assert_that(cmd).contains("--shell") 

240 

241 # Verify correct values 

242 severity_idx = cmd.index("--severity") 

243 assert_that(cmd[severity_idx + 1]).is_equal_to("warning") 

244 

245 shell_idx = cmd.index("--shell") 

246 assert_that(cmd[shell_idx + 1]).is_equal_to("ksh") 

247 

248 

249# Tests for constants 

250 

251 

252def test_severity_levels_constant() -> None: 

253 """Verify SHELLCHECK_SEVERITY_LEVELS contains expected values.""" 

254 assert_that(SHELLCHECK_SEVERITY_LEVELS).contains("error") 

255 assert_that(SHELLCHECK_SEVERITY_LEVELS).contains("warning") 

256 assert_that(SHELLCHECK_SEVERITY_LEVELS).contains("info") 

257 assert_that(SHELLCHECK_SEVERITY_LEVELS).contains("style") 

258 assert_that(SHELLCHECK_SEVERITY_LEVELS).is_length(4) 

259 

260 

261def test_shell_dialects_constant() -> None: 

262 """Verify SHELLCHECK_SHELL_DIALECTS contains expected values.""" 

263 assert_that(SHELLCHECK_SHELL_DIALECTS).contains("bash") 

264 assert_that(SHELLCHECK_SHELL_DIALECTS).contains("sh") 

265 assert_that(SHELLCHECK_SHELL_DIALECTS).contains("dash") 

266 assert_that(SHELLCHECK_SHELL_DIALECTS).contains("ksh") 

267 assert_that(SHELLCHECK_SHELL_DIALECTS).is_length(4) 

268 

269 

270def test_default_timeout_constant() -> None: 

271 """Verify SHELLCHECK_DEFAULT_TIMEOUT is 30.""" 

272 assert_that(SHELLCHECK_DEFAULT_TIMEOUT).is_equal_to(30) 

273 

274 

275def test_default_format_constant() -> None: 

276 """Verify SHELLCHECK_DEFAULT_FORMAT is json1.""" 

277 assert_that(SHELLCHECK_DEFAULT_FORMAT).is_equal_to("json1") 

278 

279 

280def test_default_severity_constant() -> None: 

281 """Verify SHELLCHECK_DEFAULT_SEVERITY is style.""" 

282 assert_that(SHELLCHECK_DEFAULT_SEVERITY).is_equal_to("style")