/* * 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 com.google.common.collect.Lists; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; import kotlin.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.kotlin.config.CompilerConfiguration; import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.kotlin.utils.ExceptionUtilsKt; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Collections; import java.util.List; public abstract class AbstractCompileKotlinAgainstKotlinTest extends CodegenTestCase { private File tmpdir; private File aDir; private File bDir; @Override protected void setUp() throws Exception { super.setUp(); tmpdir = KotlinTestUtils.tmpDirForTest(this); aDir = new File(tmpdir, "a"); bDir = new File(tmpdir, "b"); KotlinTestUtils.mkdirs(aDir); KotlinTestUtils.mkdirs(bDir); } @Override protected void doMultiFileTest(@NotNull File wholeFile, @NotNull List<TestFile> files, @Nullable File javaFilesDir) throws Exception { assert javaFilesDir == null : ".java files are not supported yet in this test"; doTwoFileTest(files); } @NotNull protected Pair<ClassFileFactory, ClassFileFactory> doTwoFileTest(@NotNull List<TestFile> files) throws Exception { // Note that it may be beneficial to improve this test to handle many files, compiling them successively against all previous assert files.size() == 2 : "There should be exactly two files in this test"; TestFile fileA = files.get(0); TestFile fileB = files.get(1); ClassFileFactory factoryA = compileA(fileA, files); ClassFileFactory factoryB = null; try { factoryB = compileB(fileB, files); invokeBox(PackagePartClassUtils.getFilePartShortName(new File(fileB.name).getName())); } catch (Throwable e) { String result = "FIRST: \n\n" + factoryA.createText(); if (factoryB != null) { result += "\n\nSECOND: \n\n" + factoryB.createText(); } System.out.println(result); throw ExceptionUtilsKt.rethrow(e); } return new Pair<>(factoryA, factoryB); } private void invokeBox(@NotNull String className) throws Exception { callBoxMethodAndCheckResult(createGeneratedClassLoader(), className); } @NotNull private URLClassLoader createGeneratedClassLoader() throws Exception { return new URLClassLoader( new URL[]{ bDir.toURI().toURL(), aDir.toURI().toURL() }, ForTestCompileRuntime.runtimeAndReflectJarClassLoader() ); } @NotNull private ClassFileFactory compileA(@NotNull TestFile testFile, List<TestFile> files) throws IOException { Disposable compileDisposable = createDisposable("compileA"); CompilerConfiguration configuration = createConfiguration(ConfigurationKind.ALL, getJdkKind(files), Collections.singletonList(KotlinTestUtils.getAnnotationsJar()), Collections.emptyList(), Collections.singletonList(testFile)); KotlinCoreEnvironment environment = KotlinCoreEnvironment.createForTests( compileDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); return compileKotlin(testFile.name, testFile.content, aDir, environment, compileDisposable); } @NotNull private ClassFileFactory compileB(@NotNull TestFile testFile, List<TestFile> files) throws IOException { CompilerConfiguration configurationWithADirInClasspath = createConfiguration(ConfigurationKind.ALL, getJdkKind(files), Lists.newArrayList(KotlinTestUtils.getAnnotationsJar(), aDir), Collections.emptyList(), Collections.singletonList(testFile)); Disposable compileDisposable = createDisposable("compileB"); KotlinCoreEnvironment environment = KotlinCoreEnvironment.createForTests( compileDisposable, configurationWithADirInClasspath, EnvironmentConfigFiles.JVM_CONFIG_FILES ); return compileKotlin(testFile.name, testFile.content, bDir, environment, compileDisposable); } private Disposable createDisposable(String debugName) { Disposable disposable = Disposer.newDisposable("CompileDisposable" + debugName); Disposer.register(getTestRootDisposable(), disposable); return disposable; } @NotNull private ClassFileFactory compileKotlin( @NotNull String fileName, @NotNull String content, @NotNull File outputDir, @NotNull KotlinCoreEnvironment environment, @NotNull Disposable disposable ) throws IOException { KtFile psiFile = KotlinTestUtils.createFile(fileName, content, environment.getProject()); ModuleVisibilityManager.SERVICE.getInstance(environment.getProject()).addModule( new ModuleBuilder("module for test", tmpdir.getAbsolutePath(), "test") ); ClassFileFactory outputFiles = GenerationUtils.compileFileTo(psiFile, environment, outputDir); Disposer.dispose(disposable); return outputFiles; } }