View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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  
24  import java.io.File;
25  import java.nio.charset.StandardCharsets;
26  import java.util.regex.Pattern;
27  
28  import org.junit.jupiter.api.BeforeEach;
29  import org.junit.jupiter.api.Test;
30  
31  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
32  import com.puppycrawl.tools.checkstyle.JavaParser;
33  import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
34  import com.puppycrawl.tools.checkstyle.api.FileContents;
35  import com.puppycrawl.tools.checkstyle.api.FileText;
36  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
37  import com.puppycrawl.tools.checkstyle.api.Violation;
38  import net.sf.saxon.Configuration;
39  import net.sf.saxon.sxpath.XPathEvaluator;
40  import net.sf.saxon.sxpath.XPathExpression;
41  import nl.jqno.equalsverifier.EqualsVerifier;
42  import nl.jqno.equalsverifier.EqualsVerifierReport;
43  
44  public class XpathFilterElementTest extends AbstractModuleTestSupport {
45  
46      private File file;
47      private FileContents fileContents;
48  
49      @BeforeEach
50      public void setUp() throws Exception {
51          file = new File(getPath("InputXpathFilterElementSuppressByXpath.java"));
52          fileContents = new FileContents(new FileText(file,
53                  StandardCharsets.UTF_8.name()));
54      }
55  
56      @Override
57      protected String getPackageLocation() {
58          return "com/puppycrawl/tools/checkstyle/filters/xpathfilterelement";
59      }
60  
61      @Test
62      public void testMatching() throws Exception {
63          final String xpath = "//CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
64          final XpathFilterElement filter = new XpathFilterElement(
65                  "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
66          final TreeWalkerAuditEvent ev = getEvent(3, 0,
67                  TokenTypes.CLASS_DEF);
68          assertWithMessage("Event should be rejected")
69                  .that(filter.accept(ev))
70                  .isFalse();
71      }
72  
73      @Test
74      public void testNonMatchingTokenType() throws Exception {
75          final String xpath = "//METHOD_DEF[./IDENT[@text='countTokens']]";
76          final XpathFilterElement filter = new XpathFilterElement(
77                  "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
78          final TreeWalkerAuditEvent ev = getEvent(4, 4,
79                  TokenTypes.CLASS_DEF);
80          assertWithMessage("Event should be accepted")
81                  .that(filter.accept(ev))
82                  .isTrue();
83      }
84  
85      @Test
86      public void testNonMatchingLineNumber() throws Exception {
87          final String xpath = "//CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
88          final XpathFilterElement filter = new XpathFilterElement(
89                  "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
90          final TreeWalkerAuditEvent ev = getEvent(100, 0,
91                  TokenTypes.CLASS_DEF);
92          assertWithMessage("Event should be accepted")
93                  .that(filter.accept(ev))
94                  .isTrue();
95      }
96  
97      @Test
98      public void testNonMatchingColumnNumber() throws Exception {
99          final String xpath = "//CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
100         final XpathFilterElement filter = new XpathFilterElement(
101                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
102         final TreeWalkerAuditEvent ev = getEvent(3, 100,
103                 TokenTypes.CLASS_DEF);
104         assertWithMessage("Event should be accepted")
105                 .that(filter.accept(ev))
106                 .isTrue();
107     }
108 
109     @Test
110     public void testComplexQuery() throws Exception {
111         final String xpath = "//VARIABLE_DEF[./IDENT[@text='pi'] and "
112                 + "../../IDENT[@text='countTokens']] "
113                 + "| //VARIABLE_DEF[./IDENT[@text='someVariable'] and ../../IDENT[@text='sum']]";
114         final XpathFilterElement filter = new XpathFilterElement(
115                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
116         final TreeWalkerAuditEvent eventOne = getEvent(5, 8,
117                 TokenTypes.VARIABLE_DEF);
118         final TreeWalkerAuditEvent eventTwo = getEvent(10, 4,
119                 TokenTypes.VARIABLE_DEF);
120         final TreeWalkerAuditEvent eventThree = getEvent(15, 8,
121                 TokenTypes.VARIABLE_DEF);
122         assertWithMessage("Event should be rejected")
123                 .that(filter.accept(eventOne))
124                 .isFalse();
125         assertWithMessage("Event should be accepted")
126                 .that(filter.accept(eventTwo))
127                 .isTrue();
128         assertWithMessage("Event should be rejected")
129                 .that(filter.accept(eventThree))
130                 .isFalse();
131     }
132 
133     @Test
134     public void testInvalidCheckRegexp() {
135         try {
136             final Object test = new XpathFilterElement(
137                     ".*", "e[l", ".*", "moduleId", "query");
138             assertWithMessage("Exception is expected but got " + test).fail();
139         }
140         catch (IllegalArgumentException ex) {
141             assertWithMessage("Message should be: Failed to initialise regular expression")
142                     .that(ex.getMessage())
143                     .contains("Failed to initialise regular expression");
144         }
145     }
146 
147     @Test
148     public void testIncorrectQuery() {
149         final String xpath = "1@#";
150         try {
151             final Object test = new XpathFilterElement("InputXpathFilterElementSuppressByXpath",
152                     "Test", null, null, xpath);
153             assertWithMessage("Exception is expected but got " + test).fail();
154         }
155         catch (IllegalArgumentException ex) {
156             assertWithMessage("Message should be: Incorrect xpath query")
157                     .that(ex.getMessage())
158                     .contains("Incorrect xpath query");
159         }
160     }
161 
162     @Test
163     public void testNoQuery() throws Exception {
164         final TreeWalkerAuditEvent event = getEvent(15, 8,
165                 TokenTypes.VARIABLE_DEF);
166         final XpathFilterElement filter = new XpathFilterElement(
167                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, null);
168         assertWithMessage("Event should be accepted")
169                 .that(filter.accept(event))
170                 .isFalse();
171     }
172 
173     @Test
174     public void testNullFileName() {
175         final XpathFilterElement filter = new XpathFilterElement(
176                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, null);
177         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(null,
178                 null, null, null);
179         assertWithMessage("Event should be accepted")
180                 .that(filter.accept(ev))
181                 .isTrue();
182     }
183 
184     @Test
185     public void testNonMatchingFileRegexp() throws Exception {
186         final XpathFilterElement filter =
187                 new XpathFilterElement("NonMatchingRegexp", "Test", null, null, null);
188         final TreeWalkerAuditEvent ev = getEvent(3, 0,
189                 TokenTypes.CLASS_DEF);
190         assertWithMessage("Event should be accepted")
191                 .that(filter.accept(ev))
192                 .isTrue();
193     }
194 
195     @Test
196     public void testNonMatchingFilePattern() throws Exception {
197         final Pattern pattern = Pattern.compile("NonMatchingRegexp");
198         final XpathFilterElement filter =
199                 new XpathFilterElement(pattern, null, null, null, null);
200         final TreeWalkerAuditEvent ev = getEvent(3, 0,
201                 TokenTypes.CLASS_DEF);
202         assertWithMessage("Event should be accepted")
203                 .that(filter.accept(ev))
204                 .isTrue();
205     }
206 
207     @Test
208     public void testNonMatchingCheckRegexp() throws Exception {
209         final XpathFilterElement filter =
210                 new XpathFilterElement(null, "NonMatchingRegexp", null, null, null);
211         final TreeWalkerAuditEvent ev = getEvent(3, 0,
212                 TokenTypes.CLASS_DEF);
213         assertWithMessage("Event should be accepted")
214                 .that(filter.accept(ev))
215                 .isTrue();
216     }
217 
218     @Test
219     public void testNonMatchingCheckPattern() throws Exception {
220         final Pattern pattern = Pattern.compile("NonMatchingRegexp");
221         final XpathFilterElement filter =
222                 new XpathFilterElement(null, pattern, null, null, null);
223         final TreeWalkerAuditEvent ev = getEvent(3, 0,
224                 TokenTypes.CLASS_DEF);
225         assertWithMessage("Event should be accepted")
226                 .that(filter.accept(ev))
227                 .isTrue();
228     }
229 
230     @Test
231     public void testNullViolation() {
232         final XpathFilterElement filter = new XpathFilterElement(
233                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, null);
234         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(null,
235                 file.getName(), null, null);
236         assertWithMessage("Event should be accepted")
237                 .that(filter.accept(ev))
238                 .isTrue();
239     }
240 
241     @Test
242     public void testNonMatchingModuleId() throws Exception {
243         final XpathFilterElement filter = new XpathFilterElement(
244                 "InputXpathFilterElementSuppressByXpath", "Test", null, "id19", null);
245         final Violation message =
246                 new Violation(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id20",
247                         getClass(), null);
248         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
249                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
250         assertWithMessage("Event should be accepted")
251                 .that(filter.accept(ev))
252                 .isTrue();
253     }
254 
255     @Test
256     public void testMatchingModuleId() throws Exception {
257         final String xpath = "//CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
258         final XpathFilterElement filter = new XpathFilterElement(
259                 "InputXpathFilterElementSuppressByXpath", "Test", null, "id19", xpath);
260         final Violation message =
261                 new Violation(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id19",
262                         getClass(), null);
263         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
264                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
265         assertWithMessage("Event should be rejected")
266                 .that(filter.accept(ev))
267                 .isFalse();
268     }
269 
270     @Test
271     public void testNonMatchingChecks() throws Exception {
272         final String xpath = "NON_MATCHING_QUERY";
273         final XpathFilterElement filter = new XpathFilterElement(
274                 "InputXpathFilterElementSuppressByXpath", "NonMatchingRegexp", null, "id19", xpath);
275         final Violation message =
276                 new Violation(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id19",
277                         getClass(), null);
278         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
279                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
280         assertWithMessage("Event should be accepted")
281                 .that(filter.accept(ev))
282                 .isTrue();
283     }
284 
285     @Test
286     public void testNonMatchingFileNameModuleIdAndCheck() throws Exception {
287         final String xpath = "NON_MATCHING_QUERY";
288         final XpathFilterElement filter = new XpathFilterElement(
289                 "InputXpathFilterElementSuppressByXpath", null, null, null, xpath);
290         final TreeWalkerAuditEvent ev = getEvent(3, 0,
291                 TokenTypes.CLASS_DEF);
292         assertWithMessage("Event should be accepted")
293                 .that(filter.accept(ev))
294                 .isTrue();
295     }
296 
297     @Test
298     public void testNullModuleIdAndNonMatchingChecks() throws Exception {
299         final String xpath = "NON_MATCHING_QUERY";
300         final XpathFilterElement filter = new XpathFilterElement(
301                 "InputXpathFilterElementSuppressByXpath", "NonMatchingRegexp", null, null, xpath);
302         final TreeWalkerAuditEvent ev = getEvent(3, 0,
303                 TokenTypes.CLASS_DEF);
304         assertWithMessage("Event should be accepted")
305                 .that(filter.accept(ev))
306                 .isTrue();
307     }
308 
309     @Test
310     public void testDecideByMessage() throws Exception {
311         final Violation message = new Violation(1, 0, TokenTypes.CLASS_DEF, "", "",
312                 null, null, null, getClass(), "Test");
313         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
314                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
315         final XpathFilterElement filter1 = new XpathFilterElement(null, null, "Test", null, null);
316         final XpathFilterElement filter2 = new XpathFilterElement(null, null, "Bad", null, null);
317         assertWithMessage("Message match")
318                 .that(filter1.accept(ev))
319                 .isFalse();
320         assertWithMessage("Message not match")
321                 .that(filter2.accept(ev))
322                 .isTrue();
323     }
324 
325     @Test
326     public void testThrowException() {
327         final String xpath = "//CLASS_DEF[@text='InputXpathFilterElementSuppressByXpath']";
328         final XpathFilterElement filter = new XpathFilterElement(
329                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
330         final Violation message =
331                 new Violation(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id19",
332                         getClass(), null);
333         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents,
334                 file.getName(), message, null);
335         try {
336             filter.accept(ev);
337             assertWithMessage("Exception is expected").fail();
338         }
339         catch (IllegalStateException ex) {
340             assertWithMessage("Exception message does not match expected one")
341                     .that(ex.getMessage())
342                     .contains("Cannot initialize context and evaluate query");
343         }
344     }
345 
346     @Test
347     public void testEqualsAndHashCode() throws Exception {
348         final XPathEvaluator xpathEvaluator = new XPathEvaluator(Configuration.newConfiguration());
349         final EqualsVerifierReport ev = EqualsVerifier.forClass(XpathFilterElement.class)
350             .withPrefabValues(XPathExpression.class,
351                 xpathEvaluator.createExpression("//METHOD_DEF"),
352                 xpathEvaluator.createExpression("//VARIABLE_DEF"))
353                 .usingGetClass()
354                 .withIgnoredFields("xpathExpression", "isEmptyConfig")
355                 .report();
356         assertWithMessage("Error: " + ev.getMessage())
357                 .that(ev.isSuccessful())
358                 .isTrue();
359     }
360 
361     private TreeWalkerAuditEvent getEvent(int line, int column, int tokenType)
362             throws Exception {
363         final Violation message =
364                 new Violation(line, column, tokenType, "", "", null, null, null,
365                         getClass(), null);
366         return new TreeWalkerAuditEvent(fileContents, file.getName(), message,
367                 JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
368     }
369 
370 }