Add tests for compilation against abi classes

This commit is contained in:
Alexey Tsvetkov
2018-12-03 16:28:34 +03:00
parent 8992ee6280
commit 9dd09151f0
16 changed files with 252 additions and 5 deletions
@@ -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<String>) {
testClass<AbstractCompareJvmAbiTest> {
model("compare", recursive = false, extension = null)
}
testClass<AbstractCompileAgainstJvmAbiTest> {
model("compile", recursive = false, extension = null)
}
}
testGroup("plugins/kapt3/kapt3-compiler/test", "plugins/kapt3/kapt3-compiler/testData") {
@@ -30,4 +30,5 @@ abstract class AbstractCompareJvmAbiTest : BaseJvmAbiTest() {
}
}
}
}
}
@@ -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))
}
}
@@ -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<Compilation> = 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)
}
}
@@ -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/");
}
}
@@ -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"
}
@@ -0,0 +1,10 @@
package lib
interface Interface {
fun getInt(): Int
}
fun getInterface(): Interface =
object : Interface {
override fun getInt(): Int = 10
}
+40
View File
@@ -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"
}
@@ -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
}
}
+10
View File
@@ -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"
}
@@ -0,0 +1,7 @@
package lib
object Object {
val x = 1
val y = 2
val z = x + y
}
@@ -0,0 +1,5 @@
package lib
val x = 1
val y = 2
val z = x + y
@@ -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"
}
@@ -0,0 +1,7 @@
package lib
class A private constructor(val x: Int) {
companion object {
fun create(x: Int): A = A(x * 2)
}
}
@@ -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"
}
@@ -0,0 +1,6 @@
package lib
val prop: Int = 1
fun func(): Int = 2
inline fun inlineFunc(): Int = 3
const val constant: Int = 4