diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 9b8ca751aec..fa4675c56db 100755 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -153,6 +153,7 @@ import org.jetbrains.kotlin.jps.incremental.AbstractJvmProtoComparisonTest import org.jetbrains.kotlin.kapt.cli.test.AbstractArgumentParsingTest import org.jetbrains.kotlin.kapt.cli.test.AbstractKaptToolIntegrationTest import org.jetbrains.kotlin.jvm.abi.AbstractCompareJvmAbiTest +import org.jetbrains.kotlin.jvm.abi.AbstractCompileAgainstJvmAbiTest import org.jetbrains.kotlin.kapt3.test.AbstractClassFileToSourceStubConverterTest import org.jetbrains.kotlin.kapt3.test.AbstractKotlinKaptContextTest import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg @@ -1074,6 +1075,10 @@ fun main(args: Array) { testClass { model("compare", recursive = false, extension = null) } + + testClass { + model("compile", recursive = false, extension = null) + } } testGroup("plugins/kapt3/kapt3-compiler/test", "plugins/kapt3/kapt3-compiler/testData") { diff --git a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractCompareJvmAbiTest.kt b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractCompareJvmAbiTest.kt index df495cd72d3..835a239240e 100644 --- a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractCompareJvmAbiTest.kt +++ b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractCompareJvmAbiTest.kt @@ -30,4 +30,5 @@ abstract class AbstractCompareJvmAbiTest : BaseJvmAbiTest() { } } } -} \ No newline at end of file +} + diff --git a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractCompileAgainstJvmAbiTest.kt b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractCompileAgainstJvmAbiTest.kt new file mode 100644 index 00000000000..22a443d2218 --- /dev/null +++ b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/AbstractCompileAgainstJvmAbiTest.kt @@ -0,0 +1,28 @@ +package org.jetbrains.kotlin.jvm.abi + +import java.io.File +import java.net.URLClassLoader + +abstract class AbstractCompileAgainstJvmAbiTest : BaseJvmAbiTest() { + fun doTest(path: String) { + val testDir = File(path) + val lib = Compilation(testDir, "lib").also { make(it) } + val app = Compilation(testDir, "app", dependencies = listOf(lib)).also { make(it) } + runApp(app) + } + + private fun runApp(compilation: Compilation) { + val runtimeDeps = compilation.dependencies.map { dep -> + check(dep.destinationDir.exists()) { "Dependency '${dep.name}' of '${compilation.name}' was not built" } + dep.destinationDir + } + + val runtimeClasspath = listOf(compilation.destinationDir) + runtimeDeps + kotlinJvmStdlib + val urls = runtimeClasspath.map { it.toURI().toURL() }.toTypedArray() + val classloader = URLClassLoader(urls) + val appClass = classloader.loadClass("app.AppKt") + val runAppMethod = appClass.getMethod("runAppAndReturnOk") + + assertEquals("OK", runAppMethod.invoke(null)) + } +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/BaseJvmAbiTest.kt b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/BaseJvmAbiTest.kt index eb1cb7f07d2..a3ce28221f8 100644 --- a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/BaseJvmAbiTest.kt +++ b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/BaseJvmAbiTest.kt @@ -10,7 +10,6 @@ import junit.framework.TestCase import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.config.Services -import org.jetbrains.kotlin.incremental.AbstractIncrementalCompilerRunnerTestBase import org.jetbrains.kotlin.incremental.utils.TestMessageCollector import java.io.File @@ -32,7 +31,11 @@ abstract class BaseJvmAbiTest : TestCase() { private fun abiOption(option: String, value: String): String = "plugin:${JvmAbiCommandLineProcessor.COMPILER_PLUGIN_ID}:$option=$value" - inner class Compilation(val projectDir: File, val name: String) { + inner class Compilation( + val projectDir: File, + val name: String, + val dependencies: Collection = emptyList() + ) { val srcDir: File get() = projectDir.resolve(name) @@ -50,11 +53,16 @@ abstract class BaseJvmAbiTest : TestCase() { check(abiPluginJar.exists()) { "Plugin jar '$abiPluginJar' does not exist" } check(compilation.srcDir.exists()) { "Source dir '${compilation.srcDir}' does not exist" } + val abiDependencies = compilation.dependencies.map { dep -> + check(dep.abiDir.exists()) { "Dependency '${dep.name}' of '${compilation.name}' was not built" } + dep.abiDir + } + val messageCollector = TestMessageCollector() val compiler = K2JVMCompiler() val args = compiler.createArguments().apply { freeArgs = listOf(compilation.srcDir.canonicalPath) - classpath = kotlinJvmStdlib.canonicalPath + classpath = (abiDependencies + kotlinJvmStdlib).joinToString(File.pathSeparator) { it.canonicalPath } pluginClasspaths = arrayOf(abiPluginJar.canonicalPath) pluginOptions = arrayOf(abiOption("outputDir", compilation.abiDir.canonicalPath)) destination = compilation.destinationDir.canonicalPath @@ -66,7 +74,7 @@ abstract class BaseJvmAbiTest : TestCase() { } } - private val kotlinJvmStdlib = File("dist/kotlinc/lib/kotlin-stdlib.jar").also { + protected val kotlinJvmStdlib = File("dist/kotlinc/lib/kotlin-stdlib.jar").also { UsefulTestCase.assertExists(it) } } \ No newline at end of file diff --git a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/CompileAgainstJvmAbiTestGenerated.java b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/CompileAgainstJvmAbiTestGenerated.java new file mode 100644 index 00000000000..2bcdc189302 --- /dev/null +++ b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/CompileAgainstJvmAbiTestGenerated.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.jvm.abi; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/jvm-abi-gen/testData/compile") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class CompileAgainstJvmAbiTestGenerated extends AbstractCompileAgainstJvmAbiTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInCompile() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/jvm-abi-gen/testData/compile"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, false); + } + + @TestMetadata("anonymousObject") + public void testAnonymousObject() throws Exception { + runTest("plugins/jvm-abi-gen/testData/compile/anonymousObject/"); + } + + @TestMetadata("classes") + public void testClasses() throws Exception { + runTest("plugins/jvm-abi-gen/testData/compile/classes/"); + } + + @TestMetadata("clinit") + public void testClinit() throws Exception { + runTest("plugins/jvm-abi-gen/testData/compile/clinit/"); + } + + @TestMetadata("privateOnlyConstructors") + public void testPrivateOnlyConstructors() throws Exception { + runTest("plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/"); + } + + @TestMetadata("topLevel") + public void testTopLevel() throws Exception { + runTest("plugins/jvm-abi-gen/testData/compile/topLevel/"); + } +} diff --git a/plugins/jvm-abi-gen/testData/compile/anonymousObject/app/app.kt b/plugins/jvm-abi-gen/testData/compile/anonymousObject/app/app.kt new file mode 100644 index 00000000000..de1ba3196cb --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/anonymousObject/app/app.kt @@ -0,0 +1,11 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + val i = getInterface() + val value = i.getInt() + if (value != 10) error("getInterface().getInt() is '$value', but is expected to be '10'") + + return "OK" +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/anonymousObject/lib/lib.kt b/plugins/jvm-abi-gen/testData/compile/anonymousObject/lib/lib.kt new file mode 100644 index 00000000000..68f19cb9e21 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/anonymousObject/lib/lib.kt @@ -0,0 +1,10 @@ +package lib + +interface Interface { + fun getInt(): Int +} + +fun getInterface(): Interface = + object : Interface { + override fun getInt(): Int = 10 + } \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/classes/app/app.kt b/plugins/jvm-abi-gen/testData/compile/classes/app/app.kt new file mode 100644 index 00000000000..a0c7bd965a1 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/classes/app/app.kt @@ -0,0 +1,40 @@ +package app + +import lib.* + +fun useI(i: I) { + i.iProperty + i.iMethod() +} + +fun useA(a: A) { + a.iProperty + a.iMethod() + + a.aProperty + a.aMethod() + a.aInlineMethod() + A.aConst +} + +fun useB(b: B) { + b.iProperty + b.iMethod() + + b.aProperty + b.aMethod() + b.aInlineMethod() + + b.bProperty + b.bMethod() + b.bInlineMethod() + B.bConst +} + +fun runAppAndReturnOk(): String { + useI(A()) + useA(A()) + useB(B()) + + return "OK" +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/classes/lib/classes.kt b/plugins/jvm-abi-gen/testData/compile/classes/lib/classes.kt new file mode 100644 index 00000000000..28708b9687c --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/classes/lib/classes.kt @@ -0,0 +1,29 @@ +package lib + +interface I { + val iProperty: Int + fun iMethod(): Int +} + +open class A : I { + override val iProperty: Int = 0 + override fun iMethod(): Int = 10 + + val aProperty: Int = 20 + fun aMethod(): Int = 30 + inline fun aInlineMethod(): Int = 40 + + companion object { + const val aConst: Int = 50 + } +} + +class B : A() { + val bProperty: Int = 60 + fun bMethod(): Int = 70 + inline fun bInlineMethod(): Int = 80 + + companion object { + const val bConst: Int = 90 + } +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/clinit/app/app.kt b/plugins/jvm-abi-gen/testData/compile/clinit/app/app.kt new file mode 100644 index 00000000000..acdac19a713 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/clinit/app/app.kt @@ -0,0 +1,10 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + if (Object.z != 3) error("lib.Object.z is ${Object.z}, but '3' was expected") + if (z != 3) error("lib.z is $z, but '3' was expected") + + return "OK" +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/clinit/lib/object.kt b/plugins/jvm-abi-gen/testData/compile/clinit/lib/object.kt new file mode 100644 index 00000000000..2e13c86ad99 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/clinit/lib/object.kt @@ -0,0 +1,7 @@ +package lib + +object Object { + val x = 1 + val y = 2 + val z = x + y +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/clinit/lib/topLevel.kt b/plugins/jvm-abi-gen/testData/compile/clinit/lib/topLevel.kt new file mode 100644 index 00000000000..9dfe37e6722 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/clinit/lib/topLevel.kt @@ -0,0 +1,5 @@ +package lib + +val x = 1 +val y = 2 +val z = x + y \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/app/app.kt b/plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/app/app.kt new file mode 100644 index 00000000000..99092a0cb1a --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/app/app.kt @@ -0,0 +1,10 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + val a = A.create(10) + if (a.x != 20) error("a.x is '${a.x}', but is expected to be '20'") + + return "OK" +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/lib/classes.kt b/plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/lib/classes.kt new file mode 100644 index 00000000000..1ad66a402d5 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/lib/classes.kt @@ -0,0 +1,7 @@ +package lib + +class A private constructor(val x: Int) { + companion object { + fun create(x: Int): A = A(x * 2) + } +} diff --git a/plugins/jvm-abi-gen/testData/compile/topLevel/app/app.kt b/plugins/jvm-abi-gen/testData/compile/topLevel/app/app.kt new file mode 100644 index 00000000000..47419838c80 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/topLevel/app/app.kt @@ -0,0 +1,14 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + if (prop != 1) error("prop is '$prop', but is expected to be '1'") + val funcValue = func() + if (funcValue != 2) error("func() is '$funcValue', but is expected to be '2'") + val inlineFuncValue = inlineFunc() + if (inlineFuncValue != 3) error("inlineFunc() is '$inlineFuncValue', but is expected to be '3'") + if (constant != 4) error("constant is '$constant', but is expected to be '4'") + + return "OK" +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/topLevel/lib/utils.kt b/plugins/jvm-abi-gen/testData/compile/topLevel/lib/utils.kt new file mode 100644 index 00000000000..c3cd59c36de --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/topLevel/lib/utils.kt @@ -0,0 +1,6 @@ +package lib + +val prop: Int = 1 +fun func(): Int = 2 +inline fun inlineFunc(): Int = 3 +const val constant: Int = 4 \ No newline at end of file