Test framework fix: Load kotlin test classes in separate class loader

This commit is contained in:
Mikhael Bogdanov
2013-10-11 13:41:08 +04:00
parent 7d7352954e
commit 6154464050
11 changed files with 118 additions and 30 deletions
@@ -229,8 +229,10 @@ public class AnnotationGenTest extends CodegenTestCase {
Class[] interfaces = aClass.getInterfaces();
assertEquals(2, interfaces.length);
assertEquals(0, aClass.getDeclaredMethods().length);
assertTrue(Annotation.class == interfaces[0] || Annotation.class == interfaces[1]);
assertTrue(JetObject.class == interfaces[0] || JetObject.class == interfaces[1]);
Class annotationClass = getCorrespondingClass(Annotation.class);
Class jetObjectClass = getCorrespondingClass(JetObject.class);
assertTrue(annotationClass == interfaces[0] || annotationClass == interfaces[1]);
assertTrue(jetObjectClass == interfaces[0] || jetObjectClass == interfaces[1]);
assertTrue(aClass.isAnnotation());
}
@@ -0,0 +1,46 @@
package org.jetbrains.jet.codegen;
import junit.framework.Assert;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import static junit.framework.Assert.*;
public class ClassLoaderIsolationUtil {
public static void assertEquals(Class<?> expected, Class<?> actual) {
if (actual == null) {
assertNull(expected);
}
else Assert.assertEquals(getClassFromClassLoader(expected, actual.getClassLoader()), actual);
}
public static Class<? extends Annotation> getAnnotationClass(Class<? extends Annotation> annotationClass, ClassLoader classLoader) {
return (Class<? extends Annotation>) getClassFromClassLoader(annotationClass, classLoader);
}
public static Object getAnnotationAttribute(Object annotation, String name) {
try {
return annotation.getClass().getMethod(name).invoke(annotation);
}
catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
return null;
}
@NotNull
public static Class<?> getClassFromClassLoader(Class<?> classForName, ClassLoader classLoader) {
try {
return classLoader.loadClass(classForName.getName());
}
catch (ClassNotFoundException e) {
e.printStackTrace();
fail(e.getMessage());
}
return null;
}
}
@@ -32,7 +32,7 @@ public class ClassPathInParentClassLoaderTest extends CodegenTestCase {
@NotNull
@Override
protected GeneratedClassLoader createClassLoader(@NotNull ClassFileFactory factory) {
ClassLoader parentClassLoader = new URLClassLoader(getClassPathURLs(), CodegenTestCase.class.getClassLoader());
ClassLoader parentClassLoader = new URLClassLoader(getClassPathURLs(), null);
initializedClassLoader = new GeneratedClassLoader(factory, parentClassLoader);
return initializedClassLoader;
}
@@ -25,12 +25,14 @@ import org.jetbrains.jet.JetTestCaseBuilder;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys;
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.utils.ExceptionUtils;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
@@ -109,7 +111,7 @@ public abstract class CodegenTestCase extends UsefulTestCase {
fail("Double initialization of class loader in same test");
}
initializedClassLoader = new GeneratedClassLoader(factory, CodegenTestCase.class.getClassLoader(), getClassPathURLs());
initializedClassLoader = new GeneratedClassLoader(factory, null, getClassPathURLs());
return initializedClassLoader;
}
@@ -123,6 +125,13 @@ public abstract class CodegenTestCase extends UsefulTestCase {
throw new RuntimeException(e);
}
}
try {
//add runtime library
urls.add(ForTestCompileRuntime.runtimeJarForTests().toURI().toURL());
}
catch (MalformedURLException e) {
throw new RuntimeException(e);
}
return urls.toArray(new URL[urls.size()]);
}
@@ -201,4 +210,12 @@ public abstract class CodegenTestCase extends UsefulTestCase {
}
return method;
}
public Class<? extends Annotation> getCorrespondingAnnotationClass(Class<? extends Annotation> classForName) {
return ClassLoaderIsolationUtil.getAnnotationClass(classForName, initializedClassLoader);
}
public Class<?> getCorrespondingClass(Class<?> classForName) {
return ClassLoaderIsolationUtil.getClassFromClassLoader(classForName, initializedClassLoader);
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
import org.junit.Test;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class JUnitUsageGenTest extends CodegenTestCase {
@@ -49,8 +50,9 @@ public class JUnitUsageGenTest extends CodegenTestCase {
Class<?> namespaceClass = generateNamespaceClass();
Method method = namespaceClass.getMethod("foo", Method.class);
method.setAccessible(true);
Test annotation = method.getAnnotation(Test.class);
assertEquals(annotation.timeout(), 0l);
assertEquals(annotation.expected(), Test.None.class);
Annotation annotation = method.getAnnotation(getCorrespondingAnnotationClass(Test.class));
assertEquals(ClassLoaderIsolationUtil.getAnnotationAttribute(annotation, "timeout"), 0l);
ClassLoaderIsolationUtil.assertEquals(Test.None.class, (Class<?>) ClassLoaderIsolationUtil.getAnnotationAttribute(annotation,
"expected"));
}
}
@@ -104,9 +104,9 @@ public class JetValueParameterAnnotationTest extends CodegenTestCase {
for (int i = 0, length = annotations.length; i < length; i++) {
assertSize(1, annotations[i]);
Annotation annotation = annotations[i][0];
assertEquals(JetValueParameter.class, annotation.annotationType());
assertEquals(expected[i].name(), ((JetValueParameter) annotation).name());
assertEquals(expected[i].type(), ((JetValueParameter) annotation).type());
ClassLoaderIsolationUtil.assertEquals(JetValueParameter.class, annotation.annotationType());
assertEquals(expected[i].name(), ClassLoaderIsolationUtil.getAnnotationAttribute(annotation, "name"));
assertEquals(expected[i].type(), ClassLoaderIsolationUtil.getAnnotationAttribute(annotation, "type"));
}
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.jet.descriptors.serialization.JavaProtoBufUtil;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;
@@ -47,10 +48,11 @@ public class KotlinClassAnnotationTest extends CodegenTestCase {
"}\n");
Class aClass = generateClass(NAMESPACE_NAME + "." + CLASS_NAME);
assertTrue(aClass.isAnnotationPresent(KotlinClass.class));
KotlinClass kotlinClass = (KotlinClass) aClass.getAnnotation(KotlinClass.class);
Class<? extends Annotation> annotationClass = getCorrespondingAnnotationClass(KotlinClass.class);
assertTrue(aClass.isAnnotationPresent(annotationClass));
Annotation kotlinClass = aClass.getAnnotation(annotationClass);
ClassData data = JavaProtoBufUtil.readClassDataFrom(kotlinClass.data());
ClassData data = JavaProtoBufUtil.readClassDataFrom((String[]) ClassLoaderIsolationUtil.getAnnotationAttribute(kotlinClass, "data"));
Set<String> callableNames = collectCallableNames(data.getClassProto().getMemberList(), data.getNameResolver());
assertSameElements(Arrays.asList("foo", "bar"), callableNames);
@@ -19,13 +19,11 @@ package org.jetbrains.jet.codegen;
import jet.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.ConfigurationKind;
import org.jetbrains.jet.descriptors.serialization.JavaProtoBufUtil;
import org.jetbrains.jet.descriptors.serialization.NameResolver;
import org.jetbrains.jet.descriptors.serialization.PackageData;
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
import org.jetbrains.jet.descriptors.serialization.*;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -51,10 +49,14 @@ public class KotlinPackageAnnotationTest extends CodegenTestCase {
"object C\n");
Class aClass = generateClass(PackageClassUtils.getPackageClassFqName(NAMESPACE_NAME).asString());
assertTrue(aClass.isAnnotationPresent(KotlinPackage.class));
KotlinPackage kotlinPackage = (KotlinPackage) aClass.getAnnotation(KotlinPackage.class);
Class<? extends Annotation> annotationClass = getCorrespondingAnnotationClass(KotlinPackage.class);
assertTrue(aClass.isAnnotationPresent(annotationClass));
assertTrue(aClass.isAnnotationPresent(annotationClass));
PackageData data = JavaProtoBufUtil.readPackageDataFrom(kotlinPackage.data());
Annotation kotlinPackage = aClass.getAnnotation(annotationClass);
PackageData data = JavaProtoBufUtil.readPackageDataFrom((String[]) ClassLoaderIsolationUtil.getAnnotationAttribute(kotlinPackage,
"data"));
Set<String> callableNames = collectCallableNames(data.getPackageProto().getMemberList(), data.getNameResolver());
assertSameElements(Arrays.asList("foo", "bar", "C"), callableNames);
@@ -23,6 +23,8 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.lang.annotation.Annotation;
public class KotlinPackageFragmentAnnotationTest extends CodegenTestCase {
public static final FqName NAMESPACE_NAME = new FqName("test");
@@ -42,12 +44,17 @@ public class KotlinPackageFragmentAnnotationTest extends CodegenTestCase {
// The file which is not a facade is a package fragment
String fqName = fileName.substring(0, fileName.length() - ".class".length()).replace('/', '.');
Class aClass = generateClass(fqName);
assertTrue("No KotlinPackageFragment annotation on a package fragment",
aClass.isAnnotationPresent(KotlinPackageFragment.class));
KotlinPackageFragment annotation = (KotlinPackageFragment) aClass.getAnnotation(KotlinPackageFragment.class);
Class<? extends Annotation> annotationClass = getCorrespondingAnnotationClass(KotlinPackageFragment.class);
assertTrue("No KotlinPackageFragment annotation on a package fragment",
aClass.isAnnotationPresent(annotationClass));
Annotation kotlinPackageFragment = aClass.getAnnotation(annotationClass);
assertTrue("KotlinPackageFragment annotation is written with an unsupported format",
AbiVersionUtil.isAbiVersionCompatible(annotation.abiVersion()));
AbiVersionUtil.isAbiVersionCompatible(
(Integer) ClassLoaderIsolationUtil.getAnnotationAttribute(kotlinPackageFragment, "abiVersion")));
return;
}
@@ -414,10 +414,11 @@ public class NamespaceGenTest extends CodegenTestCase {
public void testIntRange() throws Exception {
loadText("fun foo() = 1..10");
Method main = generateFunction();
IntRange result = (IntRange) main.invoke(null);
assertTrue(result.contains(1));
assertTrue(result.contains(10));
assertFalse(result.contains(11));
Object result = main.invoke(null);
Method contains = result.getClass().getMethod("contains", Integer.TYPE);
assertTrue((Boolean) contains.invoke(result, 1));
assertTrue((Boolean) contains.invoke(result, 10));
assertFalse((Boolean) contains.invoke(result, 11));
}
public void testSubstituteJavaMethodTypeParameters() throws Exception {
@@ -108,8 +108,17 @@ public class TestlibTest extends UsefulTestCase {
ClassFileFactory classFileFactory = generationState.getFactory();
classLoader = new GeneratedClassLoader(classFileFactory,
new URLClassLoader(new URL[] {ForTestCompileRuntime.runtimeJarForTests().toURI().toURL(), junitJar.toURI().toURL()},
TestCase.class.getClassLoader()));
new URLClassLoader(new URL[] {ForTestCompileRuntime.runtimeJarForTests().toURI().toURL()},
null)) {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("junit.") || name.startsWith("org.junit.")) {
//In other way we don't find any test cause will have two different TestCase classes!
return TestlibTest.class.getClassLoader().loadClass(name);
}
return super.loadClass(name);
}
};
typeMapper = generationState.getTypeMapper();