View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2026 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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.coding.IllegalTokenTextCheck.MSG_KEY;
24  import static com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck.MSG_INVALID_PATTERN;
25  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
26  
27  import java.util.Collections;
28  import java.util.Set;
29  
30  import org.junit.jupiter.api.Test;
31  
32  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
33  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
34  import com.puppycrawl.tools.checkstyle.checks.coding.IllegalTokenTextCheck;
35  import com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck;
36  import com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheck;
37  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
38  import nl.jqno.equalsverifier.EqualsVerifier;
39  import nl.jqno.equalsverifier.EqualsVerifierReport;
40  import nl.jqno.equalsverifier.Warning;
41  
42  public class SuppressionXpathFilterTest extends AbstractModuleTestSupport {
43  
44      private static final String PATTERN = "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$";
45  
46      private static final String[] ALL_MESSAGES = {
47          "20:29: " + getCheckMessage(ConstantNameCheck.class,
48                                      MSG_INVALID_PATTERN, "bad_name", PATTERN),
49      };
50  
51      @Override
52      public String getPackageLocation() {
53          return "com/puppycrawl/tools/checkstyle/filters/suppressionxpathfilter";
54      }
55  
56      @Test
57      public void testAcceptOne() throws Exception {
58          final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
59          verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterAcceptOne.java"),
60                                             ALL_MESSAGES,
61                                             removeSuppressed(ALL_MESSAGES, suppressed));
62      }
63  
64      @Test
65      public void testAcceptTwo() throws Exception {
66          final String[] expected = {
67              "20:29: " + getCheckMessage(ConstantNameCheck.class, MSG_INVALID_PATTERN,
68                                          "different_name_than_suppression", PATTERN),
69          };
70          final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
71          verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterAcceptTwo.java"),
72                                             expected, removeSuppressed(expected, suppressed));
73      }
74  
75      @Test
76      public void testAcceptOnNullFile() throws Exception {
77          final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
78          verifyFilterWithInlineConfigParser(
79              getPath("InputSuppressionXpathFilterAcceptOnNullFile.java"), ALL_MESSAGES,
80              removeSuppressed(ALL_MESSAGES, suppressed));
81      }
82  
83      @Test
84      public void testNonExistentSuppressionFileWithFalseOptional() throws Exception {
85          final String fileName = getPath("non_existent_suppression_file.xml");
86          final boolean optional = false;
87          final CheckstyleException exc = getExpectedThrowable(
88                  CheckstyleException.class,
89                  () -> {
90                      createSuppressionXpathFilter(fileName, optional);
91                  });
92          assertWithMessage("Invalid error message")
93              .that(exc.getMessage())
94              .isEqualTo("Unable to find: " + fileName);
95      }
96  
97      @Test
98      public void testExistingInvalidSuppressionFileWithTrueOptional() throws Exception {
99          final String fileName = getPath("InputSuppressionXpathFilterInvalidFile.xml");
100         final boolean optional = true;
101         final CheckstyleException exc = getExpectedThrowable(
102                 CheckstyleException.class,
103                 () -> {
104                     createSuppressionXpathFilter(fileName, optional);
105                 });
106         assertWithMessage("Invalid error message")
107             .that(exc.getMessage())
108             .isEqualTo("Unable to parse " + fileName
109                 + " - invalid files or checks or message format for suppress-xpath");
110     }
111 
112     @Test
113     public void testExistingSuppressionFileWithTrueOptional() throws Exception {
114         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
115         verifyFilterWithInlineConfigParser(
116             getPath("InputSuppressionXpathFilterAcceptWithOptionalTrue.java"), ALL_MESSAGES,
117             removeSuppressed(ALL_MESSAGES, suppressed));
118     }
119 
120     @Test
121     public void testNonExistentSuppressionFileWithTrueOptional() throws Exception {
122         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
123         verifyFilterWithInlineConfigParser(
124             getPath("InputSuppressionXpathFilterNonExistentFileWithTrueOptional.java"),
125             ALL_MESSAGES, removeSuppressed(ALL_MESSAGES, suppressed));
126     }
127 
128     @Test
129     public void testReject() throws Exception {
130         final String[] suppressed = {
131             "20:29: " + getCheckMessage(ConstantNameCheck.class,
132                                         MSG_INVALID_PATTERN, "bad_name", PATTERN),
133         };
134         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterReject.java"),
135                                            ALL_MESSAGES,
136                                            removeSuppressed(ALL_MESSAGES, suppressed));
137     }
138 
139     @Test
140     public void testEqualsAndHashCode() {
141         final EqualsVerifierReport ev = EqualsVerifier.forClass(SuppressionXpathFilter.class)
142                 .usingGetClass()
143                 .withIgnoredFields("file", "optional", "configuration")
144                 .suppress(Warning.NONFINAL_FIELDS).report();
145         assertWithMessage("Error: %s", ev.getMessage())
146                 .that(ev.isSuccessful())
147                 .isTrue();
148     }
149 
150     @Test
151     public void testExternalResource() throws Exception {
152         final boolean optional = false;
153         final String fileName = getPath("InputSuppressionXpathFilterIdAndQuery.xml");
154         final SuppressionXpathFilter filter = createSuppressionXpathFilter(fileName, optional);
155         final Set<String> expected = Collections.singleton(fileName);
156         final Set<String> actual = filter.getExternalResourceLocations();
157         assertWithMessage("Invalid external resource")
158             .that(actual)
159             .isEqualTo(expected);
160     }
161 
162     private static SuppressionXpathFilter createSuppressionXpathFilter(String fileName,
163                                                                        boolean optional)
164             throws CheckstyleException {
165         final SuppressionXpathFilter suppressionXpathFilter = new SuppressionXpathFilter();
166         suppressionXpathFilter.setFile(fileName);
167         suppressionXpathFilter.setOptional(optional);
168         suppressionXpathFilter.finishLocalSetup();
169         return suppressionXpathFilter;
170     }
171 
172     @Test
173     public void testFalseEncodeString() throws Exception {
174         final String pattern = "[^a-zA-z0-9]*";
175         final String[] expected = {
176             "17:24: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
177             "19:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
178             "21:28: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
179             "23:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
180             "25:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
181             "27:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
182             "29:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
183             "31:29: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
184             "33:29: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
185         };
186 
187         final String[] suppressed = {
188             "17:24: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
189             "19:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
190             "21:28: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
191             "23:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
192             "25:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
193             "27:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
194             "29:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
195         };
196 
197         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterEscapeString.java"),
198                                            expected, removeSuppressed(expected, suppressed));
199     }
200 
201     @Test
202     public void testFalseEncodeChar() throws Exception {
203         final String pattern = "[^a-zA-z0-9]*";
204         final String[] expected = {
205             "17:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
206             "19:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
207             "21:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
208             "23:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
209             "25:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
210         };
211 
212         final String[] suppressed = {
213             "21:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
214             "23:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
215             "25:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
216         };
217 
218         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterEscapeChar.java"),
219                                            expected, removeSuppressed(expected, suppressed));
220     }
221 
222     @Test
223     public void testXpathSuppression() throws Exception {
224         for (int test = 1; test <= 4; test++) {
225 
226             final String[] expected = {
227                 "20:29: " + getCheckMessage(ConstantNameCheck.class, MSG_INVALID_PATTERN,
228                         "different_name_than_suppression", PATTERN),
229             };
230             final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
231             final String path = "InputSuppressionXpathFilter" + test + ".java";
232             verifyFilterWithInlineConfigParser(getPath(path),
233                     expected, removeSuppressed(expected, suppressed));
234         }
235     }
236 
237     @Test
238     public void testXpathSuppression2() throws Exception {
239         final String pattern = "[^a-zA-z0-9]*";
240         final String[] expected = {
241             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
242         };
243 
244         final String[] suppressed = {
245             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
246         };
247 
248         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilter5.java"),
249                                            expected, removeSuppressed(expected, suppressed));
250     }
251 
252     @Test
253     public void testXpathSuppression3() throws Exception {
254         final String pattern = "[^a-zA-z0-9]*";
255         final String[] expected = {
256             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
257         };
258 
259         final String[] suppressed = {
260             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
261         };
262 
263         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilter6.java"),
264                                            expected, removeSuppressed(expected, suppressed));
265     }
266 
267     @Test
268     public void testXpathSuppression4() throws Exception {
269         final String[] suppressed = {
270             "20:29: " + getCheckMessage(ConstantNameCheck.class,
271                                         MSG_INVALID_PATTERN, "bad_name", PATTERN),
272         };
273         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilter7.java"),
274                                            ALL_MESSAGES,
275                                            removeSuppressed(ALL_MESSAGES, suppressed));
276     }
277 
278     @Test
279     public void testNonMatchingFileRegexpByXpath() throws Exception {
280         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
281         verifyFilterWithInlineConfigParser(
282             getPath("InputSuppressionXpathFilterNonMatchingFile.java"),
283             ALL_MESSAGES,
284             removeSuppressed(ALL_MESSAGES, suppressed));
285     }
286 
287     @Test
288     public void testDecideByMessageByXpath() throws Exception {
289         final String[] expected = {
290             "20:7: " + getCheckMessage(TypeNameCheck.class, MSG_INVALID_PATTERN,
291                 "inputSuppressionXpathFilterDecideByMessage", "^[A-Z][a-zA-Z0-9]*$"),
292         };
293         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
294         verifyFilterWithInlineConfigParser(
295             getPath("InputSuppressionXpathFilterDecideByMessage.java"),
296             expected,
297             removeSuppressed(expected, suppressed));
298     }
299 
300 }