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 org.junit.jupiter.api.Assumptions.assumeTrue;
24
25 import java.io.IOException;
26 import java.net.HttpURLConnection;
27 import java.net.URI;
28 import java.net.URL;
29 import java.util.HashSet;
30 import java.util.Set;
31
32 import org.junit.jupiter.api.Test;
33 import org.xml.sax.InputSource;
34
35 import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport;
36 import com.puppycrawl.tools.checkstyle.TreeWalkerFilter;
37 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
38 import com.puppycrawl.tools.checkstyle.api.FilterSet;
39 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
40
41
42
43
44 public class SuppressionsLoaderTest extends AbstractPathTestSupport {
45
46 @Override
47 public String getPackageLocation() {
48 return "com/puppycrawl/tools/checkstyle/filters/suppressionsloader";
49 }
50
51 @Test
52 public void testNoSuppressions() throws Exception {
53 final FilterSet fc =
54 SuppressionsLoader.loadSuppressions(getPath("InputSuppressionsLoaderNone.xml"));
55 final FilterSet fc2 = new FilterSet();
56 assertWithMessage("No suppressions should be loaded, but found: %s", fc.getFilters().size())
57 .that(fc.getFilters())
58 .isEqualTo(fc2.getFilters());
59 }
60
61 @Test
62 public void testLoadFromUrl() throws Exception {
63 final String[] urlCandidates = {
64 "https://raw.githubusercontent.com/checkstyle/checkstyle/master/src/site/resources/"
65 + "files/suppressions_none.xml",
66 "https://checkstyle.org/files/suppressions_none.xml",
67 };
68 FilterSet actualFilterSet = null;
69
70 for (String url : urlCandidates) {
71 actualFilterSet = loadFilterSet(url);
72
73 if (actualFilterSet != null) {
74 break;
75 }
76 }
77
78 assumeTrue(actualFilterSet != null, "No Internet connection.");
79 final FilterSet expectedFilterSet = new FilterSet();
80 assertWithMessage("Failed to load from url")
81 .that(actualFilterSet.getFilters())
82 .isEqualTo(expectedFilterSet.getFilters());
83 }
84
85 @Test
86 public void testLoadFromMalformedUrl() {
87 try {
88 SuppressionsLoader.loadSuppressions("http");
89 assertWithMessage("exception expected").fail();
90 }
91 catch (CheckstyleException exc) {
92 assertWithMessage("Invalid error message")
93 .that(exc.getMessage())
94 .isEqualTo("Unable to find: http");
95 }
96 }
97
98 @Test
99 public void testLoadFromNonExistentUrl() {
100 try {
101 SuppressionsLoader.loadSuppressions("/non/existent/file.xml");
102 assertWithMessage("exception expected").fail();
103 }
104 catch (CheckstyleException exc) {
105 assertWithMessage("Invalid error message")
106 .that(exc.getMessage())
107 .isEqualTo("Unable to find: /non/existent/file.xml");
108 }
109 }
110
111 @Test
112 public void testMultipleSuppression() throws Exception {
113 final FilterSet fc =
114 SuppressionsLoader.loadSuppressions(getPath("InputSuppressionsLoaderMultiple.xml"));
115 final FilterSet fc2 = new FilterSet();
116
117 final SuppressFilterElement se0 =
118 new SuppressFilterElement("file0", "check0", null, null, null, null);
119 fc2.addFilter(se0);
120 final SuppressFilterElement se1 =
121 new SuppressFilterElement("file1", "check1", null, null, "1,2-3", null);
122 fc2.addFilter(se1);
123 final SuppressFilterElement se2 =
124 new SuppressFilterElement("file2", "check2", null, null, null, "1,2-3");
125 fc2.addFilter(se2);
126 final SuppressFilterElement se3 =
127 new SuppressFilterElement("file3", "check3", null, null, "1,2-3", "1,2-3");
128 fc2.addFilter(se3);
129 final SuppressFilterElement se4 =
130 new SuppressFilterElement(null, null, "message0", null, null, null);
131 fc2.addFilter(se4);
132 assertWithMessage("Multiple suppressions were loaded incorrectly")
133 .that(fc.getFilters())
134 .isEqualTo(fc2.getFilters());
135 }
136
137 @Test
138 public void testNoFile() throws IOException {
139 final String fn = getPath("InputSuppressionsLoaderNoFile.xml");
140 try {
141 SuppressionsLoader.loadSuppressions(fn);
142 assertWithMessage("Exception is expected").fail();
143 }
144 catch (CheckstyleException exc) {
145 final String messageStart = "Unable to parse " + fn;
146 assertWithMessage("Exception message should start with: %s", messageStart)
147 .that(exc.getMessage())
148 .startsWith("Unable to parse " + fn);
149 assertWithMessage("Exception message should contain \"files\"")
150 .that(exc.getMessage())
151 .contains("\"files\"");
152 assertWithMessage("Exception message should contain \"suppress\"")
153 .that(exc.getMessage())
154 .contains("\"suppress\"");
155 }
156 }
157
158 @Test
159 public void testNoCheck() throws IOException {
160 final String fn = getPath("InputSuppressionsLoaderNoCheck.xml");
161 try {
162 SuppressionsLoader.loadSuppressions(fn);
163 assertWithMessage("Exception is expected").fail();
164 }
165 catch (CheckstyleException exc) {
166 final String messageStart = "Unable to parse " + fn;
167 assertWithMessage("Exception message should start with: %s", messageStart)
168 .that(exc.getMessage())
169 .startsWith(messageStart);
170 assertWithMessage("Exception message should contain \"checks\"")
171 .that(exc.getMessage())
172 .contains("\"checks\"");
173 assertWithMessage("Exception message should contain \"suppress\"")
174 .that(exc.getMessage())
175 .contains("\"suppress\"");
176 }
177 }
178
179 @Test
180 public void testBadInt() throws IOException {
181 final String fn = getPath("InputSuppressionsLoaderBadInt.xml");
182 try {
183 SuppressionsLoader.loadSuppressions(fn);
184 assertWithMessage("Exception is expected").fail();
185 }
186 catch (CheckstyleException exc) {
187 assertWithMessage(exc.getMessage())
188 .that(exc.getMessage())
189 .startsWith("Number format exception " + fn + " - For input string: \"a\"");
190 }
191 }
192
193 private static FilterSet loadFilterSet(String url) throws Exception {
194 FilterSet filterSet = null;
195
196 if (isUrlReachable(url)) {
197 int attemptCount = 0;
198 final int attemptLimit = 5;
199
200 while (attemptCount <= attemptLimit) {
201 try {
202 filterSet = SuppressionsLoader.loadSuppressions(url);
203 break;
204 }
205 catch (CheckstyleException exc) {
206 if (attemptCount < attemptLimit && exc.getMessage()
207 .contains("Unable to read")) {
208 attemptCount++;
209
210 Thread.sleep(1000);
211 }
212 else {
213 throw exc;
214 }
215 }
216 }
217 }
218 return filterSet;
219 }
220
221 private static boolean isUrlReachable(String url) {
222 boolean result = true;
223 try {
224 final URL verifiableUrl = URI.create(url).toURL();
225 final HttpURLConnection urlConnect = (HttpURLConnection) verifiableUrl.openConnection();
226 urlConnect.getContent();
227 }
228
229 catch (IOException ignored) {
230 result = false;
231 }
232 return result;
233 }
234
235 @Test
236 public void testUnableToFindSuppressions() {
237 final String sourceName = "InputSuppressionsLoaderNone.xml";
238
239 try {
240 TestUtil.invokeVoidStaticMethod(SuppressionsLoader.class, "loadSuppressions",
241 new InputSource(sourceName), sourceName);
242 assertWithMessage("InvocationTargetException is expected").fail();
243 }
244 catch (ReflectiveOperationException exc) {
245 assertWithMessage("Invalid exception cause message")
246 .that(exc)
247 .hasCauseThat()
248 .hasMessageThat()
249 .isEqualTo("Unable to find: " + sourceName);
250 }
251 }
252
253 @Test
254 public void testUnableToReadSuppressions() {
255 final String sourceName = "InputSuppressionsLoaderNone.xml";
256
257 try {
258 TestUtil.invokeVoidStaticMethod(SuppressionsLoader.class, "loadSuppressions",
259 new InputSource(), sourceName);
260 assertWithMessage("InvocationTargetException is expected").fail();
261 }
262 catch (ReflectiveOperationException exc) {
263 assertWithMessage("Invalid exception cause message")
264 .that(exc)
265 .hasCauseThat()
266 .hasMessageThat()
267 .isEqualTo("Unable to read " + sourceName);
268 }
269 }
270
271 @Test
272 public void testNoCheckNoId() throws IOException {
273 final String fn = getPath("InputSuppressionsLoaderNoCheckAndId.xml");
274 try {
275 SuppressionsLoader.loadSuppressions(fn);
276 assertWithMessage("Exception is expected").fail();
277 }
278 catch (CheckstyleException exc) {
279 assertWithMessage("Invalid error message")
280 .that(exc.getMessage())
281 .isEqualTo("Unable to parse " + fn
282 + " - missing checks or id or message attribute");
283 }
284 }
285
286 @Test
287 public void testNoCheckYesId() throws Exception {
288 final String fn = getPath("InputSuppressionsLoaderId.xml");
289 final FilterSet set = SuppressionsLoader.loadSuppressions(fn);
290
291 assertWithMessage("Invalid number of filters")
292 .that(set.getFilters())
293 .hasSize(1);
294 }
295
296 @Test
297 public void testInvalidFileFormat() throws IOException {
298 final String fn = getPath("InputSuppressionsLoaderInvalidFile.xml");
299 try {
300 SuppressionsLoader.loadSuppressions(fn);
301 assertWithMessage("Exception is expected").fail();
302 }
303 catch (CheckstyleException exc) {
304 assertWithMessage("Invalid error message")
305 .that(exc.getMessage())
306 .isEqualTo("Unable to parse " + fn
307 + " - invalid files or checks or message format");
308 }
309 }
310
311 @Test
312 public void testLoadFromClasspath() throws Exception {
313 final FilterSet fc =
314 SuppressionsLoader.loadSuppressions(getPath("InputSuppressionsLoaderNone.xml"));
315 final FilterSet fc2 = new FilterSet();
316 assertWithMessage("Suppressions were not loaded")
317 .that(fc.getFilters())
318 .isEqualTo(fc2.getFilters());
319 }
320
321 @Test
322 public void testSettingModuleId() throws Exception {
323 final FilterSet fc =
324 SuppressionsLoader.loadSuppressions(getPath("InputSuppressionsLoaderWithId.xml"));
325 final SuppressFilterElement suppressElement = (SuppressFilterElement) fc.getFilters()
326 .toArray()[0];
327
328 final String id = TestUtil.getInternalState(suppressElement, "moduleId", String.class);
329 assertWithMessage("Id has to be defined")
330 .that(id)
331 .isEqualTo("someId");
332 }
333
334 @Test
335 public void testXpathSuppressions() throws Exception {
336 final String fn = getPath("InputSuppressionsLoaderXpathCorrect.xml");
337 final Set<TreeWalkerFilter> filterSet = SuppressionsLoader.loadXpathSuppressions(fn);
338
339 final Set<TreeWalkerFilter> expectedFilterSet = new HashSet<>();
340 final XpathFilterElement xf0 =
341 new XpathFilterElement("file1", "test", null, "id1", "//CLASS_DEF");
342 expectedFilterSet.add(xf0);
343 final XpathFilterElement xf1 =
344 new XpathFilterElement(null, null, "message1", null, "//CLASS_DEF");
345 expectedFilterSet.add(xf1);
346 assertWithMessage("Multiple xpath suppressions were loaded incorrectly")
347 .that(filterSet)
348 .isEqualTo(expectedFilterSet);
349 }
350
351 @Test
352 public void testXpathInvalidFileFormat() throws IOException {
353 final String fn = getPath("InputSuppressionsLoaderXpathInvalidFile.xml");
354 try {
355 SuppressionsLoader.loadXpathSuppressions(fn);
356 assertWithMessage("Exception should be thrown").fail();
357 }
358 catch (CheckstyleException exc) {
359 assertWithMessage("Invalid error message")
360 .that(exc.getMessage())
361 .isEqualTo("Unable to parse " + fn
362 + " - invalid files or checks or message format for suppress-xpath");
363 }
364 }
365
366 @Test
367 public void testXpathNoCheckNoId() throws IOException {
368 final String fn =
369 getPath("InputSuppressionsLoaderXpathNoCheckAndId.xml");
370 try {
371 SuppressionsLoader.loadXpathSuppressions(fn);
372 assertWithMessage("Exception should be thrown").fail();
373 }
374 catch (CheckstyleException exc) {
375 assertWithMessage("Invalid error message")
376 .that(exc.getMessage())
377 .isEqualTo("Unable to parse " + fn
378 + " - missing checks or id or message attribute for suppress-xpath");
379 }
380 }
381
382 @Test
383 public void testXpathNoCheckYesId() throws Exception {
384 final String fn = getPath("InputSuppressionsLoaderXpathId.xml");
385 final Set<TreeWalkerFilter> filterSet = SuppressionsLoader.loadXpathSuppressions(fn);
386
387 assertWithMessage("Invalid number of filters")
388 .that(filterSet)
389 .hasSize(1);
390 }
391
392 }