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.xpath;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.utils.XpathUtil.getXpathItems;
24  
25  import java.io.File;
26  import java.util.List;
27  
28  import org.junit.jupiter.api.BeforeEach;
29  import org.junit.jupiter.api.Test;
30  
31  import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport;
32  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
33  import com.puppycrawl.tools.checkstyle.JavaParser;
34  import com.puppycrawl.tools.checkstyle.api.DetailAST;
35  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36  import com.puppycrawl.tools.checkstyle.xpath.iterators.DescendantIterator;
37  import net.sf.saxon.om.AxisInfo;
38  import net.sf.saxon.om.NamespaceUri;
39  import net.sf.saxon.om.NodeInfo;
40  import net.sf.saxon.tree.iter.ArrayIterator;
41  import net.sf.saxon.tree.iter.AxisIterator;
42  import net.sf.saxon.tree.iter.EmptyIterator;
43  
44  public class ElementNodeTest extends AbstractPathTestSupport {
45  
46      private static RootNode rootNode;
47  
48      @Override
49      protected String getPackageLocation() {
50          return "com/puppycrawl/tools/checkstyle/xpath/xpathmapper";
51      }
52  
53      @BeforeEach
54      public void init() throws Exception {
55          final File file = new File(getPath("InputXpathMapperAst.java"));
56          final DetailAST rootAst = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS);
57          rootNode = new RootNode(rootAst);
58      }
59  
60      @Test
61      public void testParentChildOrdering() {
62          final DetailAstImpl detailAST = new DetailAstImpl();
63          detailAST.setType(TokenTypes.VARIABLE_DEF);
64  
65          final DetailAstImpl parentAST = new DetailAstImpl();
66          parentAST.setFirstChild(detailAST);
67          parentAST.setType(TokenTypes.METHOD_DEF);
68  
69          final AbstractNode parentNode = new ElementNode(rootNode, rootNode, parentAST, 1, 0);
70          final AbstractNode childNode = new ElementNode(rootNode, parentNode, detailAST, 2, 0);
71          assertWithMessage("Incorrect ordering value")
72              .that(parentNode.compareOrder(childNode))
73              .isEqualTo(-1);
74          assertWithMessage("Incorrect ordering value")
75              .that(childNode.compareOrder(parentNode))
76              .isEqualTo(1);
77      }
78  
79      @Test
80      public void testSiblingsOrdering() {
81          final DetailAstImpl detailAst1 = new DetailAstImpl();
82          detailAst1.setType(TokenTypes.VARIABLE_DEF);
83  
84          final DetailAstImpl detailAst2 = new DetailAstImpl();
85          detailAst2.setType(TokenTypes.NUM_INT);
86  
87          final DetailAstImpl parentAST = new DetailAstImpl();
88          parentAST.setType(TokenTypes.METHOD_DEF);
89          parentAST.addChild(detailAst1);
90          parentAST.addChild(detailAst2);
91  
92          final AbstractNode parentNode = new ElementNode(rootNode, rootNode, parentAST, 1, 0);
93          final List<AbstractNode> children = parentNode.getChildren();
94  
95          assertWithMessage("Incorrect ordering value")
96              .that(children.get(0).compareOrder(children.get(1)))
97              .isEqualTo(-1);
98          assertWithMessage("Incorrect ordering value")
99              .that(children.get(1).compareOrder(children.get(0)))
100             .isEqualTo(1);
101     }
102 
103     @Test
104     public void testCompareOrderWrongInstance() throws Exception {
105         final String xpath = "//OBJBLOCK";
106         final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
107         final int result = nodes.get(0).compareOrder(null);
108         assertWithMessage("Expected result wrong")
109             .that(result)
110             .isEqualTo(0);
111     }
112 
113     @Test
114     public void testGetParent() throws Exception {
115         final String xpath = "//OBJBLOCK";
116         final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
117         assertWithMessage("Invalid number of nodes")
118             .that(nodes)
119             .hasSize(1);
120         final AbstractNode parent = (AbstractNode) nodes.get(0).getParent();
121         assertWithMessage("Invalid token type")
122             .that(parent.getTokenType())
123             .isEqualTo(TokenTypes.CLASS_DEF);
124     }
125 
126     @Test
127     public void testRootOfElementNode() throws Exception {
128         final String xpath = "//OBJBLOCK";
129         final List<NodeInfo> nodes = getXpathItems(xpath, rootNode);
130         assertWithMessage("Invalid number of nodes")
131             .that(nodes)
132             .hasSize(1);
133         final AbstractNode root = (AbstractNode) nodes.get(0).getRoot();
134         assertWithMessage("Invalid token type")
135             .that(root.getTokenType())
136             .isEqualTo(TokenTypes.COMPILATION_UNIT);
137         assertWithMessage("Should return true, because selected node is RootNode")
138                 .that(root)
139                 .isInstanceOf(RootNode.class);
140     }
141 
142     @Test
143     public void testGetNodeByValueNumInt() throws Exception {
144         final String xPath = "//NUM_INT[@text = 123]";
145         final List<NodeInfo> nodes = getXpathItems(xPath, rootNode);
146         assertWithMessage("Invalid number of nodes")
147             .that(nodes)
148             .hasSize(1);
149         final int tokenType = ((AbstractNode) nodes.get(0)).getTokenType();
150         assertWithMessage("Invalid token type")
151             .that(tokenType)
152             .isEqualTo(TokenTypes.NUM_INT);
153     }
154 
155     @Test
156     public void testGetNodeByValueStringLiteral() throws Exception {
157         final String xPath = "//STRING_LITERAL[@text = 'HelloWorld']";
158         final List<NodeInfo> nodes = getXpathItems(xPath, rootNode);
159         assertWithMessage("Invalid number of nodes")
160             .that(nodes)
161             .hasSize(2);
162         final int tokenType = ((AbstractNode) nodes.get(0)).getTokenType();
163         assertWithMessage("Invalid token type")
164             .that(tokenType)
165             .isEqualTo(TokenTypes.STRING_LITERAL);
166     }
167 
168     @Test
169     public void testGetNodeByValueWithSameTokenText() throws Exception {
170         final String xPath = "//MODIFIERS[@text = 'MODIFIERS']";
171         final List<NodeInfo> nodes = getXpathItems(xPath, rootNode);
172         assertWithMessage("Invalid number of nodes")
173             .that(nodes)
174             .hasSize(0);
175     }
176 
177     @Test
178     public void testGetAttributeValue() {
179         final DetailAstImpl detailAST = new DetailAstImpl();
180         detailAST.setType(TokenTypes.IDENT);
181         detailAST.setText("HelloWorld");
182 
183         final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST, 1, 0);
184 
185         assertWithMessage("Invalid text attribute")
186             .that(elementNode.getAttributeValue((NamespaceUri) null, "text"))
187             .isEqualTo("HelloWorld");
188     }
189 
190     @Test
191     public void testGetAttributeCached() {
192         final DetailAstImpl detailAST = new DetailAstImpl();
193         detailAST.setType(TokenTypes.IDENT);
194         detailAST.setText("HelloWorld");
195 
196         final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST, 1, 0);
197         try (AxisIterator first = elementNode.iterateAxis(AxisInfo.ATTRIBUTE);
198              AxisIterator second = elementNode.iterateAxis(AxisInfo.ATTRIBUTE)) {
199             assertWithMessage("Expected same attribute node")
200                 .that(second.next())
201                 .isSameInstanceAs(first.next());
202         }
203     }
204 
205     @Test
206     public void testGetAttributeValueNoAttribute() {
207         final DetailAstImpl detailAST = new DetailAstImpl();
208         detailAST.setType(TokenTypes.CLASS_DEF);
209         detailAST.setText("HelloWorld");
210 
211         final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST, 1, 0);
212 
213         assertWithMessage("Must be null")
214             .that(elementNode.getAttributeValue((NamespaceUri) null, "text"))
215             .isNull();
216     }
217 
218     @Test
219     public void testGetAttributeValueWrongAttribute() {
220         final DetailAstImpl detailAST = new DetailAstImpl();
221         detailAST.setType(TokenTypes.IDENT);
222         detailAST.setText("HelloWorld");
223 
224         final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST, 1, 0);
225 
226         assertWithMessage("Must be null")
227             .that(elementNode.getAttributeValue((NamespaceUri) null, "somename"))
228             .isNull();
229     }
230 
231     @Test
232     public void testIterateAxisEmptyChildren() {
233         final DetailAstImpl detailAST = new DetailAstImpl();
234         detailAST.setType(TokenTypes.METHOD_DEF);
235         final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST, 1, 0);
236         try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.CHILD)) {
237             assertWithMessage("Invalid iterator")
238                     .that(iterator)
239                     .isInstanceOf(EmptyIterator.class);
240         }
241         try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.DESCENDANT)) {
242             assertWithMessage("Invalid iterator")
243                     .that(iterator)
244                     .isInstanceOf(EmptyIterator.class);
245         }
246     }
247 
248     @Test
249     public void testIterateAxisWithChildren() {
250         final DetailAstImpl detailAST = new DetailAstImpl();
251         detailAST.setType(TokenTypes.METHOD_DEF);
252         final DetailAstImpl childAst = new DetailAstImpl();
253         childAst.setType(TokenTypes.VARIABLE_DEF);
254         detailAST.addChild(childAst);
255         final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST, 1, 0);
256         try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.CHILD)) {
257             assertWithMessage("Invalid iterator")
258                     .that(iterator)
259                     .isInstanceOf(ArrayIterator.class);
260         }
261         try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.DESCENDANT)) {
262             assertWithMessage("Invalid iterator")
263                     .that(iterator)
264                     .isInstanceOf(DescendantIterator.class);
265         }
266     }
267 
268     @Test
269     public void testIterateAxisWithNoSiblings() {
270         final DetailAstImpl detailAST = new DetailAstImpl();
271         detailAST.setType(TokenTypes.VARIABLE_DEF);
272 
273         final DetailAstImpl parentAST = new DetailAstImpl();
274         parentAST.setFirstChild(detailAST);
275         parentAST.setType(TokenTypes.METHOD_DEF);
276         final AbstractNode parentNode = new ElementNode(rootNode, rootNode, parentAST, 1, 0);
277 
278         final AbstractNode elementNode = parentNode.getChildren().get(0);
279         try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.FOLLOWING_SIBLING)) {
280             assertWithMessage("Invalid iterator")
281                     .that(iterator)
282                     .isInstanceOf(EmptyIterator.class);
283         }
284         try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.PRECEDING_SIBLING)) {
285             assertWithMessage("Invalid iterator")
286                     .that(iterator)
287                     .isInstanceOf(EmptyIterator.class);
288         }
289     }
290 }