Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add generic test for all Factory methods #3005

Merged
merged 4 commits into from
Jun 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ public <E extends CtElement> E setAnnotations(List<CtAnnotation<? extends Annota

@Override
public void delete() {
if (!isParentInitialized()) {
// already not in a tree, nothing to be deleted
return;
}
//delete is implemented as replace by no element (empty list of elements)
replace(Collections.<CtElement>emptyList());
}
Expand Down
48 changes: 48 additions & 0 deletions src/test/java/spoon/test/factory/FactoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.junit.Test;
import spoon.Launcher;
import spoon.SpoonAPI;
import spoon.SpoonException;
import spoon.processing.AbstractProcessor;
import spoon.reflect.CtModel;
import spoon.reflect.code.CtFieldRead;
Expand All @@ -32,18 +33,23 @@
import spoon.reflect.factory.CoreFactory;
import spoon.reflect.factory.Factory;
import spoon.reflect.factory.FactoryImpl;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.filter.NamedElementFilter;
import spoon.support.DefaultCoreFactory;
import spoon.support.StandardEnvironment;
import spoon.support.reflect.declaration.CtMethodImpl;
import spoon.test.SpoonTestHelpers;
import spoon.test.factory.testclasses.Foo;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static spoon.test.parent.ContractOnSettersParametrizedTest.createCompatibleObject;
import static spoon.testing.utils.ModelUtils.build;
import static spoon.testing.utils.ModelUtils.buildClass;

Expand Down Expand Up @@ -223,4 +229,46 @@ public void specificationCoreFactoryCreate() {
assertTrue(itf.getActualClass().isInstance(o));
}
}

@Test
public void factoryTest() throws Exception {
// contract: all methods of Factory can be called without exception, returning a correct object
Launcher spoon = new Launcher();
spoon.addInputResource("src/main/java/spoon/reflect/factory/Factory.java");
spoon.buildModel();
for (CtMethod<?> m : spoon.getFactory().Type().get("spoon.reflect.factory.Factory").getMethods()) {
if (!m.getSimpleName().startsWith("create")
|| "createSourcePosition".equals(m.getSimpleName()) // method with implicit contracts on int parameters
|| "createBodyHolderSourcePosition".equals(m.getSimpleName()) // method with implicit contracts on int parameters
|| "createDeclarationSourcePosition".equals(m.getSimpleName()) // method with implicit contracts on int parameters
|| "createNewClass".equals(m.getSimpleName()) // method with implicit contract between the two parameters
) {
continue;
}


// collecting arguments and creating parameters
Object[] args = new Object[m.getParameters().size()];
Class[] argsClass = new Class[m.getParameters().size()];
for (int i =0; i<args.length; i++) {
CtTypeReference<?> type = m.getParameters().get(i).getType();
args[i] = createCompatibleObject(type);
argsClass[i] = type.getActualClass();
if (!type.isPrimitive()) {
// post-condition to be sure that createCompatibleObject works well
assertTrue(args[i].getClass().toString() + " != " + argsClass[i].toString(), argsClass[i].isAssignableFrom(args[i].getClass()));
}
}

// calling the method
Method rm;
rm = m.getReference().getActualMethod();
//rm = spoon.getFactory().getClass().getDeclaredMethod(m.getSimpleName(), argsClass); // works also
//System.out.println(rm);
Object res = rm.invoke(spoon.getFactory(), args);
assertNotNull(res);

}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import spoon.SpoonException;
import spoon.reflect.code.BinaryOperatorKind;
import spoon.reflect.code.CtCodeSnippetExpression;
import spoon.reflect.code.CtComment;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtJavaDocTag;
import spoon.reflect.cu.CompilationUnit;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtCodeSnippet;
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.ModifierKind;
import spoon.support.modelobs.ActionBasedChangeListenerImpl;
import spoon.support.modelobs.action.Action;
import spoon.reflect.declaration.CtElement;
Expand Down Expand Up @@ -89,6 +99,28 @@ public void onAction(Action action) {

public static Object createCompatibleObject(CtTypeReference<?> parameterType) {
Class<?> c = parameterType.getActualClass();
Factory f = parameterType.getFactory();

// all Class objects
if (Class.class.isAssignableFrom(c) && parameterType.getActualTypeArguments().size() == 0) {
return Object.class;
}
if (Class.class.isAssignableFrom(c) && parameterType.getActualTypeArguments().get(0).toString().equals("?")) {
return Object.class;
}
if (Class.class.isAssignableFrom(c) && parameterType.getActualTypeArguments().get(0).toString().equals("? extends java.lang.Throwable")) {
return Exception.class;
}
if (Class.class.isAssignableFrom(c) && parameterType.getActualTypeArguments().get(0).toString().equals("? extends spoon.reflect.declaration.CtElement")) {
return CtCodeSnippetExpression.class;
}

// metamodel elements
if (parameterType.toString().equals("spoon.reflect.declaration.CtType<?>")) {
CtClass fooBar = f.createClass("FooBar");
fooBar.delete();// removing from default package
return fooBar; // createNewClass implictly needs a CtClass
}
for(CtType t : allInstantiableMetamodelInterfaces) {
if (c.isAssignableFrom(t.getActualClass())) {
CtElement argument = factory.Core().create(t.getActualClass());
Expand All @@ -97,10 +129,34 @@ public static Object createCompatibleObject(CtTypeReference<?> parameterType) {
if (argument instanceof CtPackage) {
((CtPackage) argument).setSimpleName(argument.getShortRepresentation());
}

return argument;

}
}

// enums
if (BinaryOperatorKind.class.isAssignableFrom(c)) {
return BinaryOperatorKind.AND;
}
if (ModifierKind.class.isAssignableFrom(c)) {
return ModifierKind.PUBLIC;
}
if (CtComment.CommentType.class.isAssignableFrom(c)) {
return CtComment.CommentType.INLINE;
}
if (CtJavaDocTag.TagType.class.isAssignableFrom(c)) {
return CtJavaDocTag.TagType.SEE;
}

// misc
if (ModifierKind[].class.isAssignableFrom(c)) {
return new ModifierKind[] {ModifierKind.PUBLIC};
}
if (CompilationUnit.class.isAssignableFrom(c)) {
return parameterType.getFactory().createCompilationUnit();
}

if (Set.class.isAssignableFrom(c)) {
// we create one set with one element
HashSet<Object> objects = new HashSet<>();
Expand All @@ -113,6 +169,32 @@ public static Object createCompatibleObject(CtTypeReference<?> parameterType) {
objects.add(createCompatibleObject(parameterType.getActualTypeArguments().get(0)));
return objects;
}
if (String.class.isAssignableFrom(c)) {
return "42";
}
if (int.class.isAssignableFrom(c)) {
return 42;
}
if (boolean.class.isAssignableFrom(c)) {
return true;
}

// arrays
if (int[].class.isAssignableFrom(c)) {
return new int[] {42};
}
if (CtExpression[].class.isAssignableFrom(c)) {
return new CtExpression[0];
}
if (Object[].class.isAssignableFrom(c)) {
return new Object[] {42};
}

// others
if (java.lang.Package.class.isAssignableFrom(c)) {
return Package.getPackages()[0];
}

throw new IllegalArgumentException("cannot instantiate "+parameterType);
}
static int nTotalSetterCalls= 0;
Expand Down