1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.filters;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck.MSG_INVALID_PATTERN;
24 import static org.junit.jupiter.api.Assumptions.assumeTrue;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.net.HttpURLConnection;
30 import java.net.URL;
31 import java.util.UUID;
32
33 import org.junit.jupiter.api.Test;
34 import org.junit.jupiter.api.io.TempDir;
35
36 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
37 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
38 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
39 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
40 import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
41 import com.puppycrawl.tools.checkstyle.api.Violation;
42 import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck;
43 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
44
45 public class SuppressionFilterTest extends AbstractModuleTestSupport {
46
47 @TempDir
48 public File temporaryFolder;
49
50 @Override
51 protected String getPackageLocation() {
52 return "com/puppycrawl/tools/checkstyle/filters/suppressionfilter";
53 }
54
55 @Test
56 public void testAccept() throws Exception {
57 final String fileName = getPath("InputSuppressionFilterNone.xml");
58 final boolean optional = false;
59 final SuppressionFilter filter = createSuppressionFilter(fileName, optional);
60
61 final AuditEvent ev = new AuditEvent(this, "ATest.java", null);
62
63 assertWithMessage("Audit event should be excepted when there are no suppressions")
64 .that(filter.accept(ev))
65 .isTrue();
66 }
67
68 @Test
69 public void testAcceptFalse() throws Exception {
70 final String fileName = getPath("InputSuppressionFilterSuppress.xml");
71 final boolean optional = false;
72 final SuppressionFilter filter = createSuppressionFilter(fileName, optional);
73
74 final Violation message = new Violation(1, 1, null, "msg", null,
75 SeverityLevel.ERROR, null, getClass(), null);
76 final AuditEvent ev = new AuditEvent(this, "ATest.java", message);
77
78 assertWithMessage("Audit event should be rejected when there is a matching suppression")
79 .that(filter.accept(ev))
80 .isFalse();
81 }
82
83 @Test
84 public void testAcceptOnNullFile() throws CheckstyleException {
85 final String fileName = null;
86 final boolean optional = false;
87 final SuppressionFilter filter = createSuppressionFilter(fileName, optional);
88
89 final AuditEvent ev = new AuditEvent(this, "AnyJava.java", null);
90 assertWithMessage("Audit event on null file should be excepted, but was not")
91 .that(filter.accept(ev))
92 .isTrue();
93 }
94
95 @Test
96 public void testNonExistentSuppressionFileWithFalseOptional() {
97 final String fileName = "non_existent_suppression_file.xml";
98 try {
99 final boolean optional = false;
100 createSuppressionFilter(fileName, optional);
101 assertWithMessage("Exception is expected").fail();
102 }
103 catch (CheckstyleException ex) {
104 assertWithMessage("Invalid error message")
105 .that(ex.getMessage())
106 .isEqualTo("Unable to find: " + fileName);
107 }
108 }
109
110 @Test
111 public void testExistingInvalidSuppressionFileWithTrueOptional() throws IOException {
112 final String fileName = getPath("InputSuppressionFilterInvalidFile.xml");
113 try {
114 final boolean optional = true;
115 createSuppressionFilter(fileName, optional);
116 assertWithMessage("Exception is expected").fail();
117 }
118 catch (CheckstyleException ex) {
119 assertWithMessage("Invalid error message")
120 .that(ex.getMessage())
121 .isEqualTo("Unable to parse " + fileName
122 + " - invalid files or checks or message format");
123 }
124 }
125
126 @Test
127 public void testExistingSuppressionFileWithTrueOptional() throws Exception {
128 final String fileName = getPath("InputSuppressionFilterNone.xml");
129 final boolean optional = true;
130 final SuppressionFilter filter = createSuppressionFilter(fileName, optional);
131
132 final AuditEvent ev = new AuditEvent(this, "AnyFile.java", null);
133
134 assertWithMessage("Suppression file with true optional was not accepted")
135 .that(filter.accept(ev))
136 .isTrue();
137 }
138
139 @Test
140 public void testNonExistentSuppressionFileWithTrueOptional() throws Exception {
141 final String fileName = "non_existent_suppression_file.xml";
142 final boolean optional = true;
143 final SuppressionFilter filter = createSuppressionFilter(fileName, optional);
144
145 final AuditEvent ev = new AuditEvent(this, "AnyFile.java", null);
146
147 assertWithMessage("Should except event when suppression file does not exist")
148 .that(filter.accept(ev))
149 .isTrue();
150 }
151
152 @Test
153 public void testNonExistentSuppressionUrlWithTrueOptional() throws Exception {
154 final String fileName =
155 "https://checkstyle.org/non_existent_suppression.xml";
156 final boolean optional = true;
157 final SuppressionFilter filter = createSuppressionFilter(fileName, optional);
158
159 final AuditEvent ev = new AuditEvent(this, "AnyFile.java", null);
160
161 assertWithMessage("Should except event when suppression file url does not exist")
162 .that(filter.accept(ev))
163 .isTrue();
164 }
165
166 @Test
167 public void testUseCacheLocalFileExternalResourceContentDoesNotChange() throws Exception {
168 final DefaultConfiguration filterConfig = createModuleConfig(SuppressionFilter.class);
169 filterConfig.addProperty("file", getPath("InputSuppressionFilterNone.xml"));
170
171 final DefaultConfiguration checkerConfig = createRootConfig(filterConfig);
172 final String uniqueFileName = "junit_" + UUID.randomUUID() + ".java";
173 final File cacheFile = new File(temporaryFolder, uniqueFileName);
174 checkerConfig.addProperty("cacheFile", cacheFile.getPath());
175
176 final File filePath = new File(temporaryFolder, uniqueFileName);
177
178 execute(checkerConfig, filePath.toString());
179
180 execute(checkerConfig, filePath.toString());
181 }
182
183 @Test
184 public void testUseCacheRemoteFileExternalResourceContentDoesNotChange() throws Exception {
185 final String[] urlCandidates = {
186 "https://checkstyle.org/files/suppressions_none.xml",
187 "https://raw.githubusercontent.com/checkstyle/checkstyle/master/src/site/resources/"
188 + "files/suppressions_none.xml",
189 };
190
191 String urlForTest = null;
192 for (String url : urlCandidates) {
193 if (isConnectionAvailableAndStable(url)) {
194 urlForTest = url;
195 break;
196 }
197 }
198
199 assumeTrue(urlForTest != null, "No Internet connection.");
200 final DefaultConfiguration firstFilterConfig = createModuleConfig(SuppressionFilter.class);
201
202 firstFilterConfig.addProperty("file", urlForTest);
203
204 final DefaultConfiguration firstCheckerConfig = createRootConfig(firstFilterConfig);
205 final String uniqueFileName1 = "junit_" + UUID.randomUUID() + ".java";
206 final File cacheFile = new File(temporaryFolder, uniqueFileName1);
207 firstCheckerConfig.addProperty("cacheFile", cacheFile.getPath());
208
209 final String uniqueFileName2 = "file_" + UUID.randomUUID() + ".java";
210 final File pathToEmptyFile = new File(temporaryFolder, uniqueFileName2);
211
212 execute(firstCheckerConfig, pathToEmptyFile.toString());
213
214
215 final DefaultConfiguration secondFilterConfig =
216 createModuleConfig(SuppressionFilter.class);
217
218 secondFilterConfig.addProperty("file", urlForTest);
219
220 final DefaultConfiguration secondCheckerConfig = createRootConfig(secondFilterConfig);
221 secondCheckerConfig.addProperty("cacheFile", cacheFile.getPath());
222
223 execute(secondCheckerConfig, pathToEmptyFile.toString());
224 }
225
226 private static boolean isConnectionAvailableAndStable(String url) throws Exception {
227 boolean available = false;
228
229 if (isUrlReachable(url)) {
230 final int attemptLimit = 5;
231 int attemptCount = 0;
232
233 while (attemptCount <= attemptLimit) {
234 try (InputStream stream = new URL(url).openStream()) {
235
236 available = stream.read() != -1;
237 break;
238 }
239 catch (IOException ex) {
240
241 if (attemptCount < attemptLimit && ex.getMessage().contains("Unable to read")) {
242 attemptCount++;
243 available = false;
244
245 Thread.sleep(1000);
246 }
247 else {
248 throw ex;
249 }
250 }
251 }
252 }
253 return available;
254 }
255
256 private static boolean isUrlReachable(String url) {
257 boolean result = true;
258 try {
259 final URL verifiableUrl = new URL(url);
260 final HttpURLConnection urlConnect = (HttpURLConnection) verifiableUrl.openConnection();
261 urlConnect.getContent();
262 }
263 catch (IOException ignored) {
264 result = false;
265 }
266 return result;
267 }
268
269 private static SuppressionFilter createSuppressionFilter(String fileName, boolean optional)
270 throws CheckstyleException {
271 final SuppressionFilter suppressionFilter = new SuppressionFilter();
272 suppressionFilter.setFile(fileName);
273 suppressionFilter.setOptional(optional);
274 suppressionFilter.finishLocalSetup();
275 return suppressionFilter;
276 }
277
278 @Test
279 public void testXpathSuppression() throws Exception {
280 for (int test = 1; test <= 6; test++) {
281 final String pattern = "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$";
282 final String[] expected = {
283 "19:29: " + getCheckMessage(ConstantNameCheck.class, MSG_INVALID_PATTERN,
284 "different_name_than_suppression", pattern),
285 };
286 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
287 final String path = "InputSuppressionFilter" + test + ".java";
288 verifyFilterWithInlineConfigParser(getPath(path),
289 expected, suppressed);
290 }
291 }
292
293 @Test
294 public void testSuppression2() throws Exception {
295 final String pattern = "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$";
296 final String[] expected = {
297 "19:29: " + getCheckMessage(ConstantNameCheck.class,
298 MSG_INVALID_PATTERN, "bad_name", pattern),
299 };
300 final String[] suppressed = {
301 "19:29: " + getCheckMessage(ConstantNameCheck.class,
302 MSG_INVALID_PATTERN, "bad_name", pattern),
303
304 };
305 verifyFilterWithInlineConfigParser(getPath("InputSuppressionFilter7.java"),
306 expected, removeSuppressed(expected, suppressed));
307 }
308
309 @Test
310 public void testSuppression3() throws Exception {
311 final String pattern = "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$";
312 final String[] expected = {
313 "19:29: " + getCheckMessage(ConstantNameCheck.class,
314 MSG_INVALID_PATTERN, "bad_name", pattern),
315 };
316 final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
317 verifyFilterWithInlineConfigParser(getPath("InputSuppressionFilter8.java"),
318 expected, removeSuppressed(expected, suppressed));
319 }
320 }