Add different tests on class loaders in reflection

This commit is contained in:
Alexander Udalov
2015-04-02 18:35:12 +03:00
parent 87ef4ff7c5
commit 47e7235e64
5 changed files with 131 additions and 11 deletions
@@ -25,11 +25,11 @@ import java.util.List;
import java.util.jar.Manifest;
public class GeneratedClassLoader extends URLClassLoader {
private ClassFileFactory state;
private ClassFileFactory factory;
public GeneratedClassLoader(@NotNull ClassFileFactory state, ClassLoader parentClassLoader, URL...urls) {
public GeneratedClassLoader(@NotNull ClassFileFactory factory, ClassLoader parentClassLoader, URL... urls) {
super(urls, parentClassLoader);
this.state = state;
this.factory = factory;
}
@NotNull
@@ -37,7 +37,7 @@ public class GeneratedClassLoader extends URLClassLoader {
protected Class<?> findClass(@NotNull String name) throws ClassNotFoundException {
String classFilePath = name.replace('.', '/') + ".class";
OutputFile outputFile = state.get(classFilePath);
OutputFile outputFile = factory.get(classFilePath);
if (outputFile != null) {
byte[] bytes = outputFile.asByteArray();
int lastDot = name.lastIndexOf('.');
@@ -54,11 +54,11 @@ public class GeneratedClassLoader extends URLClassLoader {
}
public void dispose() {
state = null;
factory = null;
}
@NotNull
public List<OutputFile> getAllGeneratedFiles() {
return state.asList();
return factory.asList();
}
}
@@ -0,0 +1,23 @@
package test
import kotlin.reflect.KClass
import kotlin.test.*
class K(val p: String)
class Test {
fun kClass(): Any = K::class
fun doTest(k1: KClass<*>, k2: KClass<*>) {
// KClass instances for classes loaded with different class loaders should have the same string representation,
// but should not be equal
assertEquals("$k1", "$k2")
assertNotEquals(k1, k2)
// The same for properties of these classes
val p1 = k1.properties.first()
val p2 = k2.properties.first()
assertEquals("$p1", "$p2")
assertNotEquals(p1, p2)
}
}
@@ -0,0 +1,15 @@
package test
import kotlin.reflect.KClass
import kotlin.test.*
class K
class Test {
fun kClass(): Any = K::class
fun doTest(k1: KClass<*>, k2: KClass<*>) {
// KClass instances should be equal for classes loaded with the child and the parent
assertEquals(k1, k2)
}
}
@@ -23,7 +23,6 @@ import com.intellij.testFramework.UsefulTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.cli.jvm.config.ConfigPackage;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.FqName;
@@ -133,10 +132,9 @@ public abstract class CodegenTestCase extends UsefulTestCase {
fail("Double initialization of class loader in same test");
}
ClassFileFactory factory = generateClassesInFile();
initializedClassLoader = new GeneratedClassLoader(factory, ForTestCompileRuntime.runtimeJarClassLoader(), getClassPathURLs());
initializedClassLoader = createClassLoader();
if (!verifyAllFilesWithAsm(factory, initializedClassLoader)) {
if (!verifyAllFilesWithAsm(generateClassesInFile(), initializedClassLoader)) {
fail("Verification failed: see exceptions above");
}
@@ -144,7 +142,12 @@ public abstract class CodegenTestCase extends UsefulTestCase {
}
@NotNull
protected URL[] getClassPathURLs() {
protected GeneratedClassLoader createClassLoader() {
return new GeneratedClassLoader(generateClassesInFile(), ForTestCompileRuntime.runtimeJarClassLoader(), getClassPathURLs());
}
@NotNull
private URL[] getClassPathURLs() {
List<URL> urls = Lists.newArrayList();
for (File file : getJvmClasspathRoots(myEnvironment.getConfiguration())) {
try {
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.test.ConfigurationKind
public class ReflectionClassLoaderTest : CodegenTestCase() {
override fun getPrefix() = "reflection/classLoaders"
override fun setUp() {
super.setUp()
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL)
}
private fun Class<*>.methodByName(name: String) = getDeclaredMethods().single { it.getName() == name }
fun doTest(cl1: ClassLoader, cl2: ClassLoader) {
val t1 = cl1.loadClass("test.Test")
val t2 = cl2.loadClass("test.Test")
fun Class<*>.getKClass() = methodByName("kClass")(newInstance())
t1.methodByName("doTest")(t1.newInstance(), t1.getKClass(), t2.getKClass())
}
fun testSimpleDifferentClassLoaders() {
loadFile(getPrefix() + "/differentClassLoaders.kt")
doTest(
createClassLoader(),
createClassLoader()
)
}
fun testClassLoaderWithNonTrivialEqualsAndHashCode() {
// Check that class loaders do not participate as keys in hash maps (use identity hash maps instead)
loadFile(getPrefix() + "/differentClassLoaders.kt")
class BrokenEqualsClassLoader(parent: ClassLoader) : ClassLoader(parent) {
override fun equals(other: Any?) = true
override fun hashCode() = 0
}
doTest(
BrokenEqualsClassLoader(createClassLoader()),
BrokenEqualsClassLoader(createClassLoader())
)
}
fun testParentFirst() {
// Check that for a child class loader, a class reference would be the same as for his parent
loadFile(getPrefix() + "/parentFirst.kt")
class ChildClassLoader(parent: ClassLoader) : ClassLoader(parent)
val parent = createClassLoader()
doTest(
parent,
ChildClassLoader(parent)
)
}
}