package rocks.inspectit.agent.java.instrumentation.asm;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import info.novatec.inspectit.org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.Retention;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import rocks.inspectit.shared.all.instrumentation.classcache.AnnotationType;
import rocks.inspectit.shared.all.instrumentation.classcache.ClassType;
import rocks.inspectit.shared.all.instrumentation.classcache.ImmutableType;
import rocks.inspectit.shared.all.instrumentation.classcache.InterfaceType;
import rocks.inspectit.shared.all.instrumentation.classcache.MethodType;
import rocks.inspectit.shared.all.instrumentation.classcache.Modifiers;
/**
* Test for the {@link ClassAnalyzer}.
*
* @author Ivan Senic
*
*/
@SuppressWarnings("PMD")
public class ClassAnalyzerTest {
/**
* Hash to be used for testing purposes.
*/
protected static final String HASH = "MyHash";
/**
* Class being tested.
*/
protected ClassAnalyzer classAnalyzer;
/**
* Init.
*/
@BeforeMethod
public void init() {
classAnalyzer = new ClassAnalyzer(HASH);
}
public class Analyze extends ClassAnalyzerTest {
/**
* Testing the correct parsing of {@link TestAnnotation}.
*/
@Test
public void theAnnotation() throws IOException {
ClassReader classReader = new ClassReader(TestAnnotation.class.getName());
classReader.accept(classAnalyzer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
ImmutableType immutableType = classAnalyzer.getType();
assertThat(immutableType, is(instanceOf(AnnotationType.class)));
AnnotationType type = (AnnotationType) immutableType;
// name
assertThat(type.getFQN(), is(equalTo(TestAnnotation.class.getName())));
assertThat(type.isInitialized(), is(true));
// modifiers
assertThat(Modifiers.isPublic(type.getModifiers()), is(true));
// only one hash when analyzed
assertThat(type.getHashes(), hasSize(1));
assertThat(type.getHashes(), hasItem(HASH));
// @Retention annotation
assertThat(type.getAnnotations(), hasSize(1));
assertThat(type.getAnnotations().iterator().next().getFQN(), is(equalTo(Retention.class.getName())));
// other
assertThat(type.getAnnotatedTypes(), is(not(nullValue())));
assertThat(type.getAnnotatedTypes(), is(empty()));
assertThat(type.getRealizingClasses(), is(not(nullValue())));
assertThat(type.getRealizingClasses(), is(empty()));
}
/**
* Testing the correct parsing of {@link TestInterface}.
*/
@Test
public void theInterface() throws IOException {
ClassReader classReader = new ClassReader(TestInterface.class.getName());
classReader.accept(classAnalyzer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
ImmutableType immutableType = classAnalyzer.getType();
assertThat(immutableType, is(instanceOf(InterfaceType.class)));
InterfaceType type = (InterfaceType) immutableType;
assertThat(type.getFQN(), is(equalTo(TestInterface.class.getName())));
assertThat(type.isInitialized(), is(true));
// modifiers
assertThat(Modifiers.isPublic(type.getModifiers()), is(false));
assertThat(Modifiers.isPrivate(type.getModifiers()), is(false));
assertThat(Modifiers.isProtected(type.getModifiers()), is(false));
// only one hash when analyzed
assertThat(type.getHashes(), hasSize(1));
assertThat(type.getHashes(), hasItem(HASH));
// @TestAnnotation annotation
assertThat(type.getAnnotations(), hasSize(1));
AnnotationType annotation = type.getAnnotations().iterator().next();
assertThat(annotation.getFQN(), is(equalTo(TestAnnotation.class.getName())));
assertThat(annotation.isInitialized(), is(false));
// super interface(s)
assertThat(type.getSuperInterfaces(), hasSize(1));
InterfaceType superInterface = type.getSuperInterfaces().iterator().next();
assertThat(superInterface.getFQN(), is(equalTo(Serializable.class.getName())));
assertThat(superInterface.isInitialized(), is(false));
// other
assertThat(type.getRealizingClasses(), is(not(nullValue())));
assertThat(type.getRealizingClasses(), is(empty()));
assertThat(type.getSubInterfaces(), is(not(nullValue())));
assertThat(type.getSubInterfaces(), is(empty()));
// method
assertThat(type.getMethods(), hasSize(1));
MethodType method = type.getMethods().iterator().next();
assertThat(method.getName(), is(equalTo("method1")));
assertThat(Modifiers.isPublic(method.getModifiers()), is(true));
assertThat(method.getMethodCharacter(), is(MethodType.Character.METHOD));
assertThat(method.getReturnType(), is(String.class.getName()));
assertThat(method.getAnnotations(), hasSize(1));
assertThat(method.getAnnotations().iterator().next().getFQN(), is(equalTo(TestAnnotation.class.getName())));
assertThat(method.getParameters(), hasSize(4));
assertThat(method.getParameters().get(0), is("int"));
assertThat(method.getParameters().get(1), is("long[]"));
assertThat(method.getParameters().get(2), is(String.class.getName()));
assertThat(method.getParameters().get(3), is(Object.class.getName() + "[][][]"));
}
/**
* Testing the correct parsing of {@link AbstractTestClass}.
*/
@Test
public void theAbstractClass() throws IOException {
ClassReader classReader = new ClassReader(AbstractTestClass.class.getName());
classReader.accept(classAnalyzer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
ImmutableType immutableType = classAnalyzer.getType();
assertThat(immutableType, is(instanceOf(ClassType.class)));
ClassType type = (ClassType) immutableType;
assertThat(type.getFQN(), is(equalTo(AbstractTestClass.class.getName())));
assertThat(type.isInitialized(), is(true));
// modifiers
assertThat(Modifiers.isAbstract(type.getModifiers()), is(true));
// only one hash when analyzed
assertThat(type.getHashes(), hasSize(1));
assertThat(type.getHashes(), hasItem(HASH));
// super class is Object
assertThat(type.getSuperClasses(), hasSize(1));
ClassType superClass = type.getSuperClasses().iterator().next();
assertThat(superClass.getFQN(), is(equalTo(Object.class.getName())));
assertThat(superClass.isInitialized(), is(false));
// other
assertThat(type.getRealizedInterfaces(), is(not(nullValue())));
assertThat(type.getRealizedInterfaces(), is(empty()));
assertThat(type.getSubClasses(), is(not(nullValue())));
assertThat(type.getSubClasses(), is(empty()));
// note that there is method + no-arg constructor
assertThat(type.getMethods(), hasSize(2));
MethodType method = null;
MethodType constructor = null;
for (MethodType methodType : type.getMethods()) {
if (methodType.getMethodCharacter().equals(MethodType.Character.CONSTRUCTOR)) {
constructor = methodType;
} else if (methodType.getMethodCharacter().equals(MethodType.Character.METHOD)) {
method = methodType;
}
}
// check constructor
assertThat(constructor.getName(), is(equalTo("<init>")));
assertThat(constructor.getMethodCharacter(), is(MethodType.Character.CONSTRUCTOR));
assertThat(constructor.getReturnType(), is("void"));
assertThat(constructor.getAnnotations(), is(empty()));
assertThat(constructor.getParameters(), is(empty()));
// check method
assertThat(method.getName(), is(equalTo("method0")));
assertThat(Modifiers.isProtected(method.getModifiers()), is(true));
assertThat(Modifiers.isAbstract(method.getModifiers()), is(true));
assertThat(method.getMethodCharacter(), is(MethodType.Character.METHOD));
assertThat(method.getReturnType(), is("void"));
assertThat(method.getAnnotations(), is(empty()));
assertThat(method.getParameters(), is(empty()));
}
/**
* Testing the correct parsing of {@link TestClass}.
*/
@Test
public void theClass() throws IOException {
ClassReader classReader = new ClassReader(TestClass.class.getName());
classReader.accept(classAnalyzer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
ImmutableType immutableType = classAnalyzer.getType();
assertThat(immutableType, is(instanceOf(ClassType.class)));
ClassType type = (ClassType) immutableType;
assertThat(type.getFQN(), is(equalTo(TestClass.class.getName())));
assertThat(type.isInitialized(), is(true));
// modifiers
assertThat(Modifiers.isAbstract(type.getModifiers()), is(false));
assertThat(Modifiers.isFinal(type.getModifiers()), is(true));
assertThat(Modifiers.isPublic(type.getModifiers()), is(true));
// only one hash when analyzed
assertThat(type.getHashes(), hasSize(1));
assertThat(type.getHashes(), hasItem(HASH));
// super class is AbstractTestClass
assertThat(type.getSuperClasses(), hasSize(1));
ClassType superClass = type.getSuperClasses().iterator().next();
assertThat(superClass.getFQN(), is(equalTo(AbstractTestClass.class.getName())));
assertThat(superClass.isInitialized(), is(false));
// has one interface
assertThat(type.getRealizedInterfaces(), hasSize(2));
assertThat(type.getRealizedInterfaces(), hasItem(new InterfaceType(TestInterface.class.getName())));
assertThat(type.getRealizedInterfaces(), hasItem(new InterfaceType(TestAnnotation.class.getName())));
// other
assertThat(type.getSubClasses(), is(not(nullValue())));
assertThat(type.getSubClasses(), is(empty()));
// note that there are methods + no-arg constructor
assertThat(type.getMethods(), hasSize(6));
MethodType method0 = null;
MethodType method1 = null;
MethodType methodWithException = null;
MethodType constructor = null;
// ignoring the methods from annotation
for (MethodType methodType : type.getMethods()) {
if (methodType.getMethodCharacter().equals(MethodType.Character.CONSTRUCTOR)) {
constructor = methodType;
} else if (methodType.getMethodCharacter().equals(MethodType.Character.METHOD) && "method0".equals(methodType.getName())) {
method0 = methodType;
} else if (methodType.getMethodCharacter().equals(MethodType.Character.METHOD) && "method1".equals(methodType.getName())) {
method1 = methodType;
} else if (methodType.getMethodCharacter().equals(MethodType.Character.METHOD) && "methodWithException".equals(methodType.getName())) {
methodWithException = methodType;
}
}
// check constructor
assertThat(constructor.getName(), is(equalTo("<init>")));
assertThat(constructor.getMethodCharacter(), is(MethodType.Character.CONSTRUCTOR));
assertThat(Modifiers.isPublic(constructor.getModifiers()), is(true));
assertThat(constructor.getReturnType(), is("void"));
assertThat(constructor.getAnnotations(), is(empty()));
assertThat(constructor.getParameters(), is(empty()));
// check method0
assertThat(method0.getName(), is(equalTo("method0")));
assertThat(Modifiers.isProtected(method0.getModifiers()), is(true));
assertThat(method0.getMethodCharacter(), is(MethodType.Character.METHOD));
assertThat(method0.getReturnType(), is("void"));
assertThat(method0.getParameters(), is(empty()));
assertThat(method0.getAnnotations(), hasSize(1));
AnnotationType annotation = method0.getAnnotations().iterator().next();
assertThat(annotation.getFQN(), is(equalTo(TestAnnotation.class.getName())));
assertThat(annotation.isInitialized(), is(false));
// check method1
assertThat(method1.getName(), is(equalTo("method1")));
assertThat(Modifiers.isPublic(method1.getModifiers()), is(true));
assertThat(method1.getMethodCharacter(), is(MethodType.Character.METHOD));
assertThat(method1.getReturnType(), is(String.class.getName()));
assertThat(method1.getAnnotations(), hasSize(0));
assertThat(method1.getParameters(), hasSize(4));
assertThat(method1.getParameters().get(0), is("int"));
assertThat(method1.getParameters().get(1), is("long[]"));
assertThat(method1.getParameters().get(2), is(String.class.getName()));
assertThat(method1.getParameters().get(3), is(Object.class.getName() + "[][][]"));
// check method with exception
assertThat(methodWithException.getName(), is(equalTo("methodWithException")));
assertThat(methodWithException.getMethodCharacter(), is(MethodType.Character.METHOD));
assertThat(methodWithException.getReturnType(), is("void"));
assertThat(methodWithException.getParameters(), is(empty()));
assertThat(methodWithException.getExceptions(), hasSize(1));
ClassType exception = methodWithException.getExceptions().iterator().next();
assertThat(exception.getFQN(), is(equalTo(Exception.class.getName())));
assertThat(exception.isInitialized(), is(false));
}
@Test
public void innerClass() throws Exception {
ClassReader classReader = new ClassReader(TestClass.InnerClass.class.getName());
classReader.accept(classAnalyzer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
ImmutableType immutableType = classAnalyzer.getType();
assertThat(immutableType.getFQN(), is(TestClass.class.getName() + "$" + TestClass.InnerClass.class.getSimpleName()));
}
@Test
public void nestedClass() throws Exception {
ClassReader classReader = new ClassReader(TestClass.NestedClass.class.getName());
classReader.accept(classAnalyzer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
ImmutableType immutableType = classAnalyzer.getType();
assertThat(immutableType.getFQN(), is(TestClass.class.getName() + "$" + TestClass.NestedClass.class.getSimpleName()));
}
}
}