/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.ast; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import org.jaxen.JaxenException; import org.junit.Ignore; import org.junit.Test; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ParserTst; public class SimpleNodeTest extends ParserTst { @Test public void testMethodDiffLines() { Set<ASTMethodDeclaration> methods = getNodes(ASTMethodDeclaration.class, METHOD_DIFF_LINES); verifyNode(methods.iterator().next(), 2, 9, 4, 2); } @Test public void testMethodSameLine() { Set<ASTMethodDeclaration> methods = getNodes(ASTMethodDeclaration.class, METHOD_SAME_LINE); verifyNode(methods.iterator().next(), 2, 9, 2, 21); } @Test public void testNoLookahead() { String code = NO_LOOKAHEAD; // 1, 8 -> 1, 20 Set<ASTClassOrInterfaceDeclaration> uCD = getNodes(ASTClassOrInterfaceDeclaration.class, code); verifyNode(uCD.iterator().next(), 1, 8, 1, 20); } @Test public void testHasExplicitExtends() { String code = HAS_EXPLICIT_EXTENDS; ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next(); assertTrue(ucd.jjtGetChild(0) instanceof ASTExtendsList); } @Test public void testNoExplicitExtends() { String code = NO_EXPLICIT_EXTENDS; ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next(); assertFalse(ucd.jjtGetChild(0) instanceof ASTExtendsList); } @Test public void testHasExplicitImplements() { String code = HAS_EXPLICIT_IMPLEMENTS; ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next(); assertTrue(ucd.jjtGetChild(0) instanceof ASTImplementsList); } @Test public void testNoExplicitImplements() { String code = NO_EXPLICIT_IMPLEMENTS; ASTClassOrInterfaceDeclaration ucd = getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next(); assertFalse(ucd.jjtGetChild(0) instanceof ASTImplementsList); } @Test public void testColumnsOnQualifiedName() { Set<ASTName> name = getNodes(ASTName.class, QUALIFIED_NAME); Iterator<ASTName> i = name.iterator(); while (i.hasNext()) { Node node = i.next(); if (node.getImage().equals("java.io.File")) { verifyNode(node, 1, 8, 1, 19); } } } @Test public void testLineNumbersForNameSplitOverTwoLines() { Set<ASTName> name = getNodes(ASTName.class, BROKEN_LINE_IN_NAME); Iterator<ASTName> i = name.iterator(); while (i.hasNext()) { Node node = i.next(); if (node.getImage().equals("java.io.File")) { verifyNode(node, 1, 8, 2, 4); } if (node.getImage().equals("Foo")) { verifyNode(node, 2, 15, 2, 18); } } } @Test public void testLineNumbersAreSetOnAllSiblings() { for (ASTBlock b : getNodes(ASTBlock.class, LINE_NUMBERS_ON_SIBLINGS)) { assertTrue(b.getBeginLine() > 0); } for (ASTVariableInitializer b : getNodes(ASTVariableInitializer.class, LINE_NUMBERS_ON_SIBLINGS)) { assertTrue(b.getBeginLine() > 0); } for (ASTExpression b : getNodes(ASTExpression.class, LINE_NUMBERS_ON_SIBLINGS)) { assertTrue(b.getBeginLine() > 0); } } @Test public void testFindDescendantsOfType() { ASTBlock block = new ASTBlock(2); block.jjtAddChild(new ASTReturnStatement(1), 0); assertEquals(1, block.findDescendantsOfType(ASTReturnStatement.class).size()); } @Test public void testFindDescendantsOfTypeMultiple() { ASTBlock block = new ASTBlock(1); block.jjtAddChild(new ASTBlockStatement(2), 0); block.jjtAddChild(new ASTBlockStatement(3), 1); List<ASTBlockStatement> nodes = block.findDescendantsOfType(ASTBlockStatement.class); assertEquals(2, nodes.size()); } @Test public void testFindDescendantsOfTypeRecurse() { ASTBlock block = new ASTBlock(1); ASTBlock childBlock = new ASTBlock(2); block.jjtAddChild(childBlock, 0); childBlock.jjtAddChild(new ASTMethodDeclaration(3), 0); List<ASTMethodDeclaration> nodes = block.findDescendantsOfType(ASTMethodDeclaration.class); assertEquals(1, nodes.size()); } @Test public void testGetFirstChild() { ASTBlock block = new ASTBlock(1); ASTStatement x = new ASTStatement(2); block.jjtAddChild(x, 0); block.jjtAddChild(new ASTStatement(3), 1); Node n = block.getFirstDescendantOfType(ASTStatement.class); assertNotNull(n); assertTrue(n instanceof ASTStatement); assertEquals(x, n); } @Test public void testGetFirstChildNested() { ASTBlock block = new ASTBlock(1); ASTStatement x = new ASTStatement(2); ASTAssignmentOperator x1 = new ASTAssignmentOperator(4); x.jjtAddChild(x1, 0); block.jjtAddChild(x, 0); block.jjtAddChild(new ASTStatement(3), 1); Node n = block.getFirstDescendantOfType(ASTAssignmentOperator.class); assertNotNull(n); assertTrue(n instanceof ASTAssignmentOperator); assertEquals(x1, n); } @Test public void testGetFirstChildNestedDeeper() { ASTBlock block = new ASTBlock(1); ASTStatement x = new ASTStatement(2); ASTAssignmentOperator x1 = new ASTAssignmentOperator(4); ASTName x2 = new ASTName(5); x.jjtAddChild(x1, 0); x1.jjtAddChild(x2, 0); block.jjtAddChild(x, 0); block.jjtAddChild(new ASTStatement(3), 1); Node n = block.getFirstDescendantOfType(ASTName.class); assertNotNull(n); assertTrue(n instanceof ASTName); assertEquals(x2, n); } @Test public void testParentMethods() { ASTCompilationUnit u = parseJava14(TEST1); ASTMethodDeclarator d = u.getFirstDescendantOfType(ASTMethodDeclarator.class); assertSame("getFirstParentOfType ASTMethodDeclaration", d.jjtGetParent(), d.getFirstParentOfType(ASTMethodDeclaration.class)); assertNull("getFirstParentOfType ASTName", d.getFirstParentOfType(ASTName.class)); assertSame("getNthParent 1", d.jjtGetParent(), d.getNthParent(1)); assertSame("getNthParent 2", d.jjtGetParent().jjtGetParent(), d.getNthParent(2)); assertSame("getNthParent 6", u, d.getNthParent(6)); assertNull("getNthParent 7", d.getNthParent(7)); assertNull("getNthParent 8", d.getNthParent(8)); } private static final String TEST1 = "public class Test {" + PMD.EOL + " void bar(String s) {" + PMD.EOL + " s = s.toLowerCase();" + PMD.EOL + " }" + PMD.EOL + "}"; @Ignore @Test public void testContainsNoInner() { ASTCompilationUnit c = getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER).iterator().next(); List<ASTFieldDeclaration> res = new ArrayList<>(); c.findDescendantsOfType(ASTFieldDeclaration.class, res, false); assertTrue(res.isEmpty()); /* * String expectedXml = * "<CompilationUnit BeginColumn=\"1\" BeginLine=\"5\" EndColumn=\"1\" EndLine=\"5\">" * + * "<TypeDeclaration BeginColumn=\"1\" BeginLine=\"1\" EndColumn=\"1\" EndLine=\"5\">" * + * "<ClassOrInterfaceDeclaration Abstract=\"false\" BeginColumn=\"8\" BeginLine=\"1\" EndColumn=\"1\" " * + * "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\">" * + * "<ClassOrInterfaceBody BeginColumn=\"19\" BeginLine=\"1\" EndColumn=\"1\" EndLine=\"5\">" * + * "<ClassOrInterfaceBodyDeclaration AnonymousInnerClass=\"false\" BeginColumn=\"3\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\">" * + * "<ClassOrInterfaceDeclaration Abstract=\"false\" BeginColumn=\"10\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\" Final=\"false\" " * + * "Image=\"Inner\" Interface=\"false\" Native=\"false\" Nested=\"true\" PackagePrivate=\"false\" Private=\"false\" Protected=\"false\" " * + * "Public=\"true\" Static=\"false\" Strictfp=\"false\" Synchronized=\"false\" Transient=\"false\" Volatile=\"false\">" * + * "<ClassOrInterfaceBody BeginColumn=\"22\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\">" * + * "<ClassOrInterfaceBodyDeclaration AnonymousInnerClass=\"false\" BeginColumn=\"4\" BeginLine=\"3\" EndColumn=\"11\" EndLine=\"3\">" * + * "<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\">" * + * "<PrimitiveType Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"4\" BeginLine=\"3\" Boolean=\"false\" EndColumn=\"6\" EndLine=\"3\" Image=\"int\"/>" * + "</Type>" + * "<VariableDeclarator BeginColumn=\"8\" BeginLine=\"3\" EndColumn=\"10\" EndLine=\"3\">" * + * "<VariableDeclaratorId Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"8\" BeginLine=\"3\" EndColumn=\"10\" EndLine=\"3\" ExceptionBlockParameter=\"false\" Image=\"foo\"/>" * + * "</VariableDeclarator></FieldDeclaration></ClassOrInterfaceBodyDeclaration></ClassOrInterfaceBody>" * + * "</ClassOrInterfaceDeclaration></ClassOrInterfaceBodyDeclaration></ClassOrInterfaceBody></ClassOrInterfaceDeclaration>" * + "</TypeDeclaration></CompilationUnit>"; assertEquals( expectedXml, * getXmlString( c ) ); */ } @Test public void testContainsNoInnerWithAnonInner() { ASTCompilationUnit c = getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER_WITH_ANON_INNER).iterator().next(); List<ASTFieldDeclaration> res = new ArrayList<>(); c.findDescendantsOfType(ASTFieldDeclaration.class, res, false); assertTrue(res.isEmpty()); } @Test public void testContainsChildOfType() { ASTClassOrInterfaceDeclaration c = getNodes(ASTClassOrInterfaceDeclaration.class, CONTAINS_CHILDREN_OF_TYPE) .iterator().next(); assertTrue(c.hasDescendantOfType(ASTFieldDeclaration.class)); } @Test public void testXPathNodeSelect() throws JaxenException { ASTClassOrInterfaceDeclaration c = getNodes(ASTClassOrInterfaceDeclaration.class, TEST_XPATH).iterator().next(); List<Node> nodes = c.findChildNodesWithXPath("//FieldDeclaration"); assertEquals(2, nodes.size()); assertTrue(nodes.get(0) instanceof ASTFieldDeclaration); assertTrue(c.hasDescendantMatchingXPath("//FieldDeclaration")); assertFalse(c.hasDescendantMatchingXPath("//MethodDeclaration")); } @Test public void testUserData() { ASTClassOrInterfaceDeclaration c = getNodes(ASTClassOrInterfaceDeclaration.class, HAS_EXPLICIT_EXTENDS) .iterator().next(); assertNull(c.getUserData()); c.setUserData("foo"); assertEquals("foo", c.getUserData()); c.setUserData(null); assertNull(c.getUserData()); } private void verifyNode(Node node, int beginLine, int beginCol, int endLine, int endCol) { assertEquals("Unexpected beginning line: ", beginLine, node.getBeginLine()); assertEquals("Unexpected beginning column: ", beginCol, node.getBeginColumn()); assertEquals("Unexpected ending line:", endLine, node.getEndLine()); assertEquals("Unexpected ending column:", endCol, node.getEndColumn()); } private static final String HAS_EXPLICIT_EXTENDS = "public class Test extends Foo {}"; private static final String NO_EXPLICIT_EXTENDS = "public class Test {}"; private static final String HAS_EXPLICIT_IMPLEMENTS = "public class Test implements Foo {}"; private static final String NO_EXPLICIT_IMPLEMENTS = "public class Test {}"; private static final String METHOD_SAME_LINE = "public class Test {" + PMD.EOL + " public void foo() {}" + PMD.EOL + "}"; private static final String QUALIFIED_NAME = "import java.io.File;" + PMD.EOL + "public class Foo{}"; private static final String BROKEN_LINE_IN_NAME = "import java.io." + PMD.EOL + "File;" + PMD.EOL + "public class Foo{}"; private static final String LINE_NUMBERS_ON_SIBLINGS = "public class Foo {" + PMD.EOL + " void bar() {" + PMD.EOL + " try {" + PMD.EOL + " } catch (Exception1 e) {" + PMD.EOL + " int x =2;" + PMD.EOL + " }" + PMD.EOL + " if (x != null) {}" + PMD.EOL + " }" + PMD.EOL + "}"; private static final String NO_LOOKAHEAD = "public class Foo { }"; private static final String METHOD_DIFF_LINES = "public class Test {" + PMD.EOL + " public void foo() {" + PMD.EOL + " int x;" + PMD.EOL + " }" + PMD.EOL + "}"; private static final String CONTAINS_CHILDREN_OF_TYPE = "public class Test {" + PMD.EOL + " int x;" + PMD.EOL + "}"; private static final String CONTAINS_NO_INNER = "public class Test {" + PMD.EOL + " public class Inner {" + PMD.EOL + " int foo;" + PMD.EOL + " }" + PMD.EOL + "}"; private static final String CONTAINS_NO_INNER_WITH_ANON_INNER = "public class Test {" + PMD.EOL + " void bar() {" + PMD.EOL + " foo(new Fuz() { int x = 2;});" + PMD.EOL + " }" + PMD.EOL + "}"; private static final String TEST_XPATH = "public class Test {" + PMD.EOL + " int x = 2;" + PMD.EOL + " int y = 42;" + PMD.EOL + "}"; }