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.utils.CommonUtil;
37  import nl.jqno.equalsverifier.EqualsVerifier;
38  import nl.jqno.equalsverifier.EqualsVerifierReport;
39  import nl.jqno.equalsverifier.Warning;
40  
41  public class SuppressionXpathFilterTest extends AbstractModuleTestSupport {
42  
43      private static final String PATTERN = "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$";
44  
45      private static final String[] ALL_MESSAGES = {
46          "20:29: " + getCheckMessage(ConstantNameCheck.class,
47                                      MSG_INVALID_PATTERN, "bad_name", PATTERN),
48      };
49  
50      @Override
51      public String getPackageLocation() {
52          return "com/puppycrawl/tools/checkstyle/filters/suppressionxpathfilter";
53      }
54  
55      @Test
56      public void testAcceptOne() throws Exception {
57          final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
58          verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterAcceptOne.java"),
59                                             ALL_MESSAGES,
60                                             removeSuppressed(ALL_MESSAGES, suppressed));
61      }
62  
63      @Test
64      public void testAcceptTwo() throws Exception {
65          final String[] expected = {
66              "20:29: " + getCheckMessage(ConstantNameCheck.class, MSG_INVALID_PATTERN,
67                                          "different_name_than_suppression", PATTERN),
68          };
69          final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
70          verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterAcceptTwo.java"),
71                                             expected, removeSuppressed(expected, suppressed));
72      }
73  
74      @Test
75      public void testAcceptOnNullFile() throws Exception {
76          final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
77          verifyFilterWithInlineConfigParser(
78              getPath("InputSuppressionXpathFilterAcceptOnNullFile.java"), ALL_MESSAGES,
79              removeSuppressed(ALL_MESSAGES, suppressed));
80      }
81  
82      @Test
83      public void testNonExistentSuppressionFileWithFalseOptional() throws Exception {
84          final String fileName = getPath("non_existent_suppression_file.xml");
85          final boolean optional = false;
86          final CheckstyleException exc = getExpectedThrowable(
87                  CheckstyleException.class,
88                  () -> {
89                      createSuppressionXpathFilter(fileName, optional);
90                  });
91          assertWithMessage("Invalid error message")
92              .that(exc.getMessage())
93              .isEqualTo("Unable to find: " + fileName);
94      }
95  
96      @Test
97      public void testExistingInvalidSuppressionFileWithTrueOptional() throws Exception {
98          final String fileName = getPath("InputSuppressionXpathFilterInvalidFile.xml");
99          final boolean optional = true;
100         final CheckstyleException exc = getExpectedThrowable(
101                 CheckstyleException.class,
102                 () -> {
103                     createSuppressionXpathFilter(fileName, optional);
104                 });
105         assertWithMessage("Invalid error message")
106             .that(exc.getMessage())
107             .isEqualTo("Unable to parse " + fileName
108                 + " - invalid files or checks or message format for suppress-xpath");
109     }
110 
111     @Test
112     public void testExistingSuppressionFileWithTrueOptional() throws Exception {
113         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
114         verifyFilterWithInlineConfigParser(
115             getPath("InputSuppressionXpathFilterAcceptWithOptionalTrue.java"), ALL_MESSAGES,
116             removeSuppressed(ALL_MESSAGES, suppressed));
117     }
118 
119     @Test
120     public void testNonExistentSuppressionFileWithTrueOptional() throws Exception {
121         final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
122         verifyFilterWithInlineConfigParser(
123             getPath("InputSuppressionXpathFilterNonExistentFileWithTrueOptional.java"),
124             ALL_MESSAGES, removeSuppressed(ALL_MESSAGES, suppressed));
125     }
126 
127     @Test
128     public void testReject() throws Exception {
129         final String[] suppressed = {
130             "20:29: " + getCheckMessage(ConstantNameCheck.class,
131                                         MSG_INVALID_PATTERN, "bad_name", PATTERN),
132         };
133         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterReject.java"),
134                                            ALL_MESSAGES,
135                                            removeSuppressed(ALL_MESSAGES, suppressed));
136     }
137 
138     @Test
139     public void testEqualsAndHashCode() {
140         final EqualsVerifierReport ev = EqualsVerifier.forClass(SuppressionXpathFilter.class)
141                 .usingGetClass()
142                 .withIgnoredFields("file", "optional", "configuration")
143                 .suppress(Warning.NONFINAL_FIELDS).report();
144         assertWithMessage("Error: %s", ev.getMessage())
145                 .that(ev.isSuccessful())
146                 .isTrue();
147     }
148 
149     @Test
150     public void testExternalResource() throws Exception {
151         final boolean optional = false;
152         final String fileName = getPath("InputSuppressionXpathFilterIdAndQuery.xml");
153         final SuppressionXpathFilter filter = createSuppressionXpathFilter(fileName, optional);
154         final Set<String> expected = Collections.singleton(fileName);
155         final Set<String> actual = filter.getExternalResourceLocations();
156         assertWithMessage("Invalid external resource")
157             .that(actual)
158             .isEqualTo(expected);
159     }
160 
161     private static SuppressionXpathFilter createSuppressionXpathFilter(String fileName,
162                                                                        boolean optional)
163             throws CheckstyleException {
164         final SuppressionXpathFilter suppressionXpathFilter = new SuppressionXpathFilter();
165         suppressionXpathFilter.setFile(fileName);
166         suppressionXpathFilter.setOptional(optional);
167         suppressionXpathFilter.finishLocalSetup();
168         return suppressionXpathFilter;
169     }
170 
171     @Test
172     public void testFalseEncodeString() throws Exception {
173         final String pattern = "[^a-zA-z0-9]*";
174         final String[] expected = {
175             "17:24: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
176             "19:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
177             "21:28: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
178             "23:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
179             "25:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
180             "27:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
181             "29:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
182             "31:29: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
183             "33:29: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
184         };
185 
186         final String[] suppressed = {
187             "17:24: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
188             "19:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
189             "21:28: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
190             "23:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
191             "25:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
192             "27:26: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
193             "29:23: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
194         };
195 
196         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterEscapeString.java"),
197                                            expected, removeSuppressed(expected, suppressed));
198     }
199 
200     @Test
201     public void testFalseEncodeChar() throws Exception {
202         final String pattern = "[^a-zA-z0-9]*";
203         final String[] expected = {
204             "17:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
205             "19:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
206             "21:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
207             "23:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
208             "25:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
209         };
210 
211         final String[] suppressed = {
212             "21:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
213             "23:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
214             "25:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
215         };
216 
217         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilterEscapeChar.java"),
218                                            expected, removeSuppressed(expected, suppressed));
219     }
220 
221     @Test
222     public void testXpathSuppression() throws Exception {
223         for (int test = 1; test <= 4; test++) {
224 
225             final String[] expected = {
226                 "20:29: " + getCheckMessage(ConstantNameCheck.class, MSG_INVALID_PATTERN,
227                         "different_name_than_suppression", PATTERN),
228             };
229             final String[] suppressed = CommonUtil.EMPTY_STRING_ARRAY;
230             final String path = "InputSuppressionXpathFilter" + test + ".java";
231             verifyFilterWithInlineConfigParser(getPath(path),
232                     expected, removeSuppressed(expected, suppressed));
233         }
234     }
235 
236     @Test
237     public void testXpathSuppression2() throws Exception {
238         final String pattern = "[^a-zA-z0-9]*";
239         final String[] expected = {
240             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
241         };
242 
243         final String[] suppressed = {
244             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
245         };
246 
247         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilter5.java"),
248                                            expected, removeSuppressed(expected, suppressed));
249     }
250 
251     @Test
252     public void testXpathSuppression3() throws Exception {
253         final String pattern = "[^a-zA-z0-9]*";
254         final String[] expected = {
255             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
256         };
257 
258         final String[] suppressed = {
259             "18:14: " + getCheckMessage(IllegalTokenTextCheck.class, MSG_KEY, pattern),
260         };
261 
262         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilter6.java"),
263                                            expected, removeSuppressed(expected, suppressed));
264     }
265 
266     @Test
267     public void testXpathSuppression4() throws Exception {
268         final String[] suppressed = {
269             "20:29: " + getCheckMessage(ConstantNameCheck.class,
270                                         MSG_INVALID_PATTERN, "bad_name", PATTERN),
271         };
272         verifyFilterWithInlineConfigParser(getPath("InputSuppressionXpathFilter7.java"),
273                                            ALL_MESSAGES,
274                                            removeSuppressed(ALL_MESSAGES, suppressed));
275     }
276 }