diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index 7f14f98e2d0..c290780e61c 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -246,22 +246,26 @@ public class KotlinToJVMBytecodeCompiler { return null; } + GeneratedClassLoader classLoader = null; try { ClassFileFactory factory = generationState.getFactory(); - try { - GeneratedClassLoader classLoader = new GeneratedClassLoader(factory, new URLClassLoader(new URL[]{ + classLoader = new GeneratedClassLoader(factory, + new URLClassLoader(new URL[] { // TODO: add all classpath paths.getRuntimePath().toURI().toURL() - }, - parentLoader == null ? AllModules.class.getClassLoader() : parentLoader)); - JetFile scriptFile = environment.getSourceFiles().get(0); - return classLoader.loadClass(ScriptNameUtil.classNameForScript(scriptFile)); - } - catch (Exception e) { - throw new RuntimeException("Failed to evaluate script: " + e, e); - } + }, + parentLoader == null ? AllModules.class.getClassLoader() : parentLoader)); + + JetFile scriptFile = environment.getSourceFiles().get(0); + return classLoader.loadClass(ScriptNameUtil.classNameForScript(scriptFile)); + } + catch (Exception e) { + throw new RuntimeException("Failed to evaluate script: " + e, e); } finally { + if (classLoader != null) { + classLoader.dispose(); + } generationState.destroy(); } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 9b4ee940212..cc1119deaf3 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -192,7 +192,7 @@ public class ClassGenTest extends CodegenTestCase { public void testAbstractClass() throws Exception { loadText("abstract class SimpleClass() { }"); - final Class aClass = createClassLoader(generateClassesInFile()).loadClass("SimpleClass"); + final Class aClass = generateClass("SimpleClass"); assertTrue((aClass.getModifiers() & Modifier.ABSTRACT) != 0); } @@ -240,7 +240,7 @@ public class ClassGenTest extends CodegenTestCase { public void testEnumClass() throws Exception { loadText("enum class Direction { NORTH; SOUTH; EAST; WEST }"); - final Class direction = createClassLoader(generateClassesInFile()).loadClass("Direction"); + final Class direction = generateClass("Direction"); final Field north = direction.getField("NORTH"); assertEquals(direction, north.getType()); assertInstanceOf(north.get(null), direction); @@ -248,7 +248,7 @@ public class ClassGenTest extends CodegenTestCase { public void testEnumConstantConstructors() throws Exception { loadText("enum class Color(val rgb: Int) { RED: Color(0xFF0000); GREEN: Color(0x00FF00); }"); - final Class colorClass = createClassLoader(generateClassesInFile()).loadClass("Color"); + final Class colorClass = generateClass("Color"); final Field redField = colorClass.getField("RED"); final Object redValue = redField.get(null); final Method rgbMethod = colorClass.getMethod("getRgb"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index 31021fcab4b..14818b9544b 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -45,10 +45,7 @@ import org.jetbrains.jet.codegen.state.Progress; import java.io.File; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import java.lang.reflect.*; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -64,6 +61,7 @@ public abstract class CodegenTestCase extends UsefulTestCase { protected Object scriptInstance; private GenerationState alreadyGenerated; + private GeneratedClassLoader initializedClassLoader; protected void createEnvironmentWithMockJdkAndIdeaAnnotations() { if (myEnvironment != null) { @@ -108,6 +106,12 @@ public abstract class CodegenTestCase extends UsefulTestCase { myEnvironment = null; scriptInstance = null; alreadyGenerated = null; + + if (initializedClassLoader != null) { + initializedClassLoader.dispose(); + initializedClassLoader = null; + } + super.tearDown(); } @@ -279,8 +283,6 @@ public abstract class CodegenTestCase extends UsefulTestCase { } catch (Throwable e) { System.out.println(generateToText()); throw new RuntimeException(e); - } finally { - loader.dispose(); } } @@ -317,6 +319,10 @@ public abstract class CodegenTestCase extends UsefulTestCase { } protected GeneratedClassLoader createClassLoader(ClassFileFactory codegens, boolean classPathInTheSameClassLoader) { + if (initializedClassLoader != null) { + fail("Double initialization of class loader in same test"); + } + List urls = Lists.newArrayList(); for (File file : myEnvironment.getConfiguration().getList(JVMConfigurationKeys.CLASSPATH_KEY)) { try { @@ -326,15 +332,17 @@ public abstract class CodegenTestCase extends UsefulTestCase { } } - final URL[] urlsArray = urls.toArray(new URL[0]); + final URL[] urlsArray = urls.toArray(new URL[urls.size()]); if (!classPathInTheSameClassLoader) { ClassLoader parentClassLoader = new URLClassLoader(urlsArray, CodegenTestCase.class.getClassLoader()); - return new GeneratedClassLoader(codegens, parentClassLoader); + initializedClassLoader = new GeneratedClassLoader(codegens, parentClassLoader); } else { - return new GeneratedClassLoader(codegens, CodegenTestCase.class.getClassLoader(), urlsArray); + initializedClassLoader = new GeneratedClassLoader(codegens, CodegenTestCase.class.getClassLoader(), urlsArray); } + + return initializedClassLoader; } protected String generateToText() { @@ -370,7 +378,6 @@ public abstract class CodegenTestCase extends UsefulTestCase { protected Class generateNamespaceClass() { ClassFileFactory state = generateClassesInFile(); - return loadRootNamespaceClass(state); } @@ -477,5 +484,4 @@ public abstract class CodegenTestCase extends UsefulTestCase { protected Class loadImplementationClass(@NotNull ClassFileFactory codegens, final String name) { return loadClass(name, codegens); } - } diff --git a/compiler/tests/org/jetbrains/jet/codegen/EnumGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/EnumGenTest.java index 49fe0eea347..cbee3a1b598 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/EnumGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/EnumGenTest.java @@ -58,7 +58,7 @@ public class EnumGenTest extends CodegenTestCase { public void testEnumConstantConstructors() throws Exception { loadText("enum class Color(val rgb: Int) { RED: Color(0xFF0000); GREEN: Color(0x00FF00); }"); - final Class colorClass = createClassLoader(generateClassesInFile()).loadClass("Color"); + final Class colorClass = generateClass("Color"); final Field redField = colorClass.getField("RED"); final Object redValue = redField.get(null); final Method rgbMethod = colorClass.getMethod("getRgb"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java index fa8f7708ea0..087822005c2 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java @@ -145,25 +145,13 @@ public class StdlibTest extends CodegenTestCase { public void testKt1592 () throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { loadFile("regressions/kt1592.kt"); - ClassFileFactory codegens = generateClassesInFile(); - GeneratedClassLoader loader = createClassLoader(codegens); - - try { - String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFiles.getPsiFile())).getFqName().getFqName(); - Class namespaceClass = loader.loadClass(fqName); - Method method = namespaceClass.getMethod("box", Method.class); - method.setAccessible(true); - Test annotation = method.getAnnotation(Test.class); - assertEquals(annotation.timeout(), 0l); - assertEquals(annotation.expected(), Test.None.class); - } - catch (Throwable t) { - System.out.println(generateToText()); - throw new RuntimeException(t); - } - finally { - loader.dispose(); - } + String fqName = NamespaceCodegen.getJVMClassNameForKotlinNs(JetPsiUtil.getFQName(myFiles.getPsiFile())).getFqName().getFqName(); + Class namespaceClass = generateClass(fqName); + Method method = namespaceClass.getMethod("box", Method.class); + method.setAccessible(true); + Test annotation = method.getAnnotation(Test.class); + assertEquals(annotation.timeout(), 0l); + assertEquals(annotation.expected(), Test.None.class); } public void testAnnotationClassWithClassProperty() diff --git a/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java index f82be2afcbc..45e4b214bca 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/TestlibTest.java @@ -16,7 +16,9 @@ package org.jetbrains.jet.codegen; +import com.intellij.testFramework.UsefulTestCase; import gnu.trove.THashSet; +import junit.extensions.TestSetup; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -42,7 +44,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.parsing.JetParsingTest; -import org.jetbrains.jet.utils.ExceptionUtils; import java.io.File; import java.lang.reflect.Constructor; @@ -51,107 +52,39 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.Set; -public class TestlibTest extends CodegenTestCase { - - private File junitJar; - +@SuppressWarnings("JUnitTestCaseWithNoTests") +public class TestlibTest extends UsefulTestCase { public static Test suite() { - return new TestlibTest().buildSuite(); + return new TestlibTest().buildTestSuite(); } - protected TestSuite buildSuite() { - try { - setUp(); - return doBuildSuite(); - } catch (Exception e) { - throw ExceptionUtils.rethrow(e); - } - finally { - try { - tearDown(); - } catch (Exception e) { - throw ExceptionUtils.rethrow(e); + private TestSuite suite; + private File junitJar; + private GeneratedClassLoader classLoader; + private JetTypeMapper typeMapper; + private GenerationState generationState; + private JetCoreEnvironment myEnvironment; + + private Test buildTestSuite() { + suite = new TestSuite("stdlib_test"); + + return new TestSetup(suite) { + @Override + protected void setUp() throws Exception { + TestlibTest.this.setUp(); } - } + + @Override + protected void tearDown() throws Exception { + TestlibTest.this.tearDown(); + } + }; } - private TestSuite doBuildSuite() { - try { - GenerationState generationState = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(myEnvironment, false); - - if (generationState == null) { - throw new RuntimeException("There were compilation errors"); - } - - ClassFileFactory classFileFactory = generationState.getFactory(); - - final GeneratedClassLoader loader = new GeneratedClassLoader( - classFileFactory, - new URLClassLoader(new URL[]{ForTestCompileRuntime.runtimeJarForTests().toURI().toURL(), junitJar.toURI().toURL()}, - TestCase.class.getClassLoader())); - - JetTypeMapper typeMapper = generationState.getTypeMapper(); - TestSuite suite = new TestSuite("stdlib_test"); - try { - for(JetFile jetFile : myEnvironment.getSourceFiles()) { - for(JetDeclaration decl : jetFile.getDeclarations()) { - if (decl instanceof JetClass) { - JetClass jetClass = (JetClass) decl; - - ClassDescriptor descriptor = (ClassDescriptor) generationState.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, jetClass); - Set allSuperTypes = new THashSet(); - DescriptorUtils.addSuperTypes(descriptor.getDefaultType(), allSuperTypes); - - for(JetType type : allSuperTypes) { - String internalName = typeMapper.mapType(type, JetTypeMapperMode.IMPL).getInternalName(); - if(internalName.equals("junit/framework/Test")) { - String name = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName(); - System.out.println(name); - Class aClass = (Class) loader.loadClass(name.replace('/', '.')); - if ((aClass.getModifiers() & Modifier.ABSTRACT) == 0 - && (aClass.getModifiers() & Modifier.PUBLIC) != 0) { - try { - Constructor constructor = aClass.getConstructor(); - if (constructor != null && (constructor.getModifiers() & Modifier.PUBLIC) != 0) { - suite.addTestSuite(aClass); - } - } - //catch (final VerifyError e) { - // suite.addTest(new TestCase(aClass.getName()) { - // @Override - // public int countTestCases() { - // return 1; - // } - // - // @Override - // public void run(TestResult result) { - // result.addError(this, new RuntimeException(e)); - // } - // }); - //} - catch (NoSuchMethodException e) { - } - } - break; - } - } - } - } - } - } - finally { - typeMapper = null; - } - - return suite; - } catch (Exception e) { - throw ExceptionUtils.rethrow(e); - } - } - @Override public void setUp() throws Exception { super.setUp(); + CompilerConfiguration configuration = JetTestUtils.compilerConfigurationForTests(ConfigurationKind.ALL, TestJdkKind.FULL_JDK); configuration.add(JVMConfigurationKeys.CLASSPATH_KEY, JetTestUtils.getAnnotationsJar()); @@ -165,5 +98,77 @@ public class TestlibTest extends CodegenTestCase { configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollectorPlainTextToStream.PLAIN_TEXT_TO_SYSTEM_ERR); myEnvironment = new JetCoreEnvironment(getTestRootDisposable(), configuration); + + generationState = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(myEnvironment, false); + if (generationState == null) { + throw new RuntimeException("There were compilation errors"); + } + + ClassFileFactory classFileFactory = generationState.getFactory(); + + classLoader = new GeneratedClassLoader(classFileFactory, + new URLClassLoader(new URL[] {ForTestCompileRuntime.runtimeJarForTests().toURI().toURL(), junitJar.toURI().toURL()}, + TestCase.class.getClassLoader())); + + typeMapper = generationState.getTypeMapper(); + + for (JetFile jetFile : myEnvironment.getSourceFiles()) { + for (JetDeclaration decl : jetFile.getDeclarations()) { + if (decl instanceof JetClass) { + JetClass jetClass = (JetClass) decl; + + ClassDescriptor descriptor = (ClassDescriptor) generationState.getBindingContext().get( + BindingContext.DECLARATION_TO_DESCRIPTOR, jetClass); + + assertNotNull("Descriptor for declaration " + jetClass + " shouldn't be null", descriptor); + + Set allSuperTypes = new THashSet(); + DescriptorUtils.addSuperTypes(descriptor.getDefaultType(), allSuperTypes); + + for (JetType type : allSuperTypes) { + String internalName = typeMapper.mapType(type, JetTypeMapperMode.IMPL).getInternalName(); + if (internalName.equals("junit/framework/Test")) { + String name = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName(); + + //noinspection UseOfSystemOutOrSystemErr + System.out.println(name); + + @SuppressWarnings("unchecked") + Class aClass = (Class) classLoader.loadClass(name.replace('/', '.')); + + if ((aClass.getModifiers() & Modifier.ABSTRACT) == 0 && (aClass.getModifiers() & Modifier.PUBLIC) != 0) { + try { + Constructor constructor = aClass.getConstructor(); + if ((constructor.getModifiers() & Modifier.PUBLIC) != 0) { + suite.addTestSuite(aClass); + } + } + catch (NoSuchMethodException e) { + // Ignore test classes we can't instantiate + } + } + + break; + } + } + } + } + } + } + + @Override + protected void tearDown() throws Exception { + typeMapper = null; + + classLoader.dispose(); + classLoader = null; + + generationState = null; + + myEnvironment = null; + + junitJar = null; + + super.tearDown(); } }