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