package spoon.test.annotation;
import org.junit.Test;
import spoon.Launcher;
import spoon.reflect.code.CtConstructorCall;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtFieldAccess;
import spoon.reflect.code.CtFieldRead;
import spoon.reflect.code.CtLiteral;
import spoon.reflect.code.CtNewArray;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.Factory;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.test.annotation.testclasses.AnnotationValues;
import spoon.test.annotation.testclasses.BoundNumber;
import spoon.testing.utils.ModelUtils;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static spoon.test.annotation.AnnotationValuesTest.Request.on;
import static spoon.testing.utils.ModelUtils.buildClass;
import static spoon.testing.utils.ModelUtils.createFactory;
public class AnnotationValuesTest {
static int i;
@Test
public void testValuesOnJava7Annotation() throws Exception {
CtType<AnnotationValues> aClass = buildClass(AnnotationValues.class);
CtAnnotation<?> ctAnnotation = on(aClass).giveMeAnnotation(AnnotationValues.Annotation.class);
on(ctAnnotation).giveMeAnnotationValue("integer").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("integers").isTypedBy(CtNewArray.class);
on(ctAnnotation).giveMeAnnotationValue("string").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("strings").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("clazz").isTypedBy(CtFieldAccess.class);
on(ctAnnotation).giveMeAnnotationValue("classes").isTypedBy(CtNewArray.class);
on(ctAnnotation).giveMeAnnotationValue("b").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("e").isTypedBy(CtFieldAccess.class);
on(ctAnnotation).giveMeAnnotationValue("ia").isTypedBy(CtAnnotation.class);
on(ctAnnotation).giveMeAnnotationValue("ias").isTypedBy(CtNewArray.class);
}
@Test
public void testValuesOnJava8Annotation() throws Exception {
CtType<AnnotationValues> aClass = buildClass(AnnotationValues.class);
CtConstructorCall aConstructorCall = aClass.getMethod("method").getElements(new TypeFilter<>(CtConstructorCall.class)).get(0);
CtAnnotation<?> ctAnnotation = on(aConstructorCall.getType()).giveMeAnnotation(AnnotationValues.Annotation.class);
on(ctAnnotation).giveMeAnnotationValue("integer").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("integers").isTypedBy(CtNewArray.class);
on(ctAnnotation).giveMeAnnotationValue("string").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("strings").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("clazz").isTypedBy(CtFieldAccess.class);
on(ctAnnotation).giveMeAnnotationValue("classes").isTypedBy(CtNewArray.class);
on(ctAnnotation).giveMeAnnotationValue("b").isTypedBy(CtLiteral.class);
on(ctAnnotation).giveMeAnnotationValue("e").isTypedBy(CtFieldAccess.class);
on(ctAnnotation).giveMeAnnotationValue("ia").isTypedBy(CtAnnotation.class);
on(ctAnnotation).giveMeAnnotationValue("ias").isTypedBy(CtNewArray.class);
}
@Test
public void testCtAnnotationAPI() throws Exception {
Factory factory = ModelUtils.createFactory();
CtAnnotation<Annotation> annotation = factory.Core().createAnnotation();
annotation.addValue("integers", 7);
on(annotation).giveMeAnnotationValue("integers").isTypedBy(CtLiteral.class);
annotation.addValue("integers", 42);
on(annotation).giveMeAnnotationValue("integers").isTypedBy(CtNewArray.class);
annotation.addValue("classes", String.class);
on(annotation).giveMeAnnotationValue("classes").isTypedBy(CtFieldAccess.class);
annotation.addValue("classes", Integer.class);
on(annotation).giveMeAnnotationValue("classes").isTypedBy(CtNewArray.class);
annotation.addValue("field", AnnotationValuesTest.class.getDeclaredField("i"));
on(annotation).giveMeAnnotationValue("field").isTypedBy(CtFieldAccess.class);
}
@Test
public void testAnnotationFactory() throws Exception {
final Factory factory = createFactory();
final CtClass<Object> target = factory.Class().create("org.example.Tacos");
on(target).isNotAnnotated();
CtAnnotation<SuppressWarnings> annotation = factory.Annotation().annotate(target, SuppressWarnings.class, "value", "test");
on(target).giveMeAnnotation(SuppressWarnings.class);
on(annotation).giveMeAnnotationValue("value").isTypedBy(CtLiteral.class);
annotation = factory.Annotation().annotate(target, SuppressWarnings.class, "value", "test2");
on(annotation).giveMeAnnotationValue("value").isTypedBy(CtNewArray.class);
}
@Test
public void testAnnotateWithEnum() throws Exception {
final Factory factory = createFactory();
final CtClass<Object> target = factory.Class().create("org.example.Tacos");
final CtField<String> field = factory.Field().create(target, new HashSet<>(), factory.Type().STRING, "field");
target.addField(field);
final CtAnnotation<BoundNumber> byteOrder = factory.Annotation().annotate(field, BoundNumber.class, "byteOrder", BoundNumber.ByteOrder.LittleEndian);
assertEquals(byteOrder, on(field).giveMeAnnotation(BoundNumber.class));
assertTrue(on(byteOrder).giveMeAnnotationValue("byteOrder").element instanceof CtFieldRead);
}
@Test
public void testAnnotationPrintAnnotation() throws Exception {
Launcher launcher = new Launcher();
launcher.addInputResource("src/test/resources/printer-test/spoon/test/AnnotationSpecTest.java");
launcher.getEnvironment().setNoClasspath(true);
launcher.buildModel();
assertEquals(strCtClassOracle,
launcher.getFactory().Class().getAll().get(0).getElements(new TypeFilter<>(CtClass.class)).get(2).toString());
}
private static final String nl = System.lineSeparator();
private static final String strCtClassOracle = "@com.squareup.javapoet.AnnotationSpecTest.HasDefaultsAnnotation(o = com.squareup.javapoet.AnnotationSpecTest.Breakfast.PANCAKES, p = 1701, f = 11.1, m = { 9 , 8 , 1 }, l = java.lang.Override.class, j = @com.squareup.javapoet.AnnotationSpecTest.AnnotationA" + nl +
", q = @com.squareup.javapoet.AnnotationSpecTest.AnnotationC(value = \"bar\")" + nl +
", r = { java.lang.Float.class , java.lang.Double.class })" + nl +
"public class IsAnnotated {}";
static class Request {
private static Request myself = new Request();
private static CtElement element;
public static Request on(CtElement ctElement) {
assertNotNull(ctElement);
element = ctElement;
return myself;
}
public <A extends Annotation> CtAnnotation<? extends Annotation> giveMeAnnotation(Class<A> annotation) {
for (CtAnnotation<? extends Annotation> ctAnnotation : element.getAnnotations()) {
if (ctAnnotation.getActualAnnotation().annotationType().equals(annotation)) {
return ctAnnotation;
}
}
fail("Annotation isn't present on the current element.");
return null;
}
public Request giveMeAnnotationValue(String key) {
assertTrue("Element given in the method on should be an CtAnnotation.", element instanceof CtAnnotation);
CtAnnotation<?> ctAnnotation = (CtAnnotation<?>) element;
CtExpression value = null;
try {
value = ctAnnotation.getValue(key);
} catch (ClassCastException e) {
fail("Value of the given key can't be cast to an expression.");
}
assertNotNull(value);
element = value;
return myself;
}
public <T extends CtElement> Request isTypedBy(Class<T> expectedType) {
try {
expectedType.cast(element);
} catch (ClassCastException e) {
fail("The given element can't be cast by the given type.");
}
return myself;
}
public Request isNotAnnotated() {
assertEquals(0, element.getAnnotations().size());
return myself;
}
}
}