Coverage for tests / unit / tools / oxlint / test_check_method.py: 100%

77 statements  

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

1"""Tests for OxlintPlugin.check method.""" 

2 

3from __future__ import annotations 

4 

5import pathlib 

6import subprocess 

7from pathlib import Path 

8from typing import TYPE_CHECKING, cast 

9from unittest.mock import MagicMock, patch 

10 

11from assertpy import assert_that 

12 

13from lintro.parsers.oxlint.oxlint_issue import OxlintIssue 

14 

15if TYPE_CHECKING: 

16 from lintro.tools.definitions.oxlint import OxlintPlugin 

17 

18 

19def test_check_with_issues(oxlint_plugin: OxlintPlugin, tmp_path: Path) -> None: 

20 """Check returns issues when found. 

21 

22 Args: 

23 oxlint_plugin: The OxlintPlugin instance to test. 

24 tmp_path: Temporary directory path for test files. 

25 """ 

26 test_file = pathlib.Path(tmp_path) / "test.js" 

27 test_file.write_text("var unused = 1;\n") 

28 

29 mock_output = """{ 

30 "diagnostics": [ 

31 { 

32 "message": "Variable 'unused' is declared but never used.", 

33 "code": "eslint(no-unused-vars)", 

34 "severity": "warning", 

35 "filename": "test.js", 

36 "labels": [{"span": {"line": 1, "column": 5}}] 

37 } 

38 ] 

39 }""" 

40 mock_result = (False, mock_output) 

41 

42 with ( 

43 patch.object(oxlint_plugin, "_prepare_execution") as mock_prepare, 

44 patch.object(oxlint_plugin, "_run_subprocess", return_value=mock_result), 

45 patch.object(oxlint_plugin, "_get_executable_command", return_value=["oxlint"]), 

46 patch.object(oxlint_plugin, "_build_config_args", return_value=[]), 

47 ): 

48 mock_ctx = MagicMock() 

49 mock_ctx.should_skip = False 

50 mock_ctx.early_result = None 

51 mock_ctx.timeout = 30 

52 mock_ctx.cwd = str(tmp_path) 

53 mock_ctx.rel_files = ["test.js"] 

54 mock_ctx.files = [str(test_file)] 

55 mock_prepare.return_value = mock_ctx 

56 

57 result = oxlint_plugin.check([str(test_file)], {}) 

58 

59 assert_that(result.name).is_equal_to("oxlint") 

60 assert_that(result.success).is_false() 

61 assert_that(result.issues_count).is_equal_to(1) 

62 assert_that(result.issues).is_not_none() 

63 issue = cast(OxlintIssue, result.issues[0]) # type: ignore[index] # validated via is_not_none 

64 assert_that(issue.code).is_equal_to("eslint(no-unused-vars)") 

65 

66 

67def test_check_without_issues(oxlint_plugin: OxlintPlugin, tmp_path: Path) -> None: 

68 """Check returns success when no issues found. 

69 

70 Args: 

71 oxlint_plugin: The OxlintPlugin instance to test. 

72 tmp_path: Temporary directory path for test files. 

73 """ 

74 test_file = pathlib.Path(tmp_path) / "test.js" 

75 test_file.write_text("const x = 1;\nconsole.log(x);\n") 

76 

77 mock_output = '{"diagnostics": []}' 

78 mock_result = (True, mock_output) 

79 

80 with ( 

81 patch.object(oxlint_plugin, "_prepare_execution") as mock_prepare, 

82 patch.object(oxlint_plugin, "_run_subprocess", return_value=mock_result), 

83 patch.object(oxlint_plugin, "_get_executable_command", return_value=["oxlint"]), 

84 patch.object(oxlint_plugin, "_build_config_args", return_value=[]), 

85 ): 

86 mock_ctx = MagicMock() 

87 mock_ctx.should_skip = False 

88 mock_ctx.early_result = None 

89 mock_ctx.timeout = 30 

90 mock_ctx.cwd = str(tmp_path) 

91 mock_ctx.rel_files = ["test.js"] 

92 mock_ctx.files = [str(test_file)] 

93 mock_prepare.return_value = mock_ctx 

94 

95 result = oxlint_plugin.check([str(test_file)], {}) 

96 

97 assert_that(result.name).is_equal_to("oxlint") 

98 assert_that(result.success).is_true() 

99 assert_that(result.issues_count).is_equal_to(0) 

100 assert_that(result.output).is_none() 

101 

102 

103def test_check_timeout_handling(oxlint_plugin: OxlintPlugin, tmp_path: Path) -> None: 

104 """Check handles timeout correctly. 

105 

106 Args: 

107 oxlint_plugin: The OxlintPlugin instance to test. 

108 tmp_path: Temporary directory path for test files. 

109 """ 

110 test_file = pathlib.Path(tmp_path) / "test.js" 

111 test_file.write_text("const x = 1;\n") 

112 

113 with ( 

114 patch.object(oxlint_plugin, "_prepare_execution") as mock_prepare, 

115 patch.object( 

116 oxlint_plugin, 

117 "_run_subprocess", 

118 side_effect=subprocess.TimeoutExpired(cmd=["oxlint"], timeout=30), 

119 ), 

120 patch.object(oxlint_plugin, "_get_executable_command", return_value=["oxlint"]), 

121 patch.object(oxlint_plugin, "_build_config_args", return_value=[]), 

122 ): 

123 mock_ctx = MagicMock() 

124 mock_ctx.should_skip = False 

125 mock_ctx.early_result = None 

126 mock_ctx.timeout = 30 

127 mock_ctx.cwd = str(tmp_path) 

128 mock_ctx.rel_files = ["test.js"] 

129 mock_ctx.files = [str(test_file)] 

130 mock_prepare.return_value = mock_ctx 

131 

132 result = oxlint_plugin.check([str(test_file)], {}) 

133 

134 assert_that(result.success).is_false() 

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

136 assert_that(result.output).contains("30s") 

137 assert_that(result.issues_count).is_equal_to(1) 

138 issue = cast(OxlintIssue, result.issues[0]) # type: ignore[index] # validated via is_not_none 

139 assert_that(issue.code).is_equal_to("TIMEOUT") 

140 

141 

142def test_check_early_skip(oxlint_plugin: OxlintPlugin, tmp_path: Path) -> None: 

143 """Check returns early when should_skip is True. 

144 

145 Args: 

146 oxlint_plugin: The OxlintPlugin instance to test. 

147 tmp_path: Temporary directory path for test files. 

148 """ 

149 from lintro.models.core.tool_result import ToolResult 

150 

151 early_result = ToolResult( 

152 name="oxlint", 

153 success=True, 

154 output=None, 

155 issues_count=0, 

156 issues=[], 

157 ) 

158 

159 with patch.object(oxlint_plugin, "_prepare_execution") as mock_prepare: 

160 mock_ctx = MagicMock() 

161 mock_ctx.should_skip = True 

162 mock_ctx.early_result = early_result 

163 mock_prepare.return_value = mock_ctx 

164 

165 result = oxlint_plugin.check([str(tmp_path)], {}) 

166 

167 assert_that(result).is_same_as(early_result)