Skip to content

Commit

Permalink
test(ParentContractTest): improves contract about setting parents
Browse files Browse the repository at this point in the history
  • Loading branch information
monperrus authored and tdurieux committed Nov 10, 2016
1 parent 7b4173b commit a9da3fc
Showing 1 changed file with 29 additions and 12 deletions.
41 changes: 29 additions & 12 deletions src/test/java/spoon/test/parent/ParentContractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
import spoon.reflect.code.CtTypeAccess;
import spoon.reflect.declaration.CtAnnotationType;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.CoreFactory;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtActualTypeContainer;
import spoon.reflect.reference.CtReference;
import spoon.reflect.visitor.CtVisitable;
import spoon.test.SpoonTestHelpers;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand All @@ -26,6 +28,8 @@
import java.util.List;
import java.util.Queue;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static spoon.testing.utils.ModelUtils.createFactory;
Expand All @@ -35,17 +39,14 @@
public class ParentContractTest<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 (Method method : CoreFactory.class.getDeclaredMethods()) {
if (method.getName().startsWith("create")
&& method.getParameterCount() == 0
&& method.getReturnType().getSimpleName().startsWith("Ct")
&& !CtReference.class.isAssignableFrom(method.getReturnType())
){
values.add(new Object[] { method.getReturnType(), method.invoke(factory.Core()) });
for (CtType t : allInstantiableMetamodelInterfaces) {
if (!(CtReference.class.isAssignableFrom(t.getActualClass()))) {
values.add(new Object[] { t.getActualClass(), factory.Core().create(t.getActualClass()) });
}
}
return values;
Expand All @@ -72,7 +73,7 @@ private List<Method> getMethodsToInvoke(Class<?> entry) throws Exception {
while (!tocheck.isEmpty()) {
Class<?> intf = tocheck.poll();

Assert.assertTrue(intf.isInterface());
assertTrue(intf.isInterface());
if (!intf.getSimpleName().startsWith("Ct")) {
continue;
}
Expand Down Expand Up @@ -101,10 +102,20 @@ private List<Method> getMethodsToInvoke(Class<?> entry) throws Exception {
return toInvoke;
}

private CtElement createCompatibleObject(Class c) {
for(CtType t : allInstantiableMetamodelInterfaces) {
if (c.isAssignableFrom(t.getActualClass())) {
return factory.Core().create(t.getActualClass());
}
}
throw new IllegalArgumentException();
}
@Test
public void testContract() throws Throwable {
// contract: all setters/adders must set the parent (not necessarily the direct parent, can be upper in the parent tree, for instance when injecting blocks
Object o = instance;
for (Method setter : getMethodsToInvoke(toTest)) {
List<Method> methodsToInvoke = getMethodsToInvoke(toTest);
for (Method setter : methodsToInvoke) {

// special case: impossible methods on some objects (they throw an UnsupportedOperationException)
if (setter.getAnnotation(Deprecated.class) != null) continue;
Expand All @@ -118,14 +129,20 @@ public void testContract() throws Throwable {
if (o instanceof CtTypeAccess && "setType".equals(setter.getName())) continue;
if (o instanceof CtType && "setSuperclass".equals(setter.getName())) continue;

CtElement mockedArgument = (CtElement) mock(setter.getParameters()[0].getType(), Mockito.withSettings().extraInterfaces(Comparable.class));

CtElement argument = createCompatibleObject((Class<? extends CtElement>) setter.getParameters()[0].getType());
// an empty package is merged with the existing one
// we have to give it a name
if (argument instanceof CtPackage) {
((CtPackage)argument).setSimpleName("foobar");
}
try {
// we create a fresh object
CtElement receiver = ((CtElement) o).clone();
// we invoke the setter
setter.invoke(receiver, new Object[] { mockedArgument });
setter.invoke(receiver, new Object[] { argument });
// we check that setParent has been called
verify(mockedArgument).setParent((CtElement) receiver);
assertTrue(argument.hasParent(receiver));
} catch (AssertionError e) {
Assert.fail("call setParent contract failed for " + setter.toString() + " " + e.toString());
} catch (InvocationTargetException e) {
Expand Down

0 comments on commit a9da3fc

Please sign in to comment.