1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package test.net.sourceforge.pmd.ast;
5   
6   import static org.junit.Assert.assertEquals;
7   import static org.junit.Assert.assertFalse;
8   import static org.junit.Assert.assertNotNull;
9   import static org.junit.Assert.assertTrue;
10  import net.sourceforge.pmd.PMD;
11  import net.sourceforge.pmd.ast.ASTAssignmentOperator;
12  import net.sourceforge.pmd.ast.ASTBlock;
13  import net.sourceforge.pmd.ast.ASTBlockStatement;
14  import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
15  import net.sourceforge.pmd.ast.ASTCompilationUnit;
16  import net.sourceforge.pmd.ast.ASTExpression;
17  import net.sourceforge.pmd.ast.ASTExtendsList;
18  import net.sourceforge.pmd.ast.ASTFieldDeclaration;
19  import net.sourceforge.pmd.ast.ASTImplementsList;
20  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
21  import net.sourceforge.pmd.ast.ASTName;
22  import net.sourceforge.pmd.ast.ASTReturnStatement;
23  import net.sourceforge.pmd.ast.ASTStatement;
24  import net.sourceforge.pmd.ast.ASTVariableInitializer;
25  import net.sourceforge.pmd.ast.Node;
26  import net.sourceforge.pmd.ast.SimpleNode;
27  
28  import org.junit.Ignore;
29  import org.junit.Test;
30  
31  import test.net.sourceforge.pmd.testframework.ParserTst;
32  
33  import java.util.ArrayList;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Set;
37  
38  public class SimpleNodeTest extends ParserTst {
39  
40      @Test
41      public void testMethodDiffLines() throws Throwable {
42          Set methods = getNodes(ASTMethodDeclaration.class, METHOD_DIFF_LINES);
43          Iterator iter = methods.iterator();
44          verifyNode((SimpleNode) iter.next(), 2, 9, 4, 2);
45      }
46  
47      @Test
48      public void testMethodSameLine() throws Throwable {
49          Set methods = getNodes(ASTMethodDeclaration.class, METHOD_SAME_LINE);
50          verifyNode((SimpleNode) methods.iterator().next(), 2, 9, 2, 21);
51      }
52  
53      @Test
54      public void testNoLookahead() throws Throwable {
55          String code = NO_LOOKAHEAD; // 1, 8 -> 1, 20
56          Set uCD = getNodes(ASTClassOrInterfaceDeclaration.class, code);
57          verifyNode((SimpleNode) uCD.iterator().next(), 1, 8, 1, 20);
58      }
59  
60      @Test
61      public void testHasExplicitExtends() throws Throwable {
62          String code = HAS_EXPLICIT_EXTENDS;
63          ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next();
64          assertTrue(ucd.jjtGetChild(0) instanceof ASTExtendsList);
65      }
66  
67      @Test
68      public void testNoExplicitExtends() throws Throwable {
69          String code = NO_EXPLICIT_EXTENDS;
70          ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next();
71          assertFalse(ucd.jjtGetChild(0) instanceof ASTExtendsList);
72      }
73  
74      @Test
75      public void testHasExplicitImplements() throws Throwable {
76          String code = HAS_EXPLICIT_IMPLEMENTS;
77          ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next();
78          assertTrue(ucd.jjtGetChild(0) instanceof ASTImplementsList);
79      }
80  
81      @Test
82      public void testNoExplicitImplements() throws Throwable {
83          String code = NO_EXPLICIT_IMPLEMENTS;
84          ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next();
85          assertFalse(ucd.jjtGetChild(0) instanceof ASTImplementsList);
86      }
87  
88      @Test
89      public void testColumnsOnQualifiedName() throws Throwable {
90          Set name = getNodes(ASTName.class, QUALIFIED_NAME);
91          Iterator i = name.iterator();
92          while (i.hasNext()) {
93              SimpleNode node = (SimpleNode) i.next();
94              if (node.getImage().equals("java.io.File")) {
95                  verifyNode(node, 1, 8, 1, 19);
96              }
97          }
98      }
99  
100     @Test
101     public void testLineNumbersForNameSplitOverTwoLines() throws Throwable {
102         Set name = getNodes(ASTName.class, BROKEN_LINE_IN_NAME);
103         Iterator i = name.iterator();
104         while (i.hasNext()) {
105             SimpleNode node = (SimpleNode) i.next();
106             if (node.getImage().equals("java.io.File")) {
107                 verifyNode(node, 1, 8, 2, 4);
108             }
109             if (node.getImage().equals("Foo")) {
110                 verifyNode(node, 2, 15, 2, 18);
111             }
112         }
113     }
114 
115     @Test
116     public void testLineNumbersAreSetOnAllSiblings() throws Throwable {
117         Set blocks = getNodes(ASTBlock.class, LINE_NUMBERS_ON_SIBLINGS);
118         Iterator i = blocks.iterator();
119         while (i.hasNext()) {
120             ASTBlock b = (ASTBlock) i.next();
121             assertTrue(b.getBeginLine() > 0);
122         }
123         blocks = getNodes(ASTVariableInitializer.class, LINE_NUMBERS_ON_SIBLINGS);
124         i = blocks.iterator();
125         while (i.hasNext()) {
126             ASTVariableInitializer b = (ASTVariableInitializer) i.next();
127             assertTrue(b.getBeginLine() > 0);
128         }
129         blocks = getNodes(ASTExpression.class, LINE_NUMBERS_ON_SIBLINGS);
130         i = blocks.iterator();
131         while (i.hasNext()) {
132             ASTExpression b = (ASTExpression) i.next();
133             assertTrue(b.getBeginLine() > 0);
134         }
135     }
136 
137     @Test
138     public void testFindChildrenOfType() {
139         ASTBlock block = new ASTBlock(2);
140         block.jjtAddChild(new ASTReturnStatement(1), 0);
141         assertEquals(1, block.findChildrenOfType(ASTReturnStatement.class).size());
142     }
143 
144     @Test
145     public void testFindChildrenOfTypeMultiple() {
146         ASTBlock block = new ASTBlock(1);
147         block.jjtAddChild(new ASTBlockStatement(2), 0);
148         block.jjtAddChild(new ASTBlockStatement(3), 1);
149         List<ASTBlockStatement> nodes = new ArrayList<ASTBlockStatement>();
150         block.findChildrenOfType(ASTBlockStatement.class, nodes);
151         assertEquals(2, nodes.size());
152     }
153 
154     @Test
155     public void testFindChildrenOfTypeRecurse() {
156         ASTBlock block = new ASTBlock(1);
157         ASTBlock childBlock = new ASTBlock(2);
158         block.jjtAddChild(childBlock, 0);
159         childBlock.jjtAddChild(new ASTMethodDeclaration(3), 0);
160         List<ASTMethodDeclaration> nodes = new ArrayList<ASTMethodDeclaration>();
161         block.findChildrenOfType(ASTMethodDeclaration.class, nodes);
162         assertEquals(1, nodes.size());
163     }
164 
165     @Test
166     public void testGetFirstChild() {
167         ASTBlock block = new ASTBlock(1);
168         ASTStatement x = new ASTStatement(2);
169         block.jjtAddChild(x, 0);
170         block.jjtAddChild(new ASTStatement(3), 1);
171 
172         Node n = block.getFirstChildOfType(ASTStatement.class);
173         assertNotNull(n);
174         assertTrue(n instanceof ASTStatement);
175         assertEquals(x, n);
176     }
177 
178     @Test
179     public void testGetFirstChildNested() {
180         ASTBlock block = new ASTBlock(1);
181         ASTStatement x = new ASTStatement(2);
182         ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
183         x.jjtAddChild(x1, 1);
184         block.jjtAddChild(x, 0);
185         block.jjtAddChild(new ASTStatement(3), 1);
186 
187         Node n = block.getFirstChildOfType(ASTAssignmentOperator.class);
188         assertNotNull(n);
189         assertTrue(n instanceof ASTAssignmentOperator);
190         assertEquals(x1, n);
191     }
192 
193     @Test
194     public void testGetFirstChildNestedDeeper() {
195         ASTBlock block = new ASTBlock(1);
196         ASTStatement x = new ASTStatement(2);
197         ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
198         ASTName x2 = new ASTName(5);
199 
200         x.jjtAddChild(x1, 1);
201         x1.jjtAddChild(x2, 0);
202         block.jjtAddChild(x, 0);
203         block.jjtAddChild(new ASTStatement(3), 1);
204 
205         Node n = block.getFirstChildOfType(ASTName.class);
206         assertNotNull(n);
207         assertTrue(n instanceof ASTName);
208         assertEquals(x2, n);
209     }
210 
211     @Ignore
212     @Test
213     public void testContainsNoInner() throws Throwable {
214         ASTCompilationUnit c = getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER).iterator().next();
215         List<ASTFieldDeclaration> res = new ArrayList<ASTFieldDeclaration>();
216         c.findChildrenOfType(ASTFieldDeclaration.class, res, false);
217         assertTrue(res.isEmpty());
218 /*        String expectedXml = "<CompilationUnit BeginColumn=\"1\" BeginLine=\"5\" EndColumn=\"1\" EndLine=\"5\">" +
219                 "<TypeDeclaration BeginColumn=\"1\" BeginLine=\"1\" EndColumn=\"1\" EndLine=\"5\">" +
220                 "<ClassOrInterfaceDeclaration Abstract=\"false\" BeginColumn=\"8\" BeginLine=\"1\" EndColumn=\"1\" " +
221                 "EndLine=\"5\" Final=\"false\" Image=\"Test\" Interface=\"false\" Native=\"false\" Nested=\"false\" PackagePrivate=\"false\" Private=\"false\" Protected=\"false\" Public=\"true\" Static=\"false\" Strictfp=\"false\" Synchronized=\"false\" Transient=\"false\" Volatile=\"false\">" +
222                 "<ClassOrInterfaceBody BeginColumn=\"19\" BeginLine=\"1\" EndColumn=\"1\" EndLine=\"5\">" +
223                 "<ClassOrInterfaceBodyDeclaration AnonymousInnerClass=\"false\" BeginColumn=\"3\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\">" +
224                 "<ClassOrInterfaceDeclaration Abstract=\"false\" BeginColumn=\"10\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\" Final=\"false\" " +
225                 "Image=\"Inner\" Interface=\"false\" Native=\"false\" Nested=\"true\" PackagePrivate=\"false\" Private=\"false\" Protected=\"false\" " +
226                 "Public=\"true\" Static=\"false\" Strictfp=\"false\" Synchronized=\"false\" Transient=\"false\" Volatile=\"false\">" +
227                 "<ClassOrInterfaceBody BeginColumn=\"22\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\">" +
228                 "<ClassOrInterfaceBodyDeclaration AnonymousInnerClass=\"false\" BeginColumn=\"4\" BeginLine=\"3\" EndColumn=\"11\" EndLine=\"3\">" +
229                 "<FieldDeclaration Abstract=\"false\" Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"4\" BeginLine=\"3\" EndColumn=\"11\" EndLine=\"3\" Final=\"false\" Native=\"false\" PackagePrivate=\"true\" Private=\"false\" Protected=\"false\" Public=\"false\" Static=\"false\" Strictfp=\"false\" Synchronized=\"false\" Transient=\"false\" VariableName=\"foo\" Volatile=\"false\"><Type Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"4\" BeginLine=\"3\" EndColumn=\"6\" EndLine=\"3\">" +
230                 "<PrimitiveType Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"4\" BeginLine=\"3\" Boolean=\"false\" EndColumn=\"6\" EndLine=\"3\" Image=\"int\"/>" +
231                 "</Type>" +
232                 "<VariableDeclarator BeginColumn=\"8\" BeginLine=\"3\" EndColumn=\"10\" EndLine=\"3\">" +
233                 "<VariableDeclaratorId Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"8\" BeginLine=\"3\" EndColumn=\"10\" EndLine=\"3\" ExceptionBlockParameter=\"false\" Image=\"foo\"/>" +
234                 "</VariableDeclarator></FieldDeclaration></ClassOrInterfaceBodyDeclaration></ClassOrInterfaceBody>" +
235                 "</ClassOrInterfaceDeclaration></ClassOrInterfaceBodyDeclaration></ClassOrInterfaceBody></ClassOrInterfaceDeclaration>" +
236                 "</TypeDeclaration></CompilationUnit>";
237         assertEquals( expectedXml, getXmlString( c ) );
238 */    }
239 
240     @Test
241     public void testContainsNoInnerWithAnonInner() throws Throwable {
242         ASTCompilationUnit c = getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER_WITH_ANON_INNER).iterator().next();
243         List<ASTFieldDeclaration> res = new ArrayList<ASTFieldDeclaration>();
244         c.findChildrenOfType(ASTFieldDeclaration.class, res, false);
245         assertTrue(res.isEmpty());
246     }
247 
248     @Test
249     public void testContainsChildOfType() throws Throwable {
250         ASTClassOrInterfaceDeclaration c = getNodes(ASTClassOrInterfaceDeclaration.class, CONTAINS_CHILDREN_OF_TYPE).iterator().next();
251         assertTrue(c.containsChildOfType(ASTFieldDeclaration.class));
252     }
253 
254     @Test
255     public void testXPathNodeSelect() throws Throwable {
256         ASTClassOrInterfaceDeclaration c = getNodes(ASTClassOrInterfaceDeclaration.class, TEST_XPATH).iterator().next();
257         List nodes = c.findChildNodesWithXPath("//FieldDeclaration");
258         assertEquals(2, nodes.size());
259         assertTrue(nodes.get(0) instanceof ASTFieldDeclaration);
260     }
261 
262     private void verifyNode(SimpleNode node, int beginLine, int beginCol, int endLine, int endCol) {
263         assertEquals("Unexpected beginning line: ", beginLine, node.getBeginLine());
264         assertEquals("Unexpected beginning column: ", beginCol, node.getBeginColumn());
265         assertEquals("Unexpected ending line:", endLine, node.getEndLine());
266         assertEquals("Unexpected ending column:", endCol, node.getEndColumn());
267     }
268 
269     private static final String HAS_EXPLICIT_EXTENDS =
270             "public class Test extends Foo {}";
271 
272     private static final String NO_EXPLICIT_EXTENDS =
273             "public class Test {}";
274 
275     private static final String HAS_EXPLICIT_IMPLEMENTS =
276             "public class Test implements Foo {}";
277 
278     private static final String NO_EXPLICIT_IMPLEMENTS =
279             "public class Test {}";
280 
281     private static final String METHOD_SAME_LINE =
282             "public class Test {" + PMD.EOL +
283             " public void foo() {}" + PMD.EOL +
284             "}";
285 
286     private static final String QUALIFIED_NAME =
287             "import java.io.File;" + PMD.EOL +
288             "public class Foo{}";
289 
290     private static final String BROKEN_LINE_IN_NAME =
291             "import java.io." + PMD.EOL +
292             "File;" + PMD.EOL +
293             "public class Foo{}";
294 
295     private static final String LINE_NUMBERS_ON_SIBLINGS =
296             "public class Foo {" + PMD.EOL +
297             " void bar() {" + PMD.EOL +
298             "  try {" + PMD.EOL +
299             "  } catch (Exception1 e) {" + PMD.EOL +
300             "   int x =2;" + PMD.EOL +
301             "  }" + PMD.EOL +
302             " if (x != null) {}" + PMD.EOL +
303             " }" + PMD.EOL +
304             "}";
305 
306     private static final String NO_LOOKAHEAD = "public class Foo { }";
307 
308     private static final String METHOD_DIFF_LINES =
309             "public class Test {" + PMD.EOL +
310             " public void foo() {" + PMD.EOL +
311             "  int x;" + PMD.EOL +
312             " }" + PMD.EOL +
313             "}";
314 
315     private static final String CONTAINS_CHILDREN_OF_TYPE =
316             "public class Test {" + PMD.EOL +
317             "  int x;" + PMD.EOL +
318             "}";
319 
320     private static final String CONTAINS_NO_INNER =
321             "public class Test {" + PMD.EOL +
322             "  public class Inner {" + PMD.EOL +
323             "   int foo;" + PMD.EOL +
324             "  }" + PMD.EOL +
325             "}";
326 
327     private static final String CONTAINS_NO_INNER_WITH_ANON_INNER =
328             "public class Test {" + PMD.EOL +
329             "  void bar() {" + PMD.EOL +
330             "   foo(new Fuz() { int x = 2;});" + PMD.EOL +
331             "  }" + PMD.EOL +
332             "}";
333 
334     private static final String TEST_XPATH =
335             "public class Test {" + PMD.EOL +
336             "  int x = 2;" + PMD.EOL +
337             "  int y = 42;" + PMD.EOL +
338             "}";
339 
340     public static junit.framework.Test suite() {
341         return new junit.framework.JUnit4TestAdapter(SimpleNodeTest.class);
342     }
343 }