package spoon.test.replace; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import spoon.SpoonException; import spoon.reflect.code.CtFieldAccess; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtPackage; import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.CtTypeMember; import spoon.reflect.factory.Factory; import spoon.reflect.reference.CtParameterReference; import spoon.reflect.reference.CtReference; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.CtVisitable; import spoon.reflect.visitor.Filter; import spoon.support.UnsettableProperty; import spoon.test.SpoonTestHelpers; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Queue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static spoon.test.SpoonTestHelpers.getAllSetters; import static spoon.test.parent.ParentContractTest.createCompatibleObject; import static spoon.testing.utils.ModelUtils.createFactory; @RunWith(Parameterized.class) public class ReplaceParametrizedTest<T extends CtVisitable> { private static Factory factory = createFactory(); private static final List<CtType<? extends CtElement>> allInstantiableMetamodelInterfaces = SpoonTestHelpers.getAllInstantiableMetamodelInterfaces(); @Parameterized.Parameters(name = "{0}") public static Collection<Object[]> data() throws Exception { List<Object[]> values = new ArrayList<>(); for (CtType t : allInstantiableMetamodelInterfaces) { values.add(new Object[] { t }); } return values; } @Parameterized.Parameter(0) public CtType<?> toTest; @Test public void testContract() throws Throwable { // contract: all elements are replaceable wherever they are in the model // this test puts them at all possible locations Object o = factory.Core().create((Class<? extends CtElement>) toTest.getActualClass()); for (CtMethod<?> ctsetter : getAllSetters(toTest)) { Method setter = ctsetter.getReference().getActualMethod(); Class<? extends CtElement> argType = (Class<? extends CtElement>) setter.getParameters()[0].getType(); if (!CtElement.class.isAssignableFrom(argType)) { continue; } CtElement argument = (CtElement) createCompatibleObject(ctsetter.getParameters().get(0).getType()); // special cases... if (o.getClass().getSimpleName().equals("CtAnnotationFieldAccessImpl") && setter.getName().equals("setVariable")) { argument = factory.Core().createFieldReference(); } if (CtFieldAccess.class.isAssignableFrom(o.getClass())&& setter.getName().equals("setVariable")) { argument = factory.Core().createFieldReference(); } // we create a fresh object CtElement receiver = ((CtElement) o).clone(); // we invoke the setter setter.invoke(receiver, new Object[]{argument}); final CtElement argument2 = argument.clone(); assertNotSame(argument, argument2); // we do the replace argument.replace(argument2); if (ctsetter.getAnnotation(UnsettableProperty.class) == null) { // the new element is indeed now in this AST assertTrue(receiver.getClass().getSimpleName() + " failed for " + setter.getName(), receiver.getElements(new Filter<CtElement>() { @Override public boolean matches(CtElement element) { return element == argument2; } }).size() > 0); } } } }