Coverage for tests / unit / tools / oxfmt / test_fix_method.py: 100%

72 statements  

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

1"""Tests for OxfmtPlugin.fix method.""" 

2 

3from __future__ import annotations 

4 

5import subprocess 

6from typing import TYPE_CHECKING, Any 

7from unittest.mock import MagicMock, patch 

8 

9from assertpy import assert_that 

10 

11from lintro.models.core.tool_result import ToolResult 

12from lintro.parsers.oxfmt.oxfmt_issue import OxfmtIssue 

13 

14if TYPE_CHECKING: 

15 from lintro.tools.definitions.oxfmt import OxfmtPlugin 

16 

17 

18def test_fix_success_no_issues( 

19 oxfmt_plugin: OxfmtPlugin, 

20 mock_execution_context_for_tool: Any, 

21) -> None: 

22 """Fix returns success when no issues to fix. 

23 

24 Args: 

25 oxfmt_plugin: The OxfmtPlugin instance to test. 

26 mock_execution_context_for_tool: Mock execution context factory. 

27 """ 

28 with ( 

29 patch.object(oxfmt_plugin, "_prepare_execution") as mock_prepare, 

30 patch.object(oxfmt_plugin, "_run_subprocess") as mock_run, 

31 patch.object(oxfmt_plugin, "_get_executable_command") as mock_exec, 

32 patch.object(oxfmt_plugin, "_build_config_args") as mock_config, 

33 ): 

34 mock_prepare.return_value = mock_execution_context_for_tool( 

35 files=["test.js"], 

36 rel_files=["test.js"], 

37 cwd="/tmp", 

38 ) 

39 

40 mock_exec.return_value = ["oxfmt"] 

41 mock_config.return_value = [] 

42 # Initial check - no issues, fix - success, final check - no issues 

43 mock_run.side_effect = [ 

44 (True, ""), 

45 (True, ""), 

46 (True, ""), 

47 ] 

48 

49 result = oxfmt_plugin.fix(["/tmp/test.js"], {}) 

50 

51 assert_that(result.success).is_true() 

52 assert_that(result.remaining_issues_count).is_equal_to(0) 

53 

54 

55def test_fix_success_with_fixes_applied( 

56 oxfmt_plugin: OxfmtPlugin, 

57 mock_execution_context_for_tool: Any, 

58) -> None: 

59 """Fix returns success when fixes are applied. 

60 

61 Args: 

62 oxfmt_plugin: The OxfmtPlugin instance to test. 

63 mock_execution_context_for_tool: Mock execution context factory. 

64 """ 

65 with ( 

66 patch.object(oxfmt_plugin, "_prepare_execution") as mock_prepare, 

67 patch.object(oxfmt_plugin, "_run_subprocess") as mock_run, 

68 patch.object(oxfmt_plugin, "_get_executable_command") as mock_exec, 

69 patch.object(oxfmt_plugin, "_build_config_args") as mock_config, 

70 ): 

71 mock_prepare.return_value = mock_execution_context_for_tool( 

72 files=["test.js"], 

73 rel_files=["test.js"], 

74 cwd="/tmp", 

75 ) 

76 

77 mock_exec.return_value = ["oxfmt"] 

78 mock_config.return_value = [] 

79 mock_run.side_effect = [ 

80 (False, "test.js"), # Initial check - issue found 

81 (True, ""), # Fix command 

82 (True, ""), # Final check - no issues 

83 ] 

84 

85 result = oxfmt_plugin.fix(["/tmp/test.js"], {}) 

86 

87 assert_that(result.success).is_true() 

88 assert_that(result.fixed_issues_count).is_equal_to(1) 

89 assert_that(result.remaining_issues_count).is_equal_to(0) 

90 

91 

92def test_fix_timeout_during_initial_check( 

93 oxfmt_plugin: OxfmtPlugin, 

94 mock_execution_context_for_tool: Any, 

95) -> None: 

96 """Fix handles timeout during initial check. 

97 

98 Args: 

99 oxfmt_plugin: The OxfmtPlugin instance to test. 

100 mock_execution_context_for_tool: Mock execution context factory. 

101 """ 

