[K/N] Test for cinterop hints

This commit is contained in:
Sergey Bogolepov
2022-12-15 15:20:37 +02:00
committed by Space Team
parent 233b01f341
commit 64319477f0
4 changed files with 50 additions and 31 deletions
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.konan.blackboxtest
import org.jetbrains.kotlin.konan.blackboxtest.support.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.*
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.*
import java.io.File
@@ -18,7 +17,7 @@ abstract class AbstractNativeCInteropBaseTest : AbstractNativeSimpleTest() {
internal val targets: KotlinNativeTargets get() = testRunSettings.get<KotlinNativeTargets>()
internal val kotlinNativeClassLoader: KotlinNativeClassLoader get() = testRunSettings.get<KotlinNativeClassLoader>()
internal fun TestCase.cinteropToLibrary(): TestCompilationResult.Success<out KLIB> {
internal fun TestCase.cinteropToLibrary(): TestCompilationResult<out KLIB> {
modules.singleOrNull()
val compilation = CInteropCompilation(
classLoader = testRunSettings.get(),
@@ -27,7 +26,7 @@ abstract class AbstractNativeCInteropBaseTest : AbstractNativeSimpleTest() {
defFile = modules.singleOrNull()!!.files.singleOrNull()!!.location,
expectedArtifact = toLibraryArtifact()
)
return compilation.result.assertSuccess()
return compilation.result
}
private fun TestCase.toLibraryArtifact() = KLIB(buildDir.resolve(modules.singleOrNull()!!.name + ".klib"))
@@ -10,6 +10,7 @@ import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.blackboxtest.support.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.*
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
import org.junit.jupiter.api.Tag
@@ -35,7 +36,7 @@ abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTes
val includeFrameworkArgs = listOf("-compiler-option", "-F${testDataDir.canonicalPath}")
val test1Case: TestCase = generateCInteropTestCaseWithSingleDef(def1File, includeFrameworkArgs)
val klib1: KLIB = test1Case.cinteropToLibrary().resultingArtifact
val klib1: KLIB = test1Case.cinteropToLibrary().assertSuccess().resultingArtifact
val contents1 = klib1.getContents(kotlinNativeClassLoader.classLoader)
val expectedFiltered1Output = golden1File.readText()
@@ -44,7 +45,7 @@ abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTes
val cinterop2ExtraArgs = listOf("-l", klib1.klibFile.canonicalPath, "-compiler-option", "-fmodules")
val test2Case: TestCase = generateCInteropTestCaseWithSingleDef(def2File, includeFrameworkArgs + cinterop2ExtraArgs)
val klib2: KLIB = test2Case.cinteropToLibrary().resultingArtifact
val klib2: KLIB = test2Case.cinteropToLibrary().assertSuccess().resultingArtifact
val contents2 = klib2.getContents(kotlinNativeClassLoader.classLoader)
val expectedFiltered2Output = golden2File.readText()
@@ -10,12 +10,15 @@ import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.blackboxtest.support.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.*
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.*
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.*
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.CInteropHints
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
import org.junit.jupiter.api.Assumptions
import org.junit.jupiter.api.Tag
import java.io.File
@@ -40,8 +43,6 @@ abstract class AbstractNativeCInteropTest : AbstractNativeCInteropBaseTest() {
this is AbstractNativeCInteropFModulesTest &&
targets.testTarget.family == Family.ANDROID
)
Assumptions.assumeFalse(!fmodules && testPath.endsWith("FModules/"))
val testPathFull = getAbsoluteFile(testPath)
val testDataDir = testPathFull.parentFile.parentFile
val includeFolder = testDataDir.resolve("include")
@@ -65,11 +66,19 @@ abstract class AbstractNativeCInteropTest : AbstractNativeCInteropBaseTest() {
val testCase: TestCase = generateCInteropTestCaseWithSingleDef(defFile, includeArgs + fmodulesArgs)
val testCompilationResult = testCase.cinteropToLibrary()
val klibContents = testCompilationResult.resultingArtifact.getContents(kotlinNativeClassLoader.classLoader)
val expectedContents = goldenFile.readText()
assertEquals(StringUtilRt.convertLineSeparators(expectedContents), StringUtilRt.convertLineSeparators(klibContents)) {
"Test failed. CInterop compilation result was: $testCompilationResult"
// If we are running fmodules-specific test without -fmodules then we want to be sure that cinterop fails the way we want it to.
if (!fmodules && testPath.endsWith("FModules/")) {
val loggedData = (testCompilationResult as TestCompilationResult.CompilationToolFailure).loggedData
val prettyMessage = CInteropHints.fmodulesHint
assertTrue(loggedData.toString().contains(prettyMessage)) {
"Test failed. CInterop compilation result was: $testCompilationResult"
}
} else {
val klibContents = testCompilationResult.assertSuccess().resultingArtifact.getContents(kotlinNativeClassLoader.classLoader)
val expectedContents = goldenFile.readText()
assertEquals(StringUtilRt.convertLineSeparators(expectedContents), StringUtilRt.convertLineSeparators(klibContents)) {
"Test failed. CInterop compilation result was: $testCompilationResult"
}
}
}
@@ -17,6 +17,7 @@ import java.io.PrintStream
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
import kotlin.time.measureTimedValue
import org.jetbrains.kotlin.konan.file.File as KonanFile
internal data class CompilationToolCallResult(
@@ -73,6 +74,7 @@ internal fun callCompiler(compilerArgs: Array<String>, kotlinNativeClassLoader:
return CompilationToolCallResult(exitCode, compilerOutput, messageCollector.hasErrors(), duration)
}
@OptIn(ExperimentalTime::class)
internal fun invokeCInterop(
kotlinNativeClassLoader: ClassLoader,
targets: KotlinNativeTargets,
@@ -90,30 +92,38 @@ internal fun invokeCInterop(
val interopClass = Class.forName("org.jetbrains.kotlin.native.interop.gen.jvm.Interop", true, kotlinNativeClassLoader)
val entryPoint = interopClass.declaredMethods.single { it.name == "interopViaReflection" }
val possibleSubsequentCompilerInvocationArgs: Array<String>?
@OptIn(ExperimentalTime::class)
val duration = measureTime {
@Suppress("UNCHECKED_CAST")
possibleSubsequentCompilerInvocationArgs = entryPoint.invoke(
val (cinteropResult, duration) = measureTimedValue {
entryPoint.invoke(
interopClass.getDeclaredConstructor().newInstance(),
"native",
args + extraArgs,
false,
generatedDir.absolutePath, nativesDir.absolutePath, manifest.path, cstubsName // args for InternalInteropOptions()
) as? Array<String>?
}
// In currently tested usecases, cinterop must return no args for the subsequent compiler call
return if (possibleSubsequentCompilerInvocationArgs == null) {
// TODO There is no technical ability to extract `toolOutput` and `toolOutputHasErrors`
// from C-interop tool invocation at the moment. This should be fixed in the future.
CompilationToolCallResult(exitCode = ExitCode.OK, toolOutput = "", toolOutputHasErrors = false, duration)
} else {
CompilationToolCallResult(
exitCode = ExitCode.COMPILATION_ERROR,
toolOutput = possibleSubsequentCompilerInvocationArgs.joinToString(" "),
toolOutputHasErrors = true,
duration
)
}
return when {
// cinterop has failed with a known error that was returned as a result.
cinteropResult is Exception -> {
CompilationToolCallResult(
exitCode = ExitCode.COMPILATION_ERROR,
toolOutput = cinteropResult.message ?: "",
toolOutputHasErrors = true,
duration
)
}
// In currently tested usecases, cinterop must return no args for the subsequent compiler call
cinteropResult is Array<*> -> {
CompilationToolCallResult(
exitCode = ExitCode.COMPILATION_ERROR,
toolOutput = cinteropResult.joinToString(" "),
toolOutputHasErrors = true,
duration
)
}
else -> {
// TODO There is no technical ability to extract `toolOutput` and `toolOutputHasErrors`
// from C-interop tool invocation at the moment. This should be fixed in the future.
CompilationToolCallResult(exitCode = ExitCode.OK, toolOutput = "", toolOutputHasErrors = false, duration)
}
}
}