blob: 3201b2910d028f5fe73ff5180c757d4672904ff6 [file] [log] [blame]
/*
* Copyright (C) 2007-2010 JĂșlio Vilmar Gesser.
* Copyright (C) 2011, 2013-2016 The JavaParser Team.
*
* This file is part of JavaParser.
*
* JavaParser can be used either under the terms of
* a) the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* b) the terms of the Apache License
*
* You should have received a copy of both licenses in LICENCE.LGPL and
* LICENCE.APACHE. Please refer to those files for details.
*
* JavaParser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package com.github.javaparser.ast;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.comments.BlockComment;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.IntegerLiteralExpr;
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.ast.observer.AstObserver;
import com.github.javaparser.ast.observer.AstObserverAdapter;
import com.github.javaparser.ast.observer.ObservableProperty;
import com.github.javaparser.ast.type.PrimitiveType;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import static com.github.javaparser.JavaParser.parse;
import static com.github.javaparser.JavaParser.parseExpression;
import static com.github.javaparser.utils.Utils.EOL;
import static org.junit.Assert.*;
public class NodeTest {
@Test
public void registerSubTree() {
String code = "class A { int f; void foo(int p) { return 'z'; }}";
CompilationUnit cu = parse(code);
List<String> changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {
@Override
public void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {
changes.add(String.format("%s.%s changed from %s to %s", observedNode.getClass().getSimpleName(), property.name().toLowerCase(), oldValue, newValue));
}
};
cu.registerForSubtree(observer);
assertEquals(Arrays.asList(), changes);
cu.getClassByName("A").get().setName("MyCoolClass");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);
cu.getClassByName("MyCoolClass").get().getFieldByName("f").get().getVariable(0).setType(new PrimitiveType(PrimitiveType.Primitive.BOOLEAN));
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean"), changes);
cu.getClassByName("MyCoolClass").get().getMethodsByName("foo").get(0).getParameterByName("p").get().setName("myParam");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean",
"Parameter.name changed from p to myParam"), changes);
}
@Test
public void registerWithJustNodeMode() {
String code = "class A { int f; void foo(int p) { return 'z'; }}";
CompilationUnit cu = parse(code);
List<String> changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {
@Override
public void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {
changes.add(String.format("%s.%s changed from %s to %s", observedNode.getClass().getSimpleName(), property.name().toLowerCase(), oldValue, newValue));
}
};
cu.getClassByName("A").get().register(observer, Node.ObserverRegistrationMode.JUST_THIS_NODE);
assertEquals(Arrays.asList(), changes);
cu.getClassByName("A").get().setName("MyCoolClass");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);
cu.getClassByName("MyCoolClass").get().getFieldByName("f").get().getVariable(0).setType(new PrimitiveType(PrimitiveType.Primitive.BOOLEAN));
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);
cu.getClassByName("MyCoolClass").get().getMethodsByName("foo").get(0).getParameterByName("p").get().setName("myParam");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);
cu.getClassByName("MyCoolClass").get().addField("int", "bar").getVariables().get(0).setInitializer("0");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);
}
@Test
public void registerWithNodeAndExistingDescendantsMode() {
String code = "class A { int f; void foo(int p) { return 'z'; }}";
CompilationUnit cu = parse(code);
List<String> changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {
@Override
public void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {
changes.add(String.format("%s.%s changed from %s to %s", observedNode.getClass().getSimpleName(), property.name().toLowerCase(), oldValue, newValue));
}
};
cu.getClassByName("A").get().register(observer, Node.ObserverRegistrationMode.THIS_NODE_AND_EXISTING_DESCENDANTS);
assertEquals(Arrays.asList(), changes);
cu.getClassByName("A").get().setName("MyCoolClass");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);
cu.getClassByName("MyCoolClass").get().getFieldByName("f").get().getVariable(0).setType(new PrimitiveType(PrimitiveType.Primitive.BOOLEAN));
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean"), changes);
cu.getClassByName("MyCoolClass").get().getMethodsByName("foo").get(0).getParameterByName("p").get().setName("myParam");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean",
"Parameter.name changed from p to myParam"), changes);
cu.getClassByName("MyCoolClass").get().addField("int", "bar").getVariables().get(0).setInitializer("0");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean",
"Parameter.name changed from p to myParam"), changes);
}
@Test
public void registerWithSelfPropagatingMode() {
String code = "class A { int f; void foo(int p) { return 'z'; }}";
CompilationUnit cu = parse(code);
List<String> changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {
@Override
public void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {
changes.add(String.format("%s.%s changed from %s to %s", observedNode.getClass().getSimpleName(), property.name().toLowerCase(), oldValue, newValue));
}
};
cu.getClassByName("A").get().register(observer, Node.ObserverRegistrationMode.SELF_PROPAGATING);
assertEquals(Arrays.asList(), changes);
cu.getClassByName("A").get().setName("MyCoolClass");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);
cu.getClassByName("MyCoolClass").get().getFieldByName("f").get().getVariable(0).setType(new PrimitiveType(PrimitiveType.Primitive.BOOLEAN));
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean"), changes);
cu.getClassByName("MyCoolClass").get().getMethodsByName("foo").get(0).getParameterByName("p").get().setName("myParam");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean",
"Parameter.name changed from p to myParam"), changes);
cu.getClassByName("MyCoolClass").get()
.addField("int", "bar")
.getVariables().get(0).setInitializer("0");
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass",
"FieldDeclaration.maximum_common_type changed from int to boolean",
"VariableDeclarator.type changed from int to boolean",
"Parameter.name changed from p to myParam",
"VariableDeclarator.initializer changed from null to 0"), changes);
}
@Test
public void deleteAParameterTriggerNotifications() {
String code = "class A { void foo(int p) { }}";
CompilationUnit cu = parse(code);
List<String> changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {
@Override
public void listChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {
changes.add("removing [" + nodeAddedOrRemoved + "] from index " + index);
}
};
cu.register(observer, Node.ObserverRegistrationMode.SELF_PROPAGATING);
cu.getClassByName("A").get().getMethodsByName("foo").get(0).getParameter(0).remove();
assertEquals(Arrays.asList("removing [int p] from index 0"), changes);
}
@Test
public void deleteClassNameDoesNotTriggerNotifications() {
String code = "class A { void foo(int p) { }}";
CompilationUnit cu = parse(code);
List<String> changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {
@Override
public void listChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {
changes.add("removing [" + nodeAddedOrRemoved + "] from index " + index);
}
};
cu.register(observer, Node.ObserverRegistrationMode.SELF_PROPAGATING);
// I cannot remove the name of a type
assertEquals(false, cu.getClassByName("A").get().getName().remove());
assertEquals(Arrays.asList(), changes);
}
@Test
public void deleteMethodBodyDoesTriggerNotifications() {
String code = "class A { void foo(int p) { }}";
CompilationUnit cu = parse(code);
List<String> changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {
@Override
public void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {
changes.add("setting [" + property + "] to " + newValue);
}
@Override
public void listChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {
changes.add("removing [" + nodeAddedOrRemoved + "] from index " + index);
}
};
cu.register(observer, Node.ObserverRegistrationMode.SELF_PROPAGATING);
assertEquals(true, cu.getClassByName("A").get().getMethodsByName("foo").get(0).getBody().get().remove());
assertEquals(Arrays.asList("setting [BODY] to null"), changes);
}
@Test
public void removeOrphanCommentPositiveCase() {
ClassOrInterfaceDeclaration decl = new ClassOrInterfaceDeclaration(EnumSet.noneOf(Modifier.class), false, "A");
Comment c = new LineComment("A comment");
decl.addOrphanComment(c);
assertEquals(1, decl.getOrphanComments().size());
assertTrue(decl == c.getParentNode().get());
assertTrue(decl.removeOrphanComment(c));
assertEquals(0, decl.getOrphanComments().size());
assertFalse(c.getParentNode().isPresent());
}
@Test
public void removeOrphanCommentNegativeCase() {
ClassOrInterfaceDeclaration aClass = new ClassOrInterfaceDeclaration(EnumSet.noneOf(Modifier.class), false, "A");
FieldDeclaration aField = new FieldDeclaration(EnumSet.noneOf(Modifier.class), new VariableDeclarator(PrimitiveType.intType(), "f"));
aClass.getMembers().add(aField);
Comment c = new LineComment("A comment");
aField.addOrphanComment(c);
// the comment is an orphan comment of the field, so trying to remove it on the class should not work
assertFalse(aClass.removeOrphanComment(c));
assertEquals(1, aField.getOrphanComments().size());
assertTrue(c.getParentNode().isPresent());
}
@Test
public void hasJavaDocCommentPositiveCaseWithSetJavaDocComment() {
ClassOrInterfaceDeclaration decl = new ClassOrInterfaceDeclaration(EnumSet.noneOf(Modifier.class),
false, "Foo");
decl.setJavadocComment("A comment");
assertEquals(true, decl.hasJavaDocComment());
}
@Test
public void hasJavaDocCommentPositiveCaseWithSetComment() {
ClassOrInterfaceDeclaration decl = new ClassOrInterfaceDeclaration(EnumSet.noneOf(Modifier.class),
false, "Foo");
decl.setComment(new JavadocComment("A comment"));
assertEquals(true, decl.hasJavaDocComment());
}
@Test
public void hasJavaDocCommentNegativeCaseNoComment() {
ClassOrInterfaceDeclaration decl = new ClassOrInterfaceDeclaration(EnumSet.noneOf(Modifier.class),
false, "Foo");
assertEquals(false, decl.hasJavaDocComment());
}
@Test
public void hasJavaDocCommentNegativeCaseLineComment() {
ClassOrInterfaceDeclaration decl = new ClassOrInterfaceDeclaration(EnumSet.noneOf(Modifier.class),
false, "Foo");
decl.setComment(new LineComment("foo"));
assertEquals(false, decl.hasJavaDocComment());
}
@Test
public void hasJavaDocCommentNegativeCaseBlockComment() {
ClassOrInterfaceDeclaration decl = new ClassOrInterfaceDeclaration(EnumSet.noneOf(Modifier.class),
false, "Foo");
decl.setComment(new BlockComment("foo"));
assertEquals(false, decl.hasJavaDocComment());
}
@Test
public void removeAllOnRequiredProperty() {
CompilationUnit cu = parse("class X{ void x(){}}");
MethodDeclaration methodDeclaration = cu.getType(0).getMethods().get(0);
methodDeclaration.getName().removeForced();
// Name is required, so to remove it the whole method is removed.
assertEquals(String.format("class X {%1$s}%1$s", EOL), cu.toString());
}
@Test
public void removingTheSecondOfAListOfIdenticalStatementsDoesNotMessUpTheParents() {
CompilationUnit unit = parse(String.format("public class Example {%1$s" +
" public static void example() {%1$s" +
" boolean swapped;%1$s" +
" swapped=false;%1$s" +
" swapped=false;%1$s" +
" }%1$s" +
"}%1$s", EOL));
// remove the second swapped=false
Node target = unit.getChildNodes().get(0).getChildNodes().get(1).getChildNodes().get(2).getChildNodes().get(2);
target.remove();
// This will throw an exception if the parents are bad.
System.out.println(unit.toString());
}
@Test
public void findCompilationUnit() {
CompilationUnit cu = parse("class X{int x;}");
VariableDeclarator x = cu.getClassByName("X").get().getMember(0).asFieldDeclaration().getVariables().get(0);
assertEquals(cu, x.findCompilationUnit().get());
}
@Test
public void findParent() {
CompilationUnit cu = parse("class X{int x;}");
SimpleName x = cu.getClassByName("X").get().getMember(0).asFieldDeclaration().getVariables().get(0).getName();
assertEquals("int x;", x.findParent(FieldDeclaration.class).get().toString());
}
@Test
public void cantFindCompilationUnit() {
VariableDeclarator x = new VariableDeclarator();
assertFalse(x.findCompilationUnit().isPresent());
}
@Test
public void genericWalk() {
Expression e = parseExpression("1+1");
StringBuilder b = new StringBuilder();
e.walk(n -> b.append(n.toString()));
assertEquals("1 + 111", b.toString());
}
@Test
public void classSpecificWalk() {
Expression e = parseExpression("1+1");
StringBuilder b = new StringBuilder();
e.walk(IntegerLiteralExpr.class, n -> b.append(n.toString()));
assertEquals("11", b.toString());
}
@Test
public void conditionalFindAll() {
Expression e = parseExpression("1+2+3");
List<IntegerLiteralExpr> ints = e.findAll(IntegerLiteralExpr.class, n -> n.asInt() > 1);
assertEquals("[2, 3]", ints.toString());
}
@Test
public void typeOnlyFindAll() {
Expression e = parseExpression("1+2+3");
List<IntegerLiteralExpr> ints = e.findAll(IntegerLiteralExpr.class);
assertEquals("[1, 2, 3]", ints.toString());
}
@Test
public void typeOnlyFindAllMatchesSubclasses() {
Expression e = parseExpression("1+2+3");
List<Node> ints = e.findAll(Node.class);
assertEquals("[1 + 2 + 3, 1 + 2, 1, 2, 3]", ints.toString());
}
@Test
public void conditionalTypedFindFirst() {
Expression e = parseExpression("1+2+3");
Optional<IntegerLiteralExpr> ints = e.findFirst(IntegerLiteralExpr.class, n -> n.asInt() > 1);
assertEquals("Optional[2]", ints.toString());
}
@Test
public void typeOnlyFindFirst() {
Expression e = parseExpression("1+2+3");
Optional<IntegerLiteralExpr> ints = e.findFirst(IntegerLiteralExpr.class);
assertEquals("Optional[1]", ints.toString());
}
@Test
public void stream() {
Expression e = parseExpression("1+2+3");
List<IntegerLiteralExpr> ints = e.stream()
.filter(n -> n instanceof IntegerLiteralExpr)
.map(IntegerLiteralExpr.class::cast)
.filter(i -> i.asInt() > 1)
.collect(Collectors.toList());
assertEquals("[2, 3]", ints.toString());
}
}