package xapi.bytecode.impl;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import xapi.source.X_Source;
import xapi.source.api.HasAnnotations;
import xapi.source.api.IsAnnotation;
import xapi.source.api.IsAnnotationValue;
import xapi.source.api.IsClass;
import xapi.source.api.IsField;
import xapi.source.api.IsMethod;
/**
* A runtime-level annotation
*/
@Retention(RetentionPolicy.RUNTIME)
@interface Runtime{}
@Retention(RetentionPolicy.CLASS)
@interface Compiletime{}
/**
* A test class containing a spattering of member types we need to handle.
*
* @author "James X. Nelson (james@wetheinter.net)"
*
*/
@SuppressWarnings("serial")
@Runtime
@Compiletime
class OuterTestClass implements Serializable {
public static class StaticInnerClass <T> implements Serializable{}
class InnerClass <T extends Serializable> implements Serializable {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
private static @interface StaticInnerAnno{
Class<?>[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({})
static @interface NoTargetAnno{
Class<?>[] value() default {};
}
@Retention(RetentionPolicy.RUNTIME)
@interface InnerAnno {
StaticInnerAnno staticAnno() default @StaticInnerAnno({
StaticInnerClass.class, InnerClass.class});
}
@InnerAnno(staticAnno=@StaticInnerAnno({}))
private static void staticMethod(){}
@StaticInnerAnno(OuterTestClass.class)
public void instanceMethod(){}
static String staticField = "withInitializer";
static Class<?>[] staticClasses = {Class.class};
@SuppressWarnings({ "unchecked", "unused" })
private InnerClass<StaticInnerClass<InnerClass<OuterTestClass>>>[] instanceField =
(InnerClass<StaticInnerClass<InnerClass<OuterTestClass>>>[])new InnerClass[0];
OuterTestClass() {}
}
public class BytecodeAdapterServiceTest {
private static BytecodeAdapterService service;
@BeforeClass
public static void extractClassFile() {
service = new BytecodeAdapterService();
}
@Test
public void testArrayParser() {
IsClass clsArray = service.toClass("java.lang.Class[]");
Assert.assertNotNull(clsArray);
}
@Test
public void testAnnoNoArgs() {
IsClass asClass = service.toClass(OuterTestClass.NoTargetAnno.class.getName());
IsAnnotation anno = asClass.getAnnotation(Target.class.getName());
IsAnnotationValue empty = anno.getValue(anno.getMethod("value"));
Assert.assertTrue(empty.isArray());
Assert.assertEquals(0, Array.getLength(empty.getRawValue()));
}
@Test
public void testTestClass() {
Class<?> cls = getTestClass();
IsClass asClass = service.toClass(cls.getName());
Assert.assertEquals(asClass.getPackage(), cls.getPackage().getName());
Assert.assertEquals(asClass.getEnclosedName(), X_Source.classToEnclosedSourceName(cls));
Assert.assertEquals(asClass.getModifier(), cls.getModifiers());
testAnnos(cls.getDeclaredAnnotations(), asClass);
}
@Test
public void testTestClass_Methods() {
Class<?> cls = getTestClass();
IsClass asClass = service.toClass(cls.getName());
for (Method method : cls.getMethods()) {
IsMethod imethod = asClass.getMethod(method.getName(), true, method.getParameterTypes());
String testCase = imethod.getQualifiedName() +" != "+method.getName();
Assert.assertNotNull(testCase, imethod);
Assert.assertEquals(testCase, method.getName(), imethod.getName());
Assert.assertEquals(testCase, method.getModifiers(), imethod.getModifier());
Assert.assertEquals(testCase, imethod.getReturnType().getQualifiedName(), method.getReturnType().getCanonicalName());
Assert.assertTrue(testCase, X_Source.typesEqual(imethod.getParameters(), method.getParameterTypes()));
Assert.assertTrue(testCase, X_Source.typesEqual(imethod.getExceptions(), method.getExceptionTypes()));
testAnnos(method.getDeclaredAnnotations(), imethod);
}
}
@Test
public void testTestClass_Fields() {
Class<?> cls = getTestClass();
IsClass asClass = service.toClass(cls.getName());
for (Field field : cls.getFields()) {
IsField ifield = asClass.getField(field.getName());
Assert.assertNotNull(field.getName(), ifield);
Assert.assertEquals(field.getName(), ifield.getName());
Assert.assertEquals(field.getModifiers(), ifield.getModifier());
testAnnos(field.getDeclaredAnnotations(), ifield);
}
}
private void testAnnos(Annotation[] runtimeAnnotations, HasAnnotations hasAnnos) {
for (Annotation anno : runtimeAnnotations) {
IsAnnotation isAnno = hasAnnos.getAnnotation(anno.annotationType().getCanonicalName());
Assert.assertNotNull("Missing annotation "+anno+" on "+hasAnnos,isAnno);
Assert.assertEquals(anno.annotationType().getCanonicalName(), isAnno.getQualifiedName());
}
int cnt = 0;
for (IsAnnotation anno : hasAnnos.getAnnotations()) {
if (anno.isRuntime()) // classes only have runtime; we have runtime and compile time.
cnt++;
}
Assert.assertEquals(runtimeAnnotations.length, cnt);
}
protected Class<?> getTestClass() {
return OuterTestClass.class;
}
}