package spoon.test.factory;
import org.junit.Test;
import spoon.Launcher;
import spoon.SpoonAPI;
import spoon.processing.AbstractProcessor;
import spoon.reflect.CtModel;
import spoon.reflect.code.CtFieldRead;
import spoon.reflect.code.CtNewArray;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.factory.CoreFactory;
import spoon.reflect.factory.Factory;
import spoon.reflect.factory.FactoryImpl;
import spoon.reflect.visitor.filter.AbstractFilter;
import spoon.reflect.visitor.filter.NameFilter;
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 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.testing.utils.ModelUtils.build;
import static spoon.testing.utils.ModelUtils.buildClass;
public class FactoryTest {
@Test
public void testClone() throws Exception {
CtClass<?> type = build("spoon.test", "SampleClass");
CtMethod<?> m = type.getMethodsByName("method3").get(0);
int i = m.getBody().getStatements().size();
m = m.clone();
assertEquals(i, m.getBody().getStatements().size());
// cloned elements must not have an initialized parent
assertFalse(m.isParentInitialized());
}
@Test
public void testFactoryOverriding() throws Exception {
@SuppressWarnings("serial")
class MyCtMethod<T> extends CtMethodImpl<T>{};
@SuppressWarnings("serial")
final CoreFactory specialCoreFactory = new DefaultCoreFactory() {
@Override
public <T> CtMethod<T> createMethod() {
MyCtMethod<T> m = new MyCtMethod<T>();
m.setFactory(getMainFactory());
return m;
}
};
Launcher launcher = new Launcher() {
@Override
public Factory createFactory() {
return new FactoryImpl(specialCoreFactory, new StandardEnvironment());
}
};
CtClass<?> type = build("spoon.test", "SampleClass", launcher.getFactory());
CtMethod<?> m = type.getMethodsByName("method3").get(0);
assertTrue(m instanceof MyCtMethod);
}
@Test
public void testClassAccessCreatedFromFactories() throws Exception {
final CtType<Foo> foo = buildClass(Foo.class);
assertEquals(1, foo.getAnnotations().size());
assertEquals(0, foo.getAnnotations().get(0).getValues().size());
foo.getFactory().Annotation().annotate(foo, Foo.Bar.class, "clazz", Foo.class);
assertEquals(1, foo.getAnnotations().size());
assertEquals(1, foo.getAnnotations().get(0).getValues().size());
assertTrue(foo.getAnnotations().get(0).getValues().get("clazz") instanceof CtFieldRead);
assertEquals("spoon.test.factory.testclasses.Foo.class", foo.getAnnotations().get(0).getValues().get("clazz").toString());
foo.getFactory().Annotation().annotate(foo, Foo.Bar.class, "classes", new Class[] { Foo.class });
assertEquals(1, foo.getAnnotations().size());
assertEquals(2, foo.getAnnotations().get(0).getValues().size());
assertTrue(foo.getAnnotations().get(0).getValues().get("classes") instanceof CtNewArray);
assertEquals(1, ((CtNewArray) foo.getAnnotations().get(0).getValues().get("classes")).getElements().size());
assertEquals("spoon.test.factory.testclasses.Foo.class", ((CtNewArray) foo.getAnnotations().get(0).getValues().get("classes")).getElements().get(0).toString());
}
@Test
public void testCtModel() throws Exception {
SpoonAPI spoon = new Launcher();
spoon.addInputResource("src/test/java/spoon/test/factory/testclasses");
spoon.buildModel();
CtModel model = spoon.getModel();
// contains Foo and Foo.@Bar
assertEquals(1, model.getAllTypes().size());
// [, spoon, spoon.test, spoon.test.factory, spoon.test.factory.testclasses]
assertEquals(5, model.getAllPackages().size());
// add to itself is fine
model.getRootPackage().addPackage(model.getRootPackage());
assertEquals(1, model.getAllTypes().size());
assertEquals(5, model.getAllPackages().size());
model.getRootPackage().getPackage("spoon").addPackage(model.getRootPackage().getPackage("spoon"));
assertEquals(1, model.getAllTypes().size());
assertEquals(5, model.getAllPackages().size());
model.getRootPackage().addPackage(model.getRootPackage().getPackage("spoon"));
assertEquals(1, model.getAllTypes().size());
assertEquals(5, model.getAllPackages().size());
CtPackage p = model.getRootPackage().getElements(new NameFilter<CtPackage>("spoon")).get(0).clone();
// if we change the implem, merge is impossible
CtField f = spoon.getFactory().Core().createField();
f.setSimpleName("foo");
f.setType(spoon.getFactory().Type().BYTE);
p.getElements(new NameFilter<CtPackage>("testclasses")).get(0).getType("Foo").addField(f);
try {
model.getRootPackage().addPackage(p);
fail("no exception thrown");
} catch (IllegalStateException success) {}
model.processWith(new AbstractProcessor<CtType>() {
@Override
public void process(CtType element) {
element.delete();
}
});
assertEquals(0, model.getAllTypes().size());
}
@Test
public void testIncrementalModel() throws Exception {
// Feed some inputResources to a spoon compiler
SpoonAPI spoon = new Launcher();
spoon.addInputResource("src/test/java/spoon/test/factory/testclasses");
// Build model
spoon.buildModel();
assertEquals(1, spoon.getModel().getAllTypes().size());
// Do something with that model..
CtModel model = spoon.getModel();
model.processWith(new AbstractProcessor<CtMethod>() {
@Override
public void process(CtMethod element) {
element.setDefaultMethod(false);
}
});
// Feed some new inputResources
SpoonAPI spoon2 = new Launcher();
spoon2.addInputResource("src/test/java/spoon/test/factory/testclasses2");
// Build models of newly added classes/packages
spoon2.buildModel();
assertEquals(1, spoon2.getModel().getAllTypes().size());
// attach them to the existing model.
model.getRootPackage().addPackage(spoon2.getModel().getRootPackage());
// checking the results
assertEquals(6, model.getAllPackages().size());
assertEquals(2, model.getAllTypes().size());
assertEquals(1, model.getRootPackage().getElements(new AbstractFilter<CtPackage>() {
@Override
public boolean matches(CtPackage element) {
return "spoon.test.factory.testclasses2".equals(element.getQualifiedName());
}
}).size());
}
@Test
public void specificationCoreFactoryCreate() throws Exception {
// contract: all concrete metamodel classes must be instantiable by CoreFactory.create
for(CtType<? extends CtElement> itf : SpoonTestHelpers.getAllInstantiableMetamodelInterfaces()) {
CtElement o = itf.getFactory().Core().create(itf.getActualClass());
assertNotNull(o);
assertTrue(itf.getActualClass().isInstance(o));
}
}
}