Coverage for tests / unit / tools / svelte_check / test_execution.py: 100%

71 statements  

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

1"""Unit tests for svelte-check plugin check method execution.""" 

2 

3from __future__ import annotations 

4 

5from pathlib import Path 

6from typing import Any 

7from unittest.mock import patch 

8 

9import pytest 

10from assertpy import assert_that 

11 

12from lintro.parsers.svelte_check.svelte_check_issue import SvelteCheckIssue 

13from lintro.tools.definitions.svelte_check import SvelteCheckPlugin 

14 

15 

16def _mock_subprocess_success(**kwargs: Any) -> tuple[bool, str]: 

17 """Mock subprocess that returns success with no output. 

18 

19 Args: 

20 **kwargs: Ignored keyword arguments. 

21 

22 Returns: 

23 Tuple of (success=True, empty string). 

24 """ 

25 return (True, "") 

26 

27 

28def _mock_subprocess_with_issues(**kwargs: Any) -> tuple[bool, str]: 

29 """Mock subprocess that returns output with type errors. 

30 

31 Args: 

32 **kwargs: Ignored keyword arguments. 

33 

34 Returns: 

35 Tuple of (success=False, error output). 

36 """ 

37 output = ( 

38 "src/lib/Button.svelte:15:5:15:10 Error " 

39 "Type 'string' is not assignable to type 'number'.\n" 

40 "src/routes/+page.svelte:20:3:20:15 Error " 

41 "Property 'foo' does not exist on type 'Props'." 

42 ) 

43 return (False, output) 

44 

45 

46def test_check_no_svelte_files( 

47 svelte_check_plugin: SvelteCheckPlugin, 

48 tmp_path: Path, 

49) -> None: 

50 """Check returns early when no Svelte files found. 

51 

52 Args: 

53 svelte_check_plugin: The SvelteCheckPlugin instance to test. 

54 tmp_path: Temporary directory path for test files. 

55 """ 

56 # Create a non-Svelte file 

57 test_file = tmp_path / "test.ts" 

58 test_file.write_text("const x = 1;") 

59 

60 result = svelte_check_plugin.check([str(test_file)], {}) 

61 

62 assert_that(result.success).is_true() 

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

64 assert_that(result.output).contains("No .svelte files found to check.") 

65 

66 

67def test_check_no_svelte_config_proceeds_with_defaults( 

68 svelte_check_plugin: SvelteCheckPlugin, 

69 tmp_path: Path, 

70) -> None: 

71 """Check proceeds with defaults when no Svelte config found. 

72 

73 Args: 

74 svelte_check_plugin: The SvelteCheckPlugin instance to test. 

75 tmp_path: Temporary directory path for test files. 

76 """ 

77 # Create a Svelte file but no config 

78 svelte_file = tmp_path / "test.svelte" 

79 svelte_file.write_text("<script>\nlet count = 0;\n</script>\n<h1>{count}</h1>") 

80 

81 with patch.object( 

82 svelte_check_plugin, 

83 "_run_subprocess", 

84 side_effect=_mock_subprocess_success, 

85 ): 

86 result = svelte_check_plugin.check([str(tmp_path)], {}) 

87 

88 assert_that(result.success).is_true() 

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

90 

91 

92def test_check_with_mocked_subprocess_success( 

93 svelte_check_plugin: SvelteCheckPlugin, 

94 tmp_path: Path, 

95) -> None: 

96 """Check returns success when svelte-check finds no issues. 

97 

98 Args: 

99 svelte_check_plugin: The SvelteCheckPlugin instance to test. 

100 tmp_path: Temporary directory path for test files. 

101 """ 

102 # Create Svelte file and config 

103 svelte_file = tmp_path / "test.svelte" 

104 svelte_file.write_text("<script>\nlet count = 0;\n</script>\n<h1>{count}</h1>") 

105 config_file = tmp_path / "svelte.config.js" 

106 config_file.write_text("export default {};") 

107 