102 timeout_result = ToolResult( 

103 name="oxfmt", 

104 success=False, 

105 output="Oxfmt execution timed out (30s limit exceeded).", 

106 issues_count=1, 

107 issues=[ 

108 OxfmtIssue( 

109 file="execution", 

110 line=1, 

111 column=1, 

112 code="TIMEOUT", 

113 message="Oxfmt execution timed out", 

114 ), 

115 ], 

116 initial_issues_count=1, 

117 fixed_issues_count=0, 

118 remaining_issues_count=1, 

119 ) 

120 

121 with ( 

122 patch.object(oxfmt_plugin, "_prepare_execution") as mock_prepare, 

123 patch.object(oxfmt_plugin, "_run_subprocess") as mock_run, 

124 patch.object(oxfmt_plugin, "_get_executable_command") as mock_exec, 

125 patch.object(oxfmt_plugin, "_build_config_args") as mock_config, 

126 patch.object( 

127 oxfmt_plugin, 

128 "_create_timeout_result", 

129 return_value=timeout_result, 

130 ), 

131 ): 

132 mock_prepare.return_value = mock_execution_context_for_tool( 

133 files=["test.js"], 

134 rel_files=["test.js"], 

135 cwd="/tmp", 

136 ) 

137 

138 mock_exec.return_value = ["oxfmt"] 

139 mock_config.return_value = [] 

140 mock_run.side_effect = subprocess.TimeoutExpired(cmd="oxfmt", timeout=30) 

141 

142 result = oxfmt_plugin.fix(["/tmp/test.js"], {}) 

143 

144 assert_that(result.success).is_false() 

145 assert_that(result.output).contains("timed out") 

146 

147 

148def test_fix_timeout_during_fix_command( 

149 oxfmt_plugin: OxfmtPlugin, 

150 mock_execution_context_for_tool: Any, 

151) -> None: 

152 """Fix handles timeout during fix command. 

153 

154 Args: 

155 oxfmt_plugin: The OxfmtPlugin instance to test. 

156 mock_execution_context_for_tool: Mock execution context factory. 

157 """ 

158 timeout_result = ToolResult( 

159 name="oxfmt", 

160 success=False, 

161 output="Oxfmt execution timed out (30s limit exceeded).", 

162 issues_count=2, 

163 issues=[ 

164 OxfmtIssue( 

165 file="test.js", 

166 line=1, 

167 column=1, 

168 code="FORMAT", 

169 message="File is not formatted", 

170 ), 

171 OxfmtIssue( 

172 file="execution", 

173 line=1, 

174 column=1, 

175 code="TIMEOUT", 

176 message="Oxfmt execution timed out", 

177 ), 

178 ], 

179 initial_issues_count=2, 

180 fixed_issues_count=0, 

181 remaining_issues_count=2, 

182 ) 

183 

184 with ( 

185 patch.object(oxfmt_plugin, "_prepare_execution") as mock_prepare, 

186 patch.object(oxfmt_plugin, "_run_subprocess") as mock_run, 

187 patch.object(oxfmt_plugin, "_get_executable_command") as mock_exec, 

188 patch.object(oxfmt_plugin, "_build_config_args") as mock_config, 

189 patch.object( 

190 oxfmt_plugin, 

191 "_create_timeout_result", 

192 return_value=timeout_result, 

193 ), 

194 ): 

195 mock_prepare.return_value = mock_execution_context_for_tool( 

196 files=["test.js"], 

197 rel_files=["test.js"], 

198 cwd="/tmp", 

199 ) 

200 

201 mock_exec.return_value = ["oxfmt"] 

202 mock_config.return_value = [] 

203 mock_run.side_effect = [ 

204 (False, "test.js"), # Initial check - issue found 

205 subprocess.TimeoutExpired(cmd="oxfmt", timeout=30), # Fix times out 

206 ] 

207 

208 result = oxfmt_plugin.fix(["/tmp/test.js"], {}) 

209 

210 assert_that(result.success).is_false() 

211 assert_that(result.output).contains("timed out") 

212 

213 

214def test_fix_early_return_when_should_skip( 

215 oxfmt_plugin: OxfmtPlugin, 

216 mock_execution_context_for_tool: Any, 

217) -> None: 

218 """Fix returns early result when should_skip is True. 

219 

220 Args: 

221 oxfmt_plugin: The OxfmtPlugin instance to test. 

222 mock_execution_context_for_tool: Mock execution context factory. 

223 """ 

224 with patch.object(oxfmt_plugin, "_prepare_execution") as mock_prepare: 

225 ctx = mock_execution_context_for_tool(should_skip=True) 

226 ctx.early_result = MagicMock(success=True, issues_count=0) 

227 mock_prepare.return_value = ctx 

228 

229 result = oxfmt_plugin.fix(["/tmp"], {}) 

230 

231 assert_that(result.success).is_true() 

232 

233 

234def test_fix_multiple_files_with_issues( 

235 oxfmt_plugin: OxfmtPlugin, 

236 mock_execution_context_for_tool: Any, 

237) -> None: 

238 """Fix handles multiple files with formatting issues. 

239 

240 Args: 

241 oxfmt_plugin: The OxfmtPlugin instance to test. 

242 mock_execution_context_for_tool: Mock execution context factory. 

243 """ 

244 with ( 

245 patch.object(oxfmt_plugin, "_prepare_execution") as mock_prepare, 

246 patch.object(oxfmt_plugin, "_run_subprocess") as mock_run, 

247 patch.object(oxfmt_plugin, "_get_executable_command") as mock_exec, 

248 patch.object(oxfmt_plugin, "_build_config_args") as mock_config, 

249 ): 

250 mock_prepare.return_value = mock_execution_context_for_tool( 

251 files=["test1.js", "test2.ts", "test3.tsx"], 

252 rel_files=["test1.js", "test2.ts", "test3.tsx"], 

253 cwd="/tmp", 

254 ) 

255 

256 mock_exec.return_value = ["oxfmt"] 

257 mock_config.return_value = [] 

258 mock_run.side_effect = [ 

259 (False, "test1.js\ntest2.ts\ntest3.tsx"), # Initial check - 3 issues 

260 (True, ""), # Fix command 

261 (True, ""), # Final check - no issues 

262 ] 

263 

264 result = oxfmt_plugin.fix(["/tmp"], {}) 

265 

266 assert_that(result.success).is_true() 

267 assert_that(result.initial_issues_count).is_equal_to(3) 

268 assert_that(result.fixed_issues_count).is_equal_to(3) 

269 assert_that(result.remaining_issues_count).is_equal_to(0) 

270 

271 

272def test_fix_output_includes_fix_count( 

273 oxfmt_plugin: OxfmtPlugin, 

274 mock_execution_context_for_tool: Any, 

275) -> None: 

276 """Fix output includes count of fixed issues. 

277 

278 Args: 

279 oxfmt_plugin: The OxfmtPlugin instance to test. 

280 mock_execution_context_for_tool: Mock execution context factory. 

281 """ 

282 with ( 

283 patch.object(oxfmt_plugin, "_prepare_execution") as mock_prepare, 

284 patch.object(oxfmt_plugin, "_run_subprocess") as mock_run, 

285 patch.object(oxfmt_plugin, "_get_executable_command") as mock_exec, 

286 patch.object(oxfmt_plugin, "_build_config_args") as mock_config, 

287 ): 

288 mock_prepare.return_value = mock_execution_context_for_tool( 

289 files=["test.js"], 

290 rel_files=["test.js"], 

291 cwd="/tmp", 

292 ) 

293 

294 mock_exec.return_value = ["oxfmt"] 

295 mock_config.return_value = [] 

296 mock_run.side_effect = [ 

297 (False, "test.js"), # Initial check - issue found 

298 (True, ""), # Fix command 

299 (True, ""), # Final check - no issues 

300 ] 

301 

302 result = oxfmt_plugin.fix(["/tmp/test.js"], {}) 

303 

304 assert_that(result.output).contains("Fixed 1 formatting issue")