diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt index 806353af292..ed7bef9a697 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt @@ -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() internal val kotlinNativeClassLoader: KotlinNativeClassLoader get() = testRunSettings.get() - internal fun TestCase.cinteropToLibrary(): TestCompilationResult.Success { + internal fun TestCase.cinteropToLibrary(): TestCompilationResult { 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")) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt index 97b82818032..e4c6a264cba 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt @@ -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() diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropTest.kt index 082fbe2656f..66f4be04fbf 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropTest.kt @@ -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" + } } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilationToolCall.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilationToolCall.kt index ba60b12ff57..ecd3794d323 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilationToolCall.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/CompilationToolCall.kt @@ -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, 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? - - @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? - } - // 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) + } + } }