1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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 org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.File;
28  import java.nio.charset.StandardCharsets;
29  
30  import org.junit.Before;
31  import org.junit.Test;
32  
33  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
34  import com.puppycrawl.tools.checkstyle.JavaParser;
35  import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
36  import com.puppycrawl.tools.checkstyle.api.FileContents;
37  import com.puppycrawl.tools.checkstyle.api.FileText;
38  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
39  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
40  import net.sf.saxon.sxpath.XPathEvaluator;
41  import net.sf.saxon.sxpath.XPathExpression;
42  import nl.jqno.equalsverifier.EqualsVerifier;
43  import nl.jqno.equalsverifier.EqualsVerifierReport;
44  
45  public class XpathFilterElementTest extends AbstractModuleTestSupport {
46  
47      private File file;
48      private FileContents fileContents;
49  
50      @Before
51      public void setUp() throws Exception {
52          file = new File(getPath("InputXpathFilterElementSuppressByXpath.java"));
53          fileContents = new FileContents(new FileText(file,
54                  StandardCharsets.UTF_8.name()));
55      }
56  
57      @Override
58      protected String getPackageLocation() {
59          return "com/puppycrawl/tools/checkstyle/filters/xpathfilterelement";
60      }
61  
62      @Test
63      public void testMatching() throws Exception {
64          final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
65          final XpathFilterElement filter = new XpathFilterElement(
66                  "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
67          final TreeWalkerAuditEvent ev = getEvent(3, 0,
68                  TokenTypes.CLASS_DEF);
69          assertFalse("Event should be rejected", filter.accept(ev));
70      }
71  
72      @Test
73      public void testNonMatchingTokenType() throws Exception {
74          final String xpath = "//METHOD_DEF[./IDENT[@text='countTokens']]";
75          final XpathFilterElement filter = new XpathFilterElement(
76                  "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
77          final TreeWalkerAuditEvent ev = getEvent(3, 0,
78                  TokenTypes.CLASS_DEF);
79          assertTrue("Event should be accepted", filter.accept(ev));
80      }
81  
82      @Test
83      public void testNonMatchingLineNumber() throws Exception {
84          final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
85          final XpathFilterElement filter = new XpathFilterElement(
86                  "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
87          final TreeWalkerAuditEvent ev = getEvent(100, 0,
88                  TokenTypes.CLASS_DEF);
89          assertTrue("Event should be accepted", filter.accept(ev));
90      }
91  
92      @Test
93      public void testNonMatchingColumnNumber() throws Exception {
94          final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
95          final XpathFilterElement filter = new XpathFilterElement(
96                  "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
97          final TreeWalkerAuditEvent ev = getEvent(3, 100,
98                  TokenTypes.CLASS_DEF);
99          assertTrue("Event should be accepted", filter.accept(ev));
100     }
101 
102     @Test
103     public void testComplexQuery() throws Exception {
104         final String xpath = "//VARIABLE_DEF[./IDENT[@text='pi'] and "
105                 + "../../IDENT[@text='countTokens']] "
106                 + "| //VARIABLE_DEF[./IDENT[@text='someVariable'] and ../../IDENT[@text='sum']]";
107         final XpathFilterElement filter = new XpathFilterElement(
108                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
109         final TreeWalkerAuditEvent eventOne = getEvent(5, 8,
110                 TokenTypes.VARIABLE_DEF);
111         final TreeWalkerAuditEvent eventTwo = getEvent(10, 4,
112                 TokenTypes.VARIABLE_DEF);
113         final TreeWalkerAuditEvent eventThree = getEvent(15, 8,
114                 TokenTypes.VARIABLE_DEF);
115         assertFalse("Event should be rejected", filter.accept(eventOne));
116         assertTrue("Event should be accepted", filter.accept(eventTwo));
117         assertFalse("Event should be rejected", filter.accept(eventThree));
118     }
119 
120     @Test
121     public void testIncorrectQuery() {
122         final String xpath = "1@#";
123         try {
124             final Object test = new XpathFilterElement("InputXpathFilterElementSuppressByXpath",
125                     "Test", null, null, xpath);
126             fail("Exception was expected but got " + test);
127         }
128         catch (IllegalArgumentException ex) {
129             assertTrue("Message should be: Unexpected xpath query",
130                     ex.getMessage().contains("Unexpected xpath query"));
131         }
132     }
133 
134     @Test
135     public void testNoQuery() throws Exception {
136         final TreeWalkerAuditEvent event = getEvent(15, 8,
137                 TokenTypes.VARIABLE_DEF);
138         final XpathFilterElement filter = new XpathFilterElement(
139                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, null);
140         assertFalse("Event should be accepted", filter.accept(event));
141     }
142 
143     @Test
144     public void testNullFileName() {
145         final String xpath = "NON_MATCHING_QUERY";
146         final XpathFilterElement filter = new XpathFilterElement(
147                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
148         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(null,
149                 null, null, null);
150         assertTrue("Event should be accepted", filter.accept(ev));
151     }
152 
153     @Test
154     public void testNonMatchingFileRegexp() throws Exception {
155         final String xpath = "NON_MATCHING_QUERY";
156         final XpathFilterElement filter =
157                 new XpathFilterElement("NonMatchingRegexp", "Test", null, null, xpath);
158         final TreeWalkerAuditEvent ev = getEvent(3, 0,
159                 TokenTypes.CLASS_DEF);
160         assertTrue("Event should be accepted", filter.accept(ev));
161     }
162 
163     @Test
164     public void testNullLocalizedMessage() {
165         final String xpath = "NON_MATCHING_QUERY";
166         final XpathFilterElement filter = new XpathFilterElement(
167                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
168         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(null,
169                 file.getName(), null, null);
170         assertTrue("Event should be accepted", filter.accept(ev));
171     }
172 
173     @Test
174     public void testNonMatchingModuleId() throws Exception {
175         final String xpath = "NON_MATCHING_QUERY";
176         final XpathFilterElement filter = new XpathFilterElement(
177                 "InputXpathFilterElementSuppressByXpath", "Test", null, "id19", xpath);
178         final LocalizedMessage message =
179                 new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id20",
180                         getClass(), null);
181         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
182                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
183         assertTrue("Event should be accepted", filter.accept(ev));
184     }
185 
186     @Test
187     public void testMatchingModuleId() throws Exception {
188         final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
189         final XpathFilterElement filter = new XpathFilterElement(
190                 "InputXpathFilterElementSuppressByXpath", "Test", null, "id19", xpath);
191         final LocalizedMessage message =
192                 new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id19",
193                         getClass(), null);
194         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
195                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
196         assertFalse("Event should be rejected", filter.accept(ev));
197     }
198 
199     @Test
200     public void testNonMatchingChecks() throws Exception {
201         final String xpath = "NON_MATCHING_QUERY";
202         final XpathFilterElement filter = new XpathFilterElement(
203                 "InputXpathFilterElementSuppressByXpath", "NonMatchingRegexp", null, "id19", xpath);
204         final LocalizedMessage message =
205                 new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id19",
206                         getClass(), null);
207         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
208                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
209         assertTrue("Event should be accepted", filter.accept(ev));
210     }
211 
212     @Test
213     public void testNonMatchingFileNameModuleIdAndCheck() throws Exception {
214         final String xpath = "NON_MATCHING_QUERY";
215         final XpathFilterElement filter = new XpathFilterElement(
216                 "InputXpathFilterElementSuppressByXpath", null, null, null, xpath);
217         final TreeWalkerAuditEvent ev = getEvent(3, 0,
218                 TokenTypes.CLASS_DEF);
219         assertTrue("Event should be accepted", filter.accept(ev));
220     }
221 
222     @Test
223     public void testNullModuleIdAndNonMatchingChecks() throws Exception {
224         final String xpath = "NON_MATCHING_QUERY";
225         final XpathFilterElement filter = new XpathFilterElement(
226                 "InputXpathFilterElementSuppressByXpath", "NonMatchingRegexp", null, null, xpath);
227         final TreeWalkerAuditEvent ev = getEvent(3, 0,
228                 TokenTypes.CLASS_DEF);
229         assertTrue("Event should be accepted", filter.accept(ev));
230     }
231 
232     @Test
233     public void testDecideByMessage() throws Exception {
234         final LocalizedMessage message = new LocalizedMessage(1, 0, TokenTypes.CLASS_DEF, "", "",
235                 null, null, null, getClass(), "Test");
236         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents, file.getName(),
237                 message, JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
238         final XpathFilterElement filter1 = new XpathFilterElement(null, null, "Test", null, null);
239         final XpathFilterElement filter2 = new XpathFilterElement(null, null, "Bad", null, null);
240         assertFalse("Message match", filter1.accept(ev));
241         assertTrue("Message not match", filter2.accept(ev));
242     }
243 
244     @Test
245     public void testThrowException() {
246         final String xpath = "/CLASS_DEF[@text='InputXpathFilterElementSuppressByXpath']";
247         final XpathFilterElement filter = new XpathFilterElement(
248                 "InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
249         final LocalizedMessage message =
250                 new LocalizedMessage(3, 0, TokenTypes.CLASS_DEF, "", "", null, null, "id19",
251                         getClass(), null);
252         final TreeWalkerAuditEvent ev = new TreeWalkerAuditEvent(fileContents,
253                 file.getName(), message, null);
254         try {
255             filter.accept(ev);
256             fail("Exception is expected");
257         }
258         catch (IllegalStateException ex) {
259             assertTrue("Exception message does not match expected one",
260                     ex.getMessage().contains("Cannot initialize context and evaluate query"));
261         }
262     }
263 
264     @Test
265     public void testEqualsAndHashCode() throws Exception {
266         final XPathEvaluator xpathEvaluator = new XPathEvaluator();
267         final EqualsVerifierReport ev = EqualsVerifier.forClass(XpathFilterElement.class)
268             .withPrefabValues(XPathExpression.class,
269                 xpathEvaluator.createExpression("//METHOD_DEF"),
270                 xpathEvaluator.createExpression("//VARIABLE_DEF"))
271                 .usingGetClass()
272                 .withIgnoredFields("fileRegexp", "checkRegexp", "messageRegexp", "xpathExpression")
273                 .report();
274         assertEquals("Error: " + ev.getMessage(), EqualsVerifierReport.SUCCESS, ev);
275     }
276 
277     private TreeWalkerAuditEvent getEvent(int line, int column, int tokenType)
278             throws Exception {
279         final LocalizedMessage message =
280                 new LocalizedMessage(line, column, tokenType, "", "", null, null, null,
281                         getClass(), null);
282         return new TreeWalkerAuditEvent(fileContents, file.getName(), message,
283                 JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS));
284     }
285 
286 }