package spoon.test.replace;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import spoon.Launcher;
import spoon.compiler.SpoonResourceHelper;
import spoon.reflect.code.CtAssignment;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtConstructorCall;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtLiteral;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtTry;
import spoon.reflect.code.CtVariableRead;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtVariable;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtFieldReference;
import spoon.reflect.reference.CtParameterReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.NameFilter;
import spoon.reflect.visitor.filter.ReferenceTypeFilter;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.test.replace.testclasses.Mole;
import spoon.test.replace.testclasses.Tacos;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame;
import static spoon.testing.utils.ModelUtils.build;
import static spoon.testing.utils.ModelUtils.buildClass;
public class ReplaceTest {
Factory factory;
@Before
public void setup() throws Exception {
Launcher spoon = new Launcher();
factory = spoon.createFactory();
spoon.createCompiler(
factory,
SpoonResourceHelper
.resources("./src/test/java/spoon/test/replace/testclasses"))
.build();
}
@Test
public void testReplaceSet() throws Exception {
CtClass<?> foo = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo");
assertEquals("Foo", foo.getSimpleName());
CtClass<?> bar = factory.Package().get("spoon.test.replace.testclasses")
.getType("Bar");
assertEquals("Bar", bar.getSimpleName());
CtField<Number> i1 = (CtField<Number>) foo.getField("i");
CtField<Number> i2 = (CtField<Number>) bar.getField("i");
assertEquals("int", foo.getField("i").getType().getSimpleName());
// do
i1.replace(i2);
assertSame(i2, foo.getField("i"));
assertEquals("float", foo.getField("i").getType().getSimpleName());
assertEquals(foo, i2.getParent());
// undo
i2.replace(i1);
assertSame(i1, foo.getField("i"));
assertEquals("int", foo.getField("i").getType().getSimpleName());
assertEquals(foo, i1.getParent());
}
@Test
public void testReplaceBlock() throws Exception {
CtClass<?> foo = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo");
CtMethod<?> m = foo.getElements(
new NameFilter<CtMethod<?>>("foo")).get(0);
assertEquals("foo", m.getSimpleName());
final CtStatement parent = m.getBody().getStatements().get(2);
CtAssignment<?, ?> assignment = (CtAssignment<?, ?>) parent;
CtExpression<Integer> s1 = (CtExpression<Integer>) assignment.getAssignment();
CtExpression<Integer> s2 = factory.Code().createLiteral(3);
assertEquals("z = x + 1", assignment.toString());
assertEquals("x + 1", s1.toString());
// do
s1.replace(s2);
assertSame(s2, assignment.getAssignment());
assertEquals("z = 3", assignment.toString());
assertEquals(parent, s2.getParent());
// undo
s2.replace(s1);
assertSame(s1, assignment.getAssignment());
assertEquals("z = x + 1", assignment.toString());
assertEquals(parent, s1.getParent());
}
@Test
public void testReplaceReplace() throws Exception {
// bug found by Benoit
CtClass<?> foo = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo");
CtMethod<?> fooMethod = foo.getElements(
new NameFilter<CtMethod<?>>("foo")).get(0);
assertEquals("foo", fooMethod.getSimpleName());
CtMethod<?> barMethod = foo.getElements(
new NameFilter<CtMethod<?>>("bar")).get(0);
assertEquals("bar", barMethod.getSimpleName());
CtLocalVariable<?> assignment = (CtLocalVariable<?>) fooMethod.getBody()
.getStatements().get(0);
CtLocalVariable<?> newAssignment = barMethod.getBody().getStatement(0);
assignment.replace(newAssignment);
assertEquals(fooMethod.getBody(), newAssignment.getParent());
CtLiteral<Integer> lit = (CtLiteral<Integer>) foo.getElements(new TypeFilter<CtLiteral<?>>(CtLiteral.class))
.get(0);
final CtElement parent = lit.getParent();
CtLiteral<Integer> newLit = factory.Code().createLiteral(0);
lit.replace(newLit);
assertEquals("int y = 0", fooMethod.getBody().getStatement(0).toString());
assertEquals(parent, newLit.getParent());
}
@Test
public void testReplaceStmtByList() {
CtClass<?> sample = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo");
// replace retry content by statements
CtStatement stmt = sample.getMethod("retry").getBody().getStatement(0);
CtBlock lst = sample.getMethod("statements").getBody();
// replace a single statement by a statement list
stmt.replace(lst);
// we should have only 2 statements after (from the stmt list)
assertEquals(1, sample.getMethod("retry").getBody().getStatements().size());
assertEquals(2, ((CtBlock) sample.getMethod("retry").getBody().getStatement(0)).getStatements().size());
}
@Test
public void testReplaceField() {
CtClass<?> sample = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo");
Assert.assertEquals(factory.Type().createReference(int.class), sample.getField("i").getType());
// replace with another type
CtField replacement = factory.Core().createField();
replacement.setSimpleName("i");
replacement.setType(factory.Type().createReference(double.class));
sample.getField("i").replace(replacement);
Assert.assertEquals(factory.Type().createReference(double.class), sample.getField("i").getType());
// replace with another name
replacement = factory.Core().createField();
replacement.setSimpleName("j");
replacement.setType(factory.Type().createReference(double.class));
sample.getField("i").replace(replacement);
Assert.assertNull(sample.getField("i"));
Assert.assertNotNull(sample.getField("j"));
Assert.assertEquals(factory.Type().createReference(double.class), sample.getField("j").getType());
}
@Test
public void testReplaceMethod() {
CtClass<?> sample = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo");
Assert.assertNotNull(sample.getMethod("foo"));
Assert.assertNull(sample.getMethod("notfoo"));
CtMethod bar = factory.Core().createMethod();
bar.setSimpleName("notfoo");
bar.setType(factory.Type().createReference(void.class));
sample.getMethod("foo").replace(bar);
Assert.assertNull(sample.getMethod("foo"));
Assert.assertNotNull(sample.getMethod("notfoo"));
}
@Test
public void testReplaceExpression() {
CtMethod<?> sample = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo").getMethod("foo");
CtVariable<?> var = sample.getBody().getStatement(0);
Assert.assertTrue(var.getDefaultExpression() instanceof CtLiteral);
Assert.assertEquals(3, ((CtLiteral<?>) var.getDefaultExpression()).getValue());
CtLiteral replacement = factory.Core().createLiteral();
replacement.setValue(42);
var.getDefaultExpression().replace(replacement);
Assert.assertEquals(42, ((CtLiteral<?>) var.getDefaultExpression()).getValue());
}
@Test
public void testReplaceStatement() {
CtMethod<?> sample = factory.Package().get("spoon.test.replace.testclasses")
.getType("Foo").getMethod("foo");
Assert.assertTrue(sample.getBody().getStatement(0) instanceof CtVariable);
CtStatement replacement = factory.Core().createInvocation();
sample.getBody().getStatement(0).replace(replacement);
Assert.assertTrue(sample.getBody().getStatement(0) instanceof CtInvocation);
}
@Test
public void testReplaceIntegerReference() throws Exception {
// contract: replace a primitive type reference by another one.
final Factory factory = build(Tacos.class);
final CtType<Tacos> aTacos = factory.Type().get(Tacos.class);
final CtMethod<?> aMethod = aTacos.getMethodsByName("m").get(0);
assertEquals(factory.Type().INTEGER_PRIMITIVE, aMethod.getType());
aMethod.getType().replace(factory.Type().DOUBLE_PRIMITIVE);
assertEquals(factory.Type().DOUBLE_PRIMITIVE, aMethod.getType());
}
@Test
public void testReplaceAllTypeRefenceWithGenerics() throws Exception {
// contract: replace all type references with a generic to the same type reference without generics.
final Factory factory = build(Tacos.class);
final List<CtTypeReference> references = Query.getElements(factory, new ReferenceTypeFilter<CtTypeReference>(CtTypeReference.class) {
@Override
public boolean matches(CtTypeReference reference) {
return reference.getActualTypeArguments().size() > 0 && super.matches(reference);
}
});
references.get(0).replace(factory.Type().createReference(references.get(0).getQualifiedName()));
final CtType<Tacos> aTacos = factory.Type().get(Tacos.class);
final CtMethod<?> aMethod = aTacos.getMethodsByName("m2").get(0);
final CtTypeReference<Object> expected = factory.Type().createReference("spoon.test.replace.testclasses.Tacos");
assertEquals(expected, aMethod.getType());
assertEquals(expected.getTypeDeclaration(), aMethod.getElements(new TypeFilter<>(CtConstructorCall.class)).get(0).getType().getTypeDeclaration());
}
@Test
public void testReplaceAPackageReferenceByAnotherOne() throws Exception {
// contract: replace a package reference of a reference to another package.
final Launcher launcher = new Launcher();
launcher.setArgs(new String[] {"--output-type", "nooutput" });
launcher.getEnvironment().setNoClasspath(true);
launcher.addInputResource("./src/test/resources/reference-package");
launcher.run();
final CtType<Object> panini = launcher.getFactory().Type().get("Panini");
final CtTypeReference<?> burritos = panini.getElements(new ReferenceTypeFilter<CtTypeReference<?>>(CtTypeReference.class) {
@Override
public boolean matches(CtTypeReference<?> reference) {
return "Burritos".equals(reference.getSimpleName()) && super.matches(reference);
}
}).get(0);
assertEquals("com.awesome", burritos.getPackage().toString());
assertEquals("com.awesome.Burritos", panini.getMethodsByName("m").get(0).getType().toString());
burritos.getPackage().replace(launcher.getFactory().Package().createReference("com.best"));
assertEquals("com.best", burritos.getPackage().toString());
assertEquals("com.best.Burritos", panini.getMethodsByName("m").get(0).getType().toString());
}
@Test
public void testReplaceAParameterReferenceToFieldReference() throws Exception {
// contract: replace a parameter reference to a field reference.
final Factory factory = build(Tacos.class);
final CtType<Tacos> aTacos = factory.Type().get(Tacos.class);
final CtInvocation inv = aTacos.getMethodsByName("m3").get(0).getElements(new TypeFilter<>(CtInvocation.class)).get(0);
final CtVariableRead<?> variableRead = (CtVariableRead<?>) inv.getArguments().get(0);
final CtParameterReference<?> aParameterReference = (CtParameterReference<?>) variableRead.getVariable();
final CtFieldReference<?> aFieldReference = aTacos.getField("field").getReference();
assertEquals(aParameterReference, variableRead.getVariable());
assertEquals("java.lang.System.err.println(param)", inv.toString());
aParameterReference.replace(aFieldReference);
assertEquals(aFieldReference, variableRead.getVariable());
assertEquals("java.lang.System.err.println(field)", inv.toString());
}
@Test
public void testReplaceExecutableReferenceByAnotherOne() throws Exception {
// contract: replace an executable reference to another one in an invocation.
final Factory factory = build(Tacos.class);
final CtType<Tacos> aTacos = factory.Type().get(Tacos.class);
final CtInvocation inv = aTacos.getMethodsByName("m3").get(0).getElements(new TypeFilter<>(CtInvocation.class)).get(0);
final CtExecutableReference oldExecutable = inv.getExecutable();
final CtExecutableReference<Object> newExecutable = factory.Executable().createReference("void java.io.PrintStream#print(java.lang.String)");
assertEquals(oldExecutable, inv.getExecutable());
assertEquals("java.io.PrintStream#println(java.lang.String)", inv.getExecutable().toString());
oldExecutable.replace(newExecutable);
assertEquals(newExecutable, inv.getExecutable());
assertEquals("java.io.PrintStream#print(java.lang.String)", inv.getExecutable().toString());
}
@Test
public void testReplaceBlockTry() throws Exception {
final CtType<Mole> aMole = buildClass(Mole.class);
final CtBlock<?> newBlock = aMole.getFactory().Code().createCtBlock(aMole.getFactory().Code().createCodeSnippetStatement("int j = 0;").compile());
final CtTry ctTry = aMole.getMethod("m").getElements(new TypeFilter<>(CtTry.class)).get(0);
assertNotEquals(newBlock, ctTry.getBody());
ctTry.getBody().replace(newBlock);
assertEquals(newBlock, ctTry.getBody());
}
}