diff --git a/build.gradle b/build.gradle index 8b77f506..f6a8f8d8 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,8 @@ idea { } dependencies { + testRuntime "org.jetbrains.kotlin:kotlin-scripting-compiler:1.3.50" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" testImplementation group: 'junit', name: 'junit', version: '4.12' @@ -67,4 +69,4 @@ compileKotlin { compileTestKotlin { kotlinOptions.jvmTarget = "1.8" kotlinOptions.freeCompilerArgs += ["-Xskip-runtime-version-check"] -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/tschuchort/compiletesting/KotlinCompilation.kt b/src/main/kotlin/com/tschuchort/compiletesting/KotlinCompilation.kt index f59325f1..5cd967e1 100644 --- a/src/main/kotlin/com/tschuchort/compiletesting/KotlinCompilation.kt +++ b/src/main/kotlin/com/tschuchort/compiletesting/KotlinCompilation.kt @@ -65,6 +65,11 @@ class KotlinCompilation { */ var classpaths: List = emptyList() + /** + * Paths to plugins to be made available in the compilation + */ + var pluginClasspaths: List = emptyList() + /** Source files to be compiled */ var sources: List = emptyList() @@ -326,6 +331,8 @@ class KotlinCompilation { it.destination = classesDir.absolutePath it.classpath = commonClasspaths().joinToString(separator = File.pathSeparator) + it.pluginClasspaths = pluginClasspaths.map(File::getAbsolutePath).toTypedArray() + if(jdkHome != null) { it.jdkHome = jdkHome!!.absolutePath } @@ -403,6 +410,13 @@ class KotlinCompilation { /** Performs the 1st and 2nd compilation step to generate stubs and run annotation processors */ private fun stubsAndApt(sourceFiles: List): ExitCode { + pluginClasspaths.forEach { filepath -> + if (!filepath.exists()) { + error("Plugin $filepath not found") + return ExitCode.INTERNAL_ERROR + } + } + if(annotationProcessors.isEmpty()) { log("No services were given. Not running kapt steps.") return ExitCode.OK @@ -473,10 +487,12 @@ class KotlinCompilation { } } + if (pluginClasspaths.isNotEmpty()) + warn("Included plugins in pluginsClasspaths will be executed twice.") + val k2JvmArgs = commonK2JVMArgs().also { it.freeArgs = sourcePaths - it.pluginClasspaths = (it.pluginClasspaths?.toList() ?: emptyList() + getResourcesPath()) - .distinct().toTypedArray() + it.pluginClasspaths = (it.pluginClasspaths ?: emptyArray()) + arrayOf(getResourcesPath()) } val compilerMessageCollector = PrintingMessageCollector( diff --git a/src/test/kotlin/com/tschuchort/compiletesting/KotlinCompilationTests.kt b/src/test/kotlin/com/tschuchort/compiletesting/KotlinCompilationTests.kt index e3a18458..eb74dcbf 100644 --- a/src/test/kotlin/com/tschuchort/compiletesting/KotlinCompilationTests.kt +++ b/src/test/kotlin/com/tschuchort/compiletesting/KotlinCompilationTests.kt @@ -1,11 +1,13 @@ package com.tschuchort.compiletesting import com.tschuchort.compiletesting.KotlinCompilation.ExitCode +import io.github.classgraph.ClassGraph import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.fail import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import java.io.File import javax.annotation.processing.AbstractProcessor import javax.annotation.processing.RoundEnvironment import javax.lang.model.element.TypeElement @@ -623,6 +625,28 @@ class KotlinCompilationTests { assertClassLoadable(result, "${KotlinTestProcessor.GENERATED_PACKAGE}.${KotlinTestProcessor.GENERATED_JAVA_CLASS_NAME}") } + @Test + fun `detects the plugin provided for compilation via pluginClasspaths property`() { + val result = defaultCompilerConfig().apply { + sources = listOf(SourceFile.kotlin("kSource.kt", "class KSource")) + pluginClasspaths = listOf(classpathOf("kotlin-scripting-compiler-1.3.50")) + }.compile() + + assertThat(result.exitCode).isEqualTo(ExitCode.OK) + assertThat(result.messages).contains("provided plugin org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar") + } + + @Test + fun `returns an internal error when adding a non existing plugin for compilation`() { + val result = defaultCompilerConfig().apply { + sources = listOf(SourceFile.kotlin("kSource.kt", "class KSource")) + pluginClasspaths = listOf(File("./non-existing-plugin.jar")) + }.compile() + + assertThat(result.exitCode).isEqualTo(ExitCode.INTERNAL_ERROR) + assertThat(result.messages).contains("non-existing-plugin.jar not found") + } + private fun defaultCompilerConfig(): KotlinCompilation { return KotlinCompilation().apply { workingDir = temporaryFolder.root @@ -645,6 +669,16 @@ class KotlinCompilationTests { return fail("Class $className could not be loaded") } } + + /** + * Returns the classpath for a dependency (format $name-$version). + * This is necessary to know the actual location of a dependency + * which has been included in test runtime (build.gradle). + */ + private fun classpathOf(dependency: String): File { + val regex = Regex(".*$dependency\\.jar") + return ClassGraph().classpathFiles.first { classpath -> classpath.name.matches(regex) } + } class InheritedClass {} }