108 with patch.object( 

109 svelte_check_plugin, 

110 "_run_subprocess", 

111 side_effect=_mock_subprocess_success, 

112 ): 

113 result = svelte_check_plugin.check([str(tmp_path)], {}) 

114 

115 assert_that(result.success).is_true() 

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

117 

118 

119def test_check_with_mocked_subprocess_issues_found( 

120 svelte_check_plugin: SvelteCheckPlugin, 

121 tmp_path: Path, 

122) -> None: 

123 """Check returns issues when svelte-check finds type errors. 

124 

125 Args: 

126 svelte_check_plugin: The SvelteCheckPlugin instance to test. 

127 tmp_path: Temporary directory path for test files. 

128 """ 

129 # Create Svelte file and config 

130 svelte_file = tmp_path / "index.svelte" 

131 svelte_file.write_text( 

132 "<script lang='ts'>\nlet x: number = 'bad';\n</script>\n<h1>{x}</h1>", 

133 ) 

134 config_file = tmp_path / "svelte.config.js" 

135 config_file.write_text("export default {};") 

136 

137 with patch.object( 

138 svelte_check_plugin, 

139 "_run_subprocess", 

140 side_effect=_mock_subprocess_with_issues, 

141 ): 

142 result = svelte_check_plugin.check([str(tmp_path)], {}) 

143 

144 assert_that(result.success).is_false() 

145 assert_that(result.issues_count).is_equal_to(2) 

146 issues = result.issues 

147 assert_that(issues).is_not_none() 

148 assert issues is not None 

149 assert_that(issues).is_length(2) 

150 

151 # Verify first issue 

152 first_issue = issues[0] 

153 assert isinstance(first_issue, SvelteCheckIssue) 

154 assert_that(first_issue.file).is_equal_to("src/lib/Button.svelte") 

155 assert_that(first_issue.line).is_equal_to(15) 

156 assert_that(first_issue.severity).is_equal_to("error") 

157 

158 

159def test_fix_raises_not_implemented( 

160 svelte_check_plugin: SvelteCheckPlugin, 

161 tmp_path: Path, 

162) -> None: 

163 """Fix method raises NotImplementedError. 

164 

165 Args: 

166 svelte_check_plugin: The SvelteCheckPlugin instance to test. 

167 tmp_path: Temporary directory path for test files. 

168 """ 

169 with pytest.raises(NotImplementedError, match="cannot automatically fix"): 

170 svelte_check_plugin.fix([str(tmp_path)], {}) 

171 

172 

173def test_check_with_threshold_option( 

174 svelte_check_plugin: SvelteCheckPlugin, 

175 tmp_path: Path, 

176) -> None: 

177 """Check uses threshold option when provided. 

178 

179 Args: 

180 svelte_check_plugin: The SvelteCheckPlugin instance to test. 

181 tmp_path: Temporary directory path for test files. 

182 """ 

183 # Create Svelte file and config 

184 svelte_file = tmp_path / "test.svelte" 

185 svelte_file.write_text("<script>\nlet count = 0;\n</script>\n<h1>{count}</h1>") 

186 config_file = tmp_path / "svelte.config.js" 

187 config_file.write_text("export default {};") 

188 

189 captured_cmd: list[str] = [] 

190 

191 def capture_cmd(cmd: list[str], **kwargs: Any) -> tuple[bool, str]: 

192 captured_cmd.extend(cmd) 

193 return (True, "") 

194 

195 with patch.object( 

196 svelte_check_plugin, 

197 "_run_subprocess", 

198 side_effect=capture_cmd, 

199 ): 

200 svelte_check_plugin.check( 

201 [str(tmp_path)], 

202 {"threshold": "warning"}, 

203 ) 

204 

205 # Verify --threshold was passed with the correct value 

206 assert_that(captured_cmd).contains("--threshold") 

207 threshold_idx = captured_cmd.index("--threshold") 

208 assert_that(captured_cmd[threshold_idx + 1]).is_equal_to("warning")