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.xpath;
21
22 import static com.puppycrawl.tools.checkstyle.internal.utils.XpathUtil.getXpathItems;
23 import static org.junit.Assert.assertArrayEquals;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29
30 import java.io.File;
31 import java.util.List;
32
33 import org.junit.Test;
34
35 import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport;
36 import com.puppycrawl.tools.checkstyle.JavaParser;
37 import com.puppycrawl.tools.checkstyle.api.DetailAST;
38 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
39 import net.sf.saxon.om.AxisInfo;
40 import net.sf.saxon.om.NodeInfo;
41 import net.sf.saxon.tree.iter.EmptyIterator;
42
43 public class XpathMapperTest extends AbstractPathTestSupport {
44
45 @Override
46 protected String getPackageLocation() {
47 return "com/puppycrawl/tools/checkstyle/xpath/xpathmapper";
48 }
49
50 @Test
51 public void testFullPath() throws Exception {
52 final String xpath = "/CLASS_DEF/OBJBLOCK/METHOD_DEF[1]/SLIST/VARIABLE_DEF[2]";
53 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
54 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
55 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
56 TokenTypes.CLASS_DEF)
57 .findFirstToken(TokenTypes.OBJBLOCK)
58 .findFirstToken(TokenTypes.METHOD_DEF)
59 .findFirstToken(TokenTypes.SLIST)
60 .findFirstToken(TokenTypes.VARIABLE_DEF)
61 .getNextSibling()
62 .getNextSibling();
63 final DetailAST[] expected = {expectedVariableDefNode};
64 assertArrayEquals("Result nodes differ from expected", expected, actual);
65 }
66
67 @Test
68 public void testParent() throws Exception {
69 final String xpath = "(//VARIABLE_DEF)[1]/..";
70 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
71 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
72 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
73 TokenTypes.CLASS_DEF)
74 .findFirstToken(TokenTypes.OBJBLOCK)
75 .findFirstToken(TokenTypes.METHOD_DEF)
76 .findFirstToken(TokenTypes.SLIST);
77 final DetailAST[] expected = {expectedVariableDefNode};
78 assertArrayEquals("Result nodes differ from expected", expected, actual);
79 }
80
81 @Test
82 public void testCurlyBrackets() throws Exception {
83 final String xpath = "(//RCURLY)[2]";
84 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
85 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
86 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
87 TokenTypes.CLASS_DEF)
88 .findFirstToken(TokenTypes.OBJBLOCK)
89 .findFirstToken(TokenTypes.METHOD_DEF)
90 .findFirstToken(TokenTypes.SLIST)
91 .findFirstToken(TokenTypes.RCURLY);
92 final DetailAST[] expected = {expectedVariableDefNode};
93 assertArrayEquals("Result nodes differ from expected", expected, actual);
94 }
95
96 @Test
97 public void testOr() throws Exception {
98 final String xpath = "//CLASS_DEF | //METHOD_DEF";
99 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
100 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
101 final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
102 TokenTypes.CLASS_DEF);
103 final DetailAST expectedMethodDefNode1 = expectedClassDefNode
104 .findFirstToken(TokenTypes.OBJBLOCK)
105 .findFirstToken(TokenTypes.METHOD_DEF);
106 final DetailAST expectedMethodDefNode2 = expectedMethodDefNode1.getNextSibling();
107 final DetailAST[] expected = {expectedClassDefNode, expectedMethodDefNode1,
108 expectedMethodDefNode2};
109 assertArrayEquals("Result nodes differ from expected", expected, actual);
110 }
111
112 @Test
113 public void testComplexQueryOne() throws Exception {
114 final String xpath = "/CLASS_DEF | /CLASS_DEF/OBJBLOCK";
115 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
116 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
117 final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
118 TokenTypes.CLASS_DEF);
119 final DetailAST expectedObjblockNode = expectedClassDefNode
120 .findFirstToken(TokenTypes.OBJBLOCK);
121 final DetailAST[] expected = {expectedClassDefNode, expectedObjblockNode};
122 assertArrayEquals("Result nodes differ from expected", expected, actual);
123 }
124
125 @Test
126 public void testComplexQueryTwo() throws Exception {
127 final String xpath = "/PACKAGE_DEF | /PACKAGE_DEF/ANNOTATIONS";
128 final RootNode rootNode = getRootNode("InputXpathMapperAnnotation.java");
129 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
130 final DetailAST expectedPackageDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
131 TokenTypes.PACKAGE_DEF);
132 final DetailAST expectedAnnotationsNode = expectedPackageDefNode
133 .findFirstToken(TokenTypes.ANNOTATIONS);
134 final DetailAST[] expected = {expectedAnnotationsNode, expectedPackageDefNode};
135 assertArrayEquals("Result nodes differ from expected", expected, actual);
136 }
137
138 @Test
139 public void testComplexQueryThree() throws Exception {
140 final String xpath = "//CLASS_DEF | //CLASS_DEF//METHOD_DEF | /CLASS_DEF/OBJBLOCK";
141 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
142 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
143 final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
144 TokenTypes.CLASS_DEF);
145 final DetailAST expectedObjblockNode = expectedClassDefNode
146 .findFirstToken(TokenTypes.OBJBLOCK);
147 final DetailAST expectedMethodDefNode = expectedObjblockNode
148 .findFirstToken(TokenTypes.METHOD_DEF);
149 final DetailAST expectedMethodDefNode2 = expectedObjblockNode
150 .findFirstToken(TokenTypes.METHOD_DEF)
151 .getNextSibling();
152 final DetailAST[] expected = {expectedClassDefNode, expectedMethodDefNode,
153 expectedMethodDefNode2, expectedObjblockNode};
154 assertArrayEquals("Result nodes differ from expected", expected, actual);
155 }
156
157 @Test
158 public void testAttributeOr() throws Exception {
159 final String xpath = "//METHOD_DEF[./IDENT[@text='getSomeMethod'] "
160 + "or ./IDENT[@text='nonExistentMethod']]";
161 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
162 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
163 final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
164 TokenTypes.CLASS_DEF);
165 final DetailAST expectedMethodDefNode = expectedClassDefNode
166 .findFirstToken(TokenTypes.OBJBLOCK)
167 .findFirstToken(TokenTypes.METHOD_DEF)
168 .getNextSibling();
169 final DetailAST[] expected = {expectedMethodDefNode};
170 assertArrayEquals("Result nodes differ from expected", expected, actual);
171 }
172
173 @Test
174 public void testAttributeAnd() throws Exception {
175 final String xpath = "//METHOD_DEF[./IDENT[@text='callSomeMethod'] and "
176 + "../..[./IDENT[@text='InputXpathMapperAst']]]";
177 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
178 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
179 final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
180 TokenTypes.CLASS_DEF);
181 final DetailAST expectedMethodDefNode = expectedClassDefNode
182 .findFirstToken(TokenTypes.OBJBLOCK)
183 .findFirstToken(TokenTypes.METHOD_DEF);
184 final DetailAST[] expected = {expectedMethodDefNode};
185 assertArrayEquals("Result nodes differ from expected", expected, actual);
186 }
187
188 @Test
189 public void testQueryAllElementsWithAttribute() throws Exception {
190 final String xpath = "//*[./IDENT[@text]]";
191 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
192 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
193 assertEquals("Invalid number of nodes", 18, nodes.size());
194 }
195
196 @Test
197 public void testQueryElementByIndex() throws Exception {
198 final String xpath = "(//VARIABLE_DEF)[1]";
199 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
200 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
201 assertEquals("Invalid number of nodes", 1, actual.length);
202 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
203 TokenTypes.CLASS_DEF)
204 .findFirstToken(TokenTypes.OBJBLOCK)
205 .findFirstToken(TokenTypes.METHOD_DEF)
206 .findFirstToken(TokenTypes.SLIST)
207 .findFirstToken(TokenTypes.VARIABLE_DEF);
208 final DetailAST[] expected = {expectedVariableDefNode};
209 assertArrayEquals("Result nodes differ from expected", expected, actual);
210 }
211
212 @Test
213 public void testQueryAllVariableDefinitionsWithAttribute() throws Exception {
214 final String xpath = "//VARIABLE_DEF[./IDENT[@*]]";
215 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
216 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
217 assertEquals("Invalid number of nodes", 4, nodes.size());
218 }
219
220 @Test
221 public void testQueryAllVariableDefWrongAttribute() throws Exception {
222 final String xpath = "//VARIABLE_DEF[@qwe]";
223 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
224 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
225 assertEquals("Invalid number of nodes", 0, nodes.size());
226 }
227
228 @Test
229 public void testQueryAllMethodDefinitionsInContext() throws Exception {
230 final String objectXpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]//OBJBLOCK";
231 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
232 final List<NodeInfo> objectNodes = getXpathItems(objectXpath, rootNode);
233 assertEquals("Invalid number of nodes", 1, objectNodes.size());
234 final AbstractNode objNode = (AbstractNode) objectNodes.get(0);
235 final String methodsXpath = "METHOD_DEF";
236 final List<NodeInfo> methodsNodes = getXpathItems(methodsXpath, objNode);
237 assertEquals("Invalid number of nodes", 2, methodsNodes.size());
238 final DetailAST[] actual = convertToArray(methodsNodes);
239 final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
240 TokenTypes.CLASS_DEF)
241 .findFirstToken(TokenTypes.OBJBLOCK)
242 .findFirstToken(TokenTypes.METHOD_DEF);
243 final DetailAST[] expected = {expectedMethodDefNode,
244 expectedMethodDefNode.getNextSibling()};
245 assertArrayEquals("Result nodes differ from expected", expected, actual);
246 }
247
248 @Test
249 public void testQueryAllClassDefinitions() throws Exception {
250 final String xpath = "CLASS_DEF";
251 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
252 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
253 assertEquals("Invalid number of nodes", 1, nodes.size());
254 final AbstractNode classDefNode = (AbstractNode) nodes.get(0);
255 assertEquals("Invalid number of nodes", 3, classDefNode.getLineNumber());
256 assertEquals("Invalid number of nodes", 0, classDefNode.getColumnNumber());
257 final DetailAST[] actual = convertToArray(nodes);
258 final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
259 TokenTypes.CLASS_DEF);
260 final DetailAST[] expected = {expectedClassDefNode};
261 assertArrayEquals("Result nodes differ from expected", expected, actual);
262 }
263
264 @Test
265 public void testQueryByMethodName() throws Exception {
266 final String xpath = "//METHOD_DEF[./IDENT[@text='getSomeMethod']]";
267 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
268 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
269 final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
270 TokenTypes.CLASS_DEF)
271 .findFirstToken(TokenTypes.OBJBLOCK)
272 .findFirstToken(TokenTypes.METHOD_DEF)
273 .getNextSibling();
274 final DetailAST[] expected = {expectedMethodDefNode};
275 assertArrayEquals("Result nodes differ from expected", expected, actual);
276 }
277
278 @Test
279 public void testQueryMethodDefinitionsByClassName() throws Exception {
280 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]"
281 + "//OBJBLOCK//METHOD_DEF";
282 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
283 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
284 final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
285 TokenTypes.CLASS_DEF)
286 .findFirstToken(TokenTypes.OBJBLOCK)
287 .findFirstToken(TokenTypes.METHOD_DEF);
288 final DetailAST[] expected = {expectedMethodDefNode,
289 expectedMethodDefNode.getNextSibling()};
290 assertArrayEquals("Result nodes differ from expected", expected, actual);
291 }
292
293 @Test
294 public void testQueryByClassNameAndMethodName() throws Exception {
295 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]//OBJBLOCK"
296 + "//METHOD_DEF[./IDENT[@text='getSomeMethod']]";
297 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
298 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
299 final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
300 TokenTypes.CLASS_DEF)
301 .findFirstToken(TokenTypes.OBJBLOCK)
302 .findFirstToken(TokenTypes.METHOD_DEF)
303 .getNextSibling();
304 final DetailAST[] expected = {expectedMethodDefNode};
305 assertArrayEquals("Result nodes differ from expected", expected, actual);
306 }
307
308 @Test
309 public void testQueryClassDefinitionByClassName() throws Exception {
310 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]";
311 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
312 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
313 final DetailAST[] actual = convertToArray(nodes);
314 final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
315 TokenTypes.CLASS_DEF);
316 final DetailAST[] expected = {expectedClassDefNode};
317 final ElementNode classDefNode = (ElementNode) nodes.get(0);
318 assertEquals("Invalid number of nodes", "CLASS_DEF", classDefNode.getStringValue());
319 assertArrayEquals("Result nodes differ from expected", expected, actual);
320 }
321
322 @Test
323 public void testQueryWrongClassName() throws Exception {
324 final String xpath = "/CLASS_DEF[@text='WrongName']";
325 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
326 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
327 assertTrue("Should return true, because no item matches xpath", nodes.isEmpty());
328 }
329
330 @Test
331 public void testQueryWrongXpath() throws Exception {
332 final String xpath = "/WRONG_XPATH";
333 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
334 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
335 assertTrue("Should return true, because no item matches xpath", nodes.isEmpty());
336 }
337
338 @Test
339 public void testQueryAncestor() throws Exception {
340 final String xpath = "//VARIABLE_DEF[./IDENT[@text='another']]/ancestor::METHOD_DEF";
341 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
342 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
343 final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
344 TokenTypes.CLASS_DEF)
345 .findFirstToken(TokenTypes.OBJBLOCK)
346 .findFirstToken(TokenTypes.METHOD_DEF);
347 final DetailAST[] expected = {expectedMethodDefNode};
348 assertArrayEquals("Result nodes differ from expected", expected, actual);
349 }
350
351 @Test
352 public void testQueryAncestorOrSelf() throws Exception {
353 final String xpath = "//VARIABLE_DEF[./IDENT[@text='another']]"
354 + "/ancestor-or-self::VARIABLE_DEF";
355 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
356 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
357 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
358 TokenTypes.CLASS_DEF)
359 .findFirstToken(TokenTypes.OBJBLOCK)
360 .findFirstToken(TokenTypes.METHOD_DEF)
361 .findFirstToken(TokenTypes.SLIST)
362 .findFirstToken(TokenTypes.VARIABLE_DEF)
363 .getNextSibling()
364 .getNextSibling();
365 final DetailAST[] expected = {expectedVariableDefNode};
366 assertArrayEquals("Result nodes differ from expected", expected, actual);
367 }
368
369 @Test
370 public void testQueryDescendant() throws Exception {
371 final String xpath = "//METHOD_DEF/descendant::EXPR";
372 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
373 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
374 assertEquals("Invalid number of nodes", 6, nodes.size());
375 }
376
377 @Test
378 public void testQueryDescendantOrSelf() throws Exception {
379 final String xpath = "//METHOD_DEF/descendant-or-self::METHOD_DEF";
380 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
381 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
382 final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
383 TokenTypes.CLASS_DEF)
384 .findFirstToken(TokenTypes.OBJBLOCK)
385 .findFirstToken(TokenTypes.METHOD_DEF);
386 final DetailAST[] expected = {expectedMethodDefNode,
387 expectedMethodDefNode.getNextSibling()};
388 assertArrayEquals("Result nodes differ from expected", expected, actual);
389 }
390
391 @Test
392 public void testQueryNoChild() throws Exception {
393 final String xpath = "//RCURLY/METHOD_DEF";
394 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
395 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
396 assertTrue("Should return true, because no item matches xpath", nodes.isEmpty());
397 }
398
399 @Test
400 public void testQueryNoDescendant() throws Exception {
401 final String xpath = "//RCURLY/descendant::METHOD_DEF";
402 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
403 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
404 assertTrue("Should return true, because no item matches xpath", nodes.isEmpty());
405 }
406
407 @Test
408 public void testQueryRootNotImplementedAxis() throws Exception {
409 final String xpath = "//following-sibling::METHOD_DEF";
410 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
411 try {
412 getXpathItems(xpath, rootNode);
413 fail("Exception is excepted");
414 }
415 catch (UnsupportedOperationException ex) {
416 assertEquals("Invalid number of nodes", "Operation is not supported", ex.getMessage());
417 }
418 }
419
420 @Test
421 public void testQueryElementNotImplementedAxis() throws Exception {
422 final String xpath = "/CLASS_DEF//following-sibling::METHOD_DEF";
423 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
424 try {
425 getXpathItems(xpath, rootNode);
426 fail("Exception is excepted");
427 }
428 catch (UnsupportedOperationException ex) {
429 assertEquals("Invalid number of nodes", "Operation is not supported", ex.getMessage());
430 }
431 }
432
433 @Test
434 public void testQuerySelf() throws Exception {
435 final String objectXpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]//OBJBLOCK";
436 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
437 final List<NodeInfo> objectNodes = getXpathItems(objectXpath, rootNode);
438 assertEquals("Invalid number of nodes", 1, objectNodes.size());
439 final AbstractNode objNode = (AbstractNode) objectNodes.get(0);
440 final String methodsXpath = "self::OBJBLOCK";
441 final DetailAST[] actual = convertToArray(getXpathItems(methodsXpath, objNode));
442 final DetailAST expectedObjBlockNode = getSiblingByType(rootNode.getUnderlyingNode(),
443 TokenTypes.CLASS_DEF)
444 .findFirstToken(TokenTypes.OBJBLOCK);
445 final DetailAST[] expected = {expectedObjBlockNode};
446 assertArrayEquals("Result nodes differ from expected", expected, actual);
447 }
448
449 @Test
450 public void testRootWithNullDetailAst() {
451 final RootNode emptyRootNode = new RootNode(null);
452 assertFalse("Empty node should not have children", emptyRootNode.hasChildNodes());
453 assertEquals("Invalid number of nodes", EmptyIterator.OfNodes.THE_INSTANCE,
454 emptyRootNode.iterateAxis(
455 AxisInfo.DESCENDANT));
456 assertEquals("Invalid number of nodes", EmptyIterator.OfNodes.THE_INSTANCE,
457 emptyRootNode.iterateAxis(AxisInfo.CHILD));
458 }
459
460 @Test
461 public void testQueryNonExistentAttribute() throws Exception {
462 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]";
463 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
464 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
465 final ElementNode classDefNode = (ElementNode) nodes.get(0);
466 assertNull("Not existing attribute should have null value",
467 classDefNode.getAttributeValue("", "noneExistingAttribute"));
468 }
469
470 @Test
471 public void testQueryRootSelf() throws Exception {
472 final String xpath = "self::node()";
473 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
474 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
475 assertEquals("Invalid number of nodes", 1, nodes.size());
476 }
477
478 @Test
479 public void testQueryAnnotation() throws Exception {
480 final String xpath = "//ANNOTATION[./IDENT[@text='Deprecated']]";
481 final RootNode rootNode = getRootNode("InputXpathMapperAnnotation.java");
482 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
483 final DetailAST expectedAnnotationNode = getSiblingByType(rootNode.getUnderlyingNode(),
484 TokenTypes.CLASS_DEF)
485 .findFirstToken(TokenTypes.MODIFIERS)
486 .findFirstToken(TokenTypes.ANNOTATION);
487 final DetailAST[] expected = {expectedAnnotationNode};
488 assertArrayEquals("Result nodes differ from expected", expected, actual);
489 }
490
491 @Test
492 public void testQueryNonExistentAnnotation() throws Exception {
493 final String xpath = "//ANNOTATION[@text='SpringBootApplication']";
494 final RootNode rootNode = getRootNode("InputXpathMapperAnnotation.java");
495 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
496 assertEquals("Invalid number of nodes", 0, nodes.size());
497 }
498
499 @Test
500 public void testQueryEnumDef() throws Exception {
501 final String xpath = "/ENUM_DEF";
502 final RootNode enumRootNode = getRootNode("InputXpathMapperEnum.java");
503 final DetailAST[] actual = convertToArray(getXpathItems(xpath, enumRootNode));
504 final DetailAST expectedEnumDefNode = getSiblingByType(enumRootNode.getUnderlyingNode(),
505 TokenTypes.ENUM_DEF);
506 final DetailAST[] expected = {expectedEnumDefNode};
507 assertArrayEquals("Result nodes differ from expected", expected, actual);
508 }
509
510 @Test
511 public void testQueryEnumElementsNumber() throws Exception {
512 final String xpath = "/ENUM_DEF/OBJBLOCK/ENUM_CONSTANT_DEF";
513 final RootNode enumRootNode = getRootNode("InputXpathMapperEnum.java");
514 final List<NodeInfo> nodes = getXpathItems(xpath, enumRootNode);
515 assertEquals("Invalid number of nodes", 3, nodes.size());
516 }
517
518 @Test
519 public void testQueryEnumElementByName() throws Exception {
520 final String xpath = "//*[./IDENT[@text='TWO']]";
521 final RootNode enumRootNode = getRootNode("InputXpathMapperEnum.java");
522 final DetailAST[] actual = convertToArray(getXpathItems(xpath, enumRootNode));
523 final DetailAST expectedEnumConstantDefNode = getSiblingByType(
524 enumRootNode.getUnderlyingNode(),
525 TokenTypes.ENUM_DEF)
526 .findFirstToken(TokenTypes.OBJBLOCK)
527 .findFirstToken(TokenTypes.ENUM_CONSTANT_DEF)
528 .getNextSibling()
529 .getNextSibling();
530 final DetailAST[] expected = {expectedEnumConstantDefNode};
531 assertArrayEquals("Result nodes differ from expected", expected, actual);
532 }
533
534 @Test
535 public void testQueryInterfaceDef() throws Exception {
536 final String xpath = "/INTERFACE_DEF";
537 final RootNode interfaceRootNode = getRootNode("InputXpathMapperInterface.java");
538 final DetailAST[] actual = convertToArray(getXpathItems(xpath, interfaceRootNode));
539 final DetailAST expectedInterfaceDefNode = getSiblingByType(
540 interfaceRootNode.getUnderlyingNode(),
541 TokenTypes.INTERFACE_DEF);
542 final DetailAST[] expected = {expectedInterfaceDefNode};
543 assertArrayEquals("Result nodes differ from expected", expected, actual);
544 }
545
546 @Test
547 public void testQueryInterfaceMethodDefNumber() throws Exception {
548 final String xpath = "/INTERFACE_DEF/OBJBLOCK/METHOD_DEF";
549 final RootNode interfaceRootNode = getRootNode("InputXpathMapperInterface.java");
550 final List<NodeInfo> nodes = getXpathItems(xpath, interfaceRootNode);
551 assertEquals("Invalid number of nodes", 4, nodes.size());
552 }
553
554 @Test
555 public void testQueryInterfaceParameterDef() throws Exception {
556 final String xpath = "//PARAMETER_DEF[./IDENT[@text='someVariable']]/../..";
557 final RootNode interfaceRootNode = getRootNode("InputXpathMapperInterface.java");
558 final DetailAST[] actual = convertToArray(getXpathItems(xpath, interfaceRootNode));
559 final DetailAST expectedMethodDefNode = getSiblingByType(
560 interfaceRootNode.getUnderlyingNode(),
561 TokenTypes.INTERFACE_DEF)
562 .findFirstToken(TokenTypes.OBJBLOCK)
563 .findFirstToken(TokenTypes.METHOD_DEF)
564 .getNextSibling();
565 final DetailAST[] expected = {expectedMethodDefNode};
566 assertArrayEquals("Result nodes differ from expected", expected, actual);
567 }
568
569 @Test
570 public void testIdent() throws Exception {
571 final String xpath = "/CLASS_DEF/IDENT[@text='InputXpathMapperAst']";
572 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
573 final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
574 final DetailAST[] actual = convertToArray(nodes);
575 final DetailAST expectedIdentNode = getSiblingByType(rootNode.getUnderlyingNode(),
576 TokenTypes.CLASS_DEF)
577 .findFirstToken(TokenTypes.IDENT);
578
579 final DetailAST[] expected = {expectedIdentNode};
580 assertArrayEquals("Result nodes differ from expected", expected, actual);
581 }
582
583 @Test
584 public void testIdentByText() throws Exception {
585 final String xpath = "//IDENT[@text='puppycrawl']";
586 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
587 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
588 final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
589 TokenTypes.PACKAGE_DEF)
590 .findFirstToken(TokenTypes.DOT)
591 .findFirstToken(TokenTypes.DOT)
592 .findFirstToken(TokenTypes.DOT)
593 .findFirstToken(TokenTypes.DOT)
594 .findFirstToken(TokenTypes.DOT)
595 .findFirstToken(TokenTypes.IDENT)
596 .getNextSibling();
597 final DetailAST[] expected = {expectedMethodDefNode};
598 assertArrayEquals("Result nodes differ from expected", expected, actual);
599 }
600
601 @Test
602 public void testNumVariableByItsValue() throws Exception {
603 final String xpath = "//VARIABLE_DEF[.//NUM_INT[@text=123]]";
604 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
605 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
606 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
607 TokenTypes.CLASS_DEF)
608 .findFirstToken(TokenTypes.OBJBLOCK)
609 .findFirstToken(TokenTypes.METHOD_DEF)
610 .findFirstToken(TokenTypes.SLIST)
611 .findFirstToken(TokenTypes.VARIABLE_DEF);
612 final DetailAST[] expected = {expectedVariableDefNode};
613 assertArrayEquals("Result nodes differ from expected", expected, actual);
614 }
615
616 @Test
617 public void testStringVariableByItsValue() throws Exception {
618 final String xpath = "//VARIABLE_DEF[./ASSIGN/EXPR"
619 + "/STRING_LITERAL[@text='HelloWorld']]";
620 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
621 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
622 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
623 TokenTypes.CLASS_DEF)
624 .findFirstToken(TokenTypes.OBJBLOCK)
625 .findFirstToken(TokenTypes.METHOD_DEF)
626 .findFirstToken(TokenTypes.SLIST)
627 .findFirstToken(TokenTypes.VARIABLE_DEF)
628 .getNextSibling()
629 .getNextSibling();
630 final DetailAST[] expected = {expectedVariableDefNode};
631 assertArrayEquals("Result nodes differ from expected", expected, actual);
632 }
633
634 @Test
635 public void testSameNodesByNameAndByText() throws Exception {
636 final String xpath1 = "//VARIABLE_DEF[./IDENT[@text='another']]/ASSIGN/EXPR/STRING_LITERAL";
637 final String xpath2 = "//VARIABLE_DEF/ASSIGN/EXPR/STRING_LITERAL[@text='HelloWorld']";
638 final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
639 final DetailAST[] actual1 = convertToArray(getXpathItems(xpath1, rootNode));
640 final DetailAST[] actual2 = convertToArray(getXpathItems(xpath2, rootNode));
641 assertArrayEquals("Result nodes differ from expected", actual1, actual2);
642 }
643
644 @Test
645 public void testMethodDefByAnnotationValue() throws Exception {
646 final String xpath = "//METHOD_DEF[.//ANNOTATION[./IDENT[@text='SuppressWarnings']"
647 + " and .//*[@text='good']]]";
648 final RootNode rootNode = getRootNode("InputXpathMapperAnnotation.java");
649 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
650 final DetailAST expectedAnnotationNode = getSiblingByType(rootNode.getUnderlyingNode(),
651 TokenTypes.CLASS_DEF)
652 .findFirstToken(TokenTypes.OBJBLOCK)
653 .findFirstToken(TokenTypes.METHOD_DEF)
654 .getNextSibling();
655 final DetailAST[] expected = {expectedAnnotationNode};
656 assertArrayEquals("Result nodes differ from expected", expected, actual);
657 }
658
659 @Test
660 public void testFirstImport() throws Exception {
661 final String xpath = "/IMPORT[1]";
662 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
663 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
664 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
665 TokenTypes.IMPORT);
666 final DetailAST[] expected = {expectedVariableDefNode};
667 assertArrayEquals("Result nodes differ from expected", expected, actual);
668 }
669
670 @Test
671 public void testSecondImport() throws Exception {
672 final String xpath = "/IMPORT[2]";
673 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
674 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
675 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
676 TokenTypes.IMPORT).getNextSibling();
677 final DetailAST[] expected = {expectedVariableDefNode};
678 assertArrayEquals("Result nodes differ from expected", expected, actual);
679 }
680
681 @Test
682 public void testThirdImport() throws Exception {
683 final String xpath = "/IMPORT[3]";
684 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
685 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
686 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
687 TokenTypes.IMPORT).getNextSibling().getNextSibling();
688 final DetailAST[] expected = {expectedVariableDefNode};
689 assertArrayEquals("Result nodes differ from expected", expected, actual);
690 }
691
692 @Test
693 public void testLastImport() throws Exception {
694 final String xpath = "/IMPORT[9]";
695 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
696 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
697 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
698 TokenTypes.IMPORT)
699 .getNextSibling()
700 .getNextSibling()
701 .getNextSibling()
702 .getNextSibling()
703 .getNextSibling()
704 .getNextSibling()
705 .getNextSibling()
706 .getNextSibling();
707 final DetailAST[] expected = {expectedVariableDefNode};
708 assertArrayEquals("Result nodes differ from expected", expected, actual);
709 }
710
711 @Test
712 public void testFirstCaseGroup() throws Exception {
713 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
714 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
715 + "/SLIST/LITERAL_SWITCH/CASE_GROUP[1]";
716 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
717 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
718 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
719 TokenTypes.CLASS_DEF)
720 .findFirstToken(TokenTypes.OBJBLOCK)
721 .findFirstToken(TokenTypes.METHOD_DEF)
722 .findFirstToken(TokenTypes.SLIST)
723 .findFirstToken(TokenTypes.LITERAL_SWITCH)
724 .findFirstToken(TokenTypes.CASE_GROUP);
725 final DetailAST[] expected = {expectedVariableDefNode};
726 assertArrayEquals("Result nodes differ from expected", expected, actual);
727 }
728
729 @Test
730 public void testSecondCaseGroup() throws Exception {
731 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
732 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
733 + "/SLIST/LITERAL_SWITCH/CASE_GROUP[2]";
734 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
735 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
736 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
737 TokenTypes.CLASS_DEF)
738 .findFirstToken(TokenTypes.OBJBLOCK)
739 .findFirstToken(TokenTypes.METHOD_DEF)
740 .findFirstToken(TokenTypes.SLIST)
741 .findFirstToken(TokenTypes.LITERAL_SWITCH)
742 .findFirstToken(TokenTypes.CASE_GROUP)
743 .getNextSibling();
744 final DetailAST[] expected = {expectedVariableDefNode};
745 assertArrayEquals("Result nodes differ from expected", expected, actual);
746 }
747
748 @Test
749 public void testThirdCaseGroup() throws Exception {
750 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
751 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
752 + "/SLIST/LITERAL_SWITCH/CASE_GROUP[3]";
753 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
754 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
755 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
756 TokenTypes.CLASS_DEF)
757 .findFirstToken(TokenTypes.OBJBLOCK)
758 .findFirstToken(TokenTypes.METHOD_DEF)
759 .findFirstToken(TokenTypes.SLIST)
760 .findFirstToken(TokenTypes.LITERAL_SWITCH)
761 .findFirstToken(TokenTypes.CASE_GROUP)
762 .getNextSibling()
763 .getNextSibling();
764 final DetailAST[] expected = {expectedVariableDefNode};
765 assertArrayEquals("Result nodes differ from expected", expected, actual);
766 }
767
768 @Test
769 public void testFourthCaseGroup() throws Exception {
770 final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
771 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
772 + "/SLIST/LITERAL_SWITCH/CASE_GROUP[4]";
773 final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
774 final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
775 final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
776 TokenTypes.CLASS_DEF)
777 .findFirstToken(TokenTypes.OBJBLOCK)
778 .findFirstToken(TokenTypes.METHOD_DEF)
779 .findFirstToken(TokenTypes.SLIST)
780 .findFirstToken(TokenTypes.LITERAL_SWITCH)
781 .findFirstToken(TokenTypes.CASE_GROUP)
782 .getNextSibling()
783 .getNextSibling()
784 .getNextSibling();
785 final DetailAST[] expected = {expectedVariableDefNode};
786 assertArrayEquals("Result nodes differ from expected", expected, actual);
787 }
788
789 private RootNode getRootNode(String fileName) throws Exception {
790 final File file = new File(getPath(fileName));
791 final DetailAST rootAst = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS);
792 return new RootNode(rootAst);
793 }
794
795 private static DetailAST[] convertToArray(List<NodeInfo> nodes) {
796 final DetailAST[] result = new DetailAST[nodes.size()];
797 for (int i = 0; i < nodes.size(); i++) {
798 final AbstractNode abstractNode = (AbstractNode) nodes.get(i);
799 result[i] = abstractNode.getUnderlyingNode();
800 }
801 return result;
802 }
803
804 private static DetailAST getSiblingByType(DetailAST node, int type) {
805 DetailAST returnValue = null;
806 for (DetailAST ast = node; ast != null; ast = ast.getNextSibling()) {
807 if (ast.getType() == type) {
808 returnValue = ast;
809 break;
810 }
811 }
812 return returnValue;
813 }
814
815 }