[KT-39120] Add "-fmodules" argument support to Cinterop

Merge-request: KT-MR-6921
Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
Vladimir Sukharev
2022-11-30 08:46:40 +00:00
committed by Space Team
parent 10fc86ef92
commit b883dc5434
173 changed files with 2707 additions and 214 deletions
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.generators.tests
import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
import org.jetbrains.kotlin.generators.model.annotation
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeBlackBoxTest
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeCodegenBoxTest
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeKlibABITest
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeKlibBinaryCompatibilityTest
import org.jetbrains.kotlin.konan.blackboxtest.*
import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseExtTestCaseGroupProvider
import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseStandardTestCaseGroupProvider
import org.jetbrains.kotlin.test.TargetBackend
@@ -59,6 +56,31 @@ fun main() {
model("binaryCompatibility/klibEvolution", recursive = false)
}
}
// CInterop tests.
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeCInteropFModulesTest>(
suiteTestClassName = "CInteropFModulesTestGenerated"
) {
model("CInterop/simple/simpleDefs", pattern = "^([^_](.+))$", recursive = false)
model("CInterop/framework/frameworkDefs", pattern = "^([^_](.+))$", recursive = false)
model("CInterop/framework.macros/macrosDefs", pattern = "^([^_](.+))$", recursive = false)
model("CInterop/builtins/builtinsDefs", pattern = "^([^_](.+))$", recursive = false)
}
testClass<AbstractNativeCInteropNoFModulesTest>(
suiteTestClassName = "CInteropNoFModulesTestGenerated"
) {
model("CInterop/simple/simpleDefs", pattern = "^([^_](.+))$", recursive = false)
model("CInterop/framework/frameworkDefs", pattern = "^([^_](.+))$", recursive = false)
model("CInterop/framework.macros/macrosDefs", pattern = "^([^_](.+))$", recursive = false)
model("CInterop/builtins/builtinsDefs", pattern = "^([^_](.+))$", recursive = false)
}
testClass<AbstractNativeCInteropKT39120Test>(
suiteTestClassName = "CInteropKT39120TestGenerated"
) {
model("CInterop/KT-39120/defs", pattern = "^([^_](.+))$", recursive = false)
}
}
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.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
abstract class AbstractNativeCInteropBaseTest : AbstractNativeSimpleTest() {
private val buildDir: File get() = testRunSettings.get<SimpleTestDirectories>().testBuildDir
internal val targets: KotlinNativeTargets get() = testRunSettings.get<KotlinNativeTargets>()
internal val kotlinNativeClassLoader: KotlinNativeClassLoader get() = testRunSettings.get<KotlinNativeClassLoader>()
internal fun TestCase.cinteropToLibrary(): TestCompilationResult.Success<out KLIB> {
modules.singleOrNull()
val compilation = CInteropCompilation(
classLoader = testRunSettings.get(),
targets = targets,
freeCompilerArgs = freeCompilerArgs,
defFile = modules.singleOrNull()!!.files.singleOrNull()!!.location,
expectedArtifact = toLibraryArtifact()
)
return compilation.result.assertSuccess()
}
private fun TestCase.toLibraryArtifact() = KLIB(buildDir.resolve(modules.singleOrNull()!!.name + ".klib"))
internal fun generateCInteropTestCaseWithSingleDef(defFile: File, extraArgs: List<String>): TestCase {
val moduleName: String = defFile.name
val module = TestModule.Exclusive(moduleName, emptySet(), emptySet())
module.files += TestFile.createCommitted(defFile, module)
return TestCase(
id = TestCaseId.Named(moduleName),
kind = TestKind.STANDALONE,
modules = setOf(module),
freeCompilerArgs = TestCompilerArgs(extraArgs),
nominalPackageName = PackageName.EMPTY,
checks = TestRunChecks.Default(testRunSettings.get<Timeouts>().executionTimeout),
extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT)
).apply {
initialize(null, null)
}
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest
import com.intellij.openapi.util.text.StringUtilRt
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.settings.*
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
import org.junit.jupiter.api.Tag
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.*
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals
import org.junit.jupiter.api.Assumptions
@Tag("cinterop")
abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTest() {
@Synchronized
protected fun runTest(@TestDataFile testPath: String) {
// KT-39120 is about Objective-C, so this test is for Apple hosts/targets only
Assumptions.assumeTrue(targets.hostTarget.family.isAppleFamily && targets.testTarget.family.isAppleFamily)
val testPathFull = getAbsoluteFile(testPath)
val testDataDir = testPathFull.parentFile.parentFile
val def1File = testPathFull.resolve("pod1.def")
val def2File = testPathFull.resolve("pod2.def")
val golden1File = testPathFull.resolve("pod1.contents.gold.txt")
val golden2File = testPathFull.resolve("pod2.contents.gold.txt")
val includeFrameworkArgs = listOf("-compiler-option", "-F${testDataDir.canonicalPath}")
val test1Case: TestCase = generateCInteropTestCaseWithSingleDef(def1File, includeFrameworkArgs)
val klib1: KLIB = test1Case.cinteropToLibrary().resultingArtifact
val contents1 = klib1.getContents(kotlinNativeClassLoader.classLoader)
val expectedFiltered1Output = golden1File.readText()
val actualFiltered1Output = filterContentsOutput(contents1, " pod.Version|POD|class Pod")
assertEquals(StringUtilRt.convertLineSeparators(expectedFiltered1Output), StringUtilRt.convertLineSeparators(actualFiltered1Output))
val cinterop2ExtraArgs = listOf("-l", klib1.klibFile.canonicalPath, "-compiler-option", "-fmodules")
val test2Case: TestCase = generateCInteropTestCaseWithSingleDef(def2File, includeFrameworkArgs + cinterop2ExtraArgs)
val klib2: KLIB = test2Case.cinteropToLibrary().resultingArtifact
val contents2 = klib2.getContents(kotlinNativeClassLoader.classLoader)
val expectedFiltered2Output = golden2File.readText()
val actualFiltered2Output = filterContentsOutput(contents2, " pod.Version|POD|class Pod")
assertEquals(StringUtilRt.convertLineSeparators(expectedFiltered2Output), StringUtilRt.convertLineSeparators(actualFiltered2Output))
}
private fun filterContentsOutput(contents: String, pattern: String) =
contents.split("\n").filter {
it.contains(Regex(pattern))
}.joinToString(separator = "\n")
}
@@ -0,0 +1,113 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest
import com.intellij.openapi.util.text.StringUtilRt
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.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.test.services.JUnit5Assertions.assertEquals
import org.junit.jupiter.api.Assumptions
import org.junit.jupiter.api.Tag
import java.io.File
abstract class AbstractNativeCInteropFModulesTest : AbstractNativeCInteropTest() {
override val fmodules = true
}
abstract class AbstractNativeCInteropNoFModulesTest : AbstractNativeCInteropTest() {
override val fmodules = false
}
@Tag("cinterop")
abstract class AbstractNativeCInteropTest : AbstractNativeCInteropBaseTest() {
abstract val fmodules: Boolean
@Synchronized
protected fun runTest(@TestDataFile testPath: String) {
// FIXME: check the following failures under Android with -fmodules
// fatal error: could not build module 'std'
Assumptions.assumeFalse(
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")
val defFile = testPathFull.resolve("pod1.def")
val defContents = defFile.readText().split("\n").map { it.trim() }
val defHasObjC = defContents.any { it.endsWith("Objective-C") }
Assumptions.assumeFalse(defHasObjC && !targets.testTarget.family.isAppleFamily)
val defHasHeaders = defContents.any { it.startsWith("headers") }
Assumptions.assumeFalse(fmodules && defHasHeaders)
val goldenFile = if (testDataDir.name == "builtins")
getBuiltinsGoldenFile(testPathFull)
else
getGoldenFile(testPathFull)
val fmodulesArgs = if (fmodules) listOf("-compiler-option", "-fmodules") else listOf()
val includeArgs = if (testDataDir.name.startsWith("framework"))
listOf("-compiler-option", "-F${testDataDir.canonicalPath}")
else
listOf("-compiler-option", "-I${includeFolder.canonicalPath}")
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"
}
}
private fun getGoldenFile(testPathFull: File): File {
return testPathFull.resolve("contents.gold.txt")
}
private fun getBuiltinsGoldenFile(testPathFull: File): File {
val goldenFilePart = when (targets.testTarget) {
KonanTarget.ANDROID_ARM32 -> "ARM32"
KonanTarget.ANDROID_ARM64 -> "ARM64"
KonanTarget.ANDROID_X64 -> "X64"
KonanTarget.ANDROID_X86 -> "CPointerByteVar"
KonanTarget.IOS_ARM32 -> "COpaquePointer"
KonanTarget.IOS_ARM64 -> "CPointerByteVar"
KonanTarget.IOS_SIMULATOR_ARM64 -> "CPointerByteVar"
KonanTarget.IOS_X64 -> "X64"
KonanTarget.LINUX_ARM32_HFP -> "ARM32"
KonanTarget.LINUX_ARM64 -> "ARM64"
KonanTarget.LINUX_MIPS32 -> "COpaquePointer"
KonanTarget.LINUX_MIPSEL32 -> "COpaquePointer"
KonanTarget.LINUX_X64 -> "X64"
KonanTarget.MACOS_ARM64 -> "CPointerByteVar"
KonanTarget.MACOS_X64 -> "X64"
KonanTarget.MINGW_X64 -> "CPointerByteVar"
KonanTarget.MINGW_X86 -> "CPointerByteVar"
KonanTarget.TVOS_ARM64 -> "CPointerByteVar"
KonanTarget.TVOS_SIMULATOR_ARM64 -> "CPointerByteVar"
KonanTarget.TVOS_X64 -> "X64"
KonanTarget.WASM32 -> "COpaquePointer"
KonanTarget.WATCHOS_ARM32 -> "CPointerByteVar"
KonanTarget.WATCHOS_ARM64 -> "CPointerByteVar"
KonanTarget.WATCHOS_DEVICE_ARM64 -> "CPointerByteVar"
KonanTarget.WATCHOS_SIMULATOR_ARM64 -> "CPointerByteVar"
KonanTarget.WATCHOS_X64 -> "X64"
KonanTarget.WATCHOS_X86 -> "CPointerByteVar"
is KonanTarget.ZEPHYR -> "COpaquePointer"
}
return testPathFull.resolve("contents.gold.${goldenFilePart}.txt")
}
}
@@ -83,31 +83,47 @@ internal abstract class LoggedData {
abstract class CompilerCall : LoggedData()
class RealCompilerCall(
private val parameters: CompilerParameters,
class CInteropParameters(
private val extraArgs: Array<String>,
private val defFile: File,
private val environment: JVMEnvironment = JVMEnvironment() // Capture environment.
) : LoggedData() {
override fun computeText() = buildString {
appendArguments("CINTEROP INVOCATION EXTRA ARGUMENTS:", extraArgs.toList())
appendLine()
appendLine(environment)
appendLine()
appendLine("TEST DEF FILE: ${defFile.canonicalPath}")
}
}
class CompilationToolCall(
private val toolName: String,
private val parameters: LoggedData,
private val exitCode: ExitCode,
private val compilerOutput: String,
private val compilerOutputHasErrors: Boolean,
private val toolOutput: String,
private val toolOutputHasErrors: Boolean,
private val duration: Duration
) : CompilerCall() {
override fun computeText(): String {
val problems = listOfNotNull(
"- Non-zero exit code".takeIf { exitCode != ExitCode.OK },
"- Errors reported by the compiler".takeIf { compilerOutputHasErrors }
"- Errors reported by the $toolName".takeIf { toolOutputHasErrors }
)
return buildString {
if (problems.isNotEmpty()) {
appendLine("COMPILATION PROBLEMS:")
appendLine("$toolName PROBLEMS:")
problems.forEach(::appendLine)
appendLine()
}
appendLine("COMPILER CALL:")
appendLine("$toolName CALL:")
appendLine("- Exit code: ${exitCode.code} (${exitCode.name})")
appendDuration(duration)
appendLine()
appendPotentiallyLargeOutput(compilerOutput, "RAW COMPILER OUTPUT", truncateLargeOutput = false)
appendPotentiallyLargeOutput(toolOutput, "RAW $toolName OUTPUT", truncateLargeOutput = false)
appendLine()
appendLine(parameters)
}
@@ -118,10 +134,10 @@ internal abstract class LoggedData {
override fun computeText() = "No compiler call performed for external (given) artifact $artifactFile"
}
class CompilerCallUnexpectedFailure(parameters: CompilerParameters, throwable: Throwable) : UnexpectedFailure(parameters, throwable)
class CompilationToolCallUnexpectedFailure(parameters: LoggedData, throwable: Throwable) : UnexpectedFailure(parameters, throwable)
class TestRunParameters(
private val compilerCall: CompilerCall,
private val compilationToolCall: CompilerCall,
private val testCaseId: TestCaseId?,
private val runArgs: Iterable<String>,
private val runParameters: List<TestRunParameter>?
@@ -151,7 +167,7 @@ internal abstract class LoggedData {
appendLine(expectedOutputDataFile)
appendLine()
}
appendLine(compilerCall)
appendLine(compilationToolCall)
}
}
@@ -10,13 +10,23 @@ import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.compilerRunner.processCompilerOutput
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.KotlinNativeTargets
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
import org.jetbrains.kotlin.konan.file.File as KonanFile
internal fun callCompiler(compilerArgs: Array<String>, kotlinNativeClassLoader: ClassLoader): CompilerCallResult {
internal data class CompilationToolCallResult(
val exitCode: ExitCode,
val toolOutput: String,
val toolOutputHasErrors: Boolean,
val duration: Duration
)
internal fun callCompiler(compilerArgs: Array<String>, kotlinNativeClassLoader: ClassLoader): CompilationToolCallResult {
val compilerXmlOutput: ByteArrayOutputStream
val exitCode: ExitCode
@@ -60,12 +70,50 @@ internal fun callCompiler(compilerArgs: Array<String>, kotlinNativeClassLoader:
compilerOutput = outputStream.toString(Charsets.UTF_8.name())
}
return CompilerCallResult(exitCode, compilerOutput, messageCollector.hasErrors(), duration)
return CompilationToolCallResult(exitCode, compilerOutput, messageCollector.hasErrors(), duration)
}
internal data class CompilerCallResult(
val exitCode: ExitCode,
val compilerOutput: String,
val compilerOutputHasErrors: Boolean,
val duration: Duration
)
internal fun invokeCInterop(
kotlinNativeClassLoader: ClassLoader,
targets: KotlinNativeTargets,
inputDef: File,
outputLib: File,
extraArgs: Array<String>
): CompilationToolCallResult {
val args = arrayOf("-o", outputLib.canonicalPath, "-def", inputDef.canonicalPath, "-no-default-libs", "-target", targets.testTarget.name)
val buildDir = KonanFile("${outputLib.canonicalPath}-build")
val generatedDir = KonanFile(buildDir, "kotlin")
val nativesDir = KonanFile(buildDir, "natives")
val manifest = KonanFile(buildDir, "manifest.properties")
val cstubsName = "cstubs"
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(
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
)
}
}
@@ -88,17 +88,17 @@ internal abstract class BasicCompilation<A : TestCompilationArtifact>(
kotlinNativeClassLoader = classLoader.classLoader
)
val loggedCompilerCall =
LoggedData.RealCompilerCall(loggedCompilerParameters, exitCode, compilerOutput, compilerOutputHasErrors, duration)
val loggedCompilationToolCall =
LoggedData.CompilationToolCall("COMPILER", loggedCompilerParameters, exitCode, compilerOutput, compilerOutputHasErrors, duration)
val result = if (exitCode != ExitCode.OK || compilerOutputHasErrors)
TestCompilationResult.CompilerFailure(loggedCompilerCall)
TestCompilationResult.CompilationToolFailure(loggedCompilationToolCall)
else
TestCompilationResult.Success(expectedArtifact, loggedCompilerCall)
TestCompilationResult.Success(expectedArtifact, loggedCompilationToolCall)
loggedCompilerCall to result
loggedCompilationToolCall to result
} catch (unexpectedThrowable: Throwable) {
val loggedFailure = LoggedData.CompilerCallUnexpectedFailure(loggedCompilerParameters, unexpectedThrowable)
val loggedFailure = LoggedData.CompilationToolCallUnexpectedFailure(loggedCompilerParameters, unexpectedThrowable)
val result = TestCompilationResult.UnexpectedFailure(loggedFailure)
loggedFailure to result
@@ -189,6 +189,52 @@ internal class GivenLibraryCompilation(givenArtifact: KLIB) : TestCompilation<KL
override val result = TestCompilationResult.Success(givenArtifact, LoggedData.NoopCompilerCall(givenArtifact.klibFile))
}
internal class CInteropCompilation(
targets: KotlinNativeTargets,
classLoader: KotlinNativeClassLoader,
freeCompilerArgs: TestCompilerArgs,
defFile: File,
expectedArtifact: KLIB
) : TestCompilation<KLIB>() {
override val result: TestCompilationResult<out KLIB> by lazy {
val extraArgsArray = freeCompilerArgs.compilerArgs.toTypedArray()
val loggedCInteropParameters = LoggedData.CInteropParameters(extraArgs = extraArgsArray, defFile = defFile)
val (loggedCall: LoggedData, immediateResult: TestCompilationResult.ImmediateResult<out KLIB>) = try {
val (exitCode, cinteropOutput, cinteropOutputHasErrors, duration) = invokeCInterop(
classLoader.classLoader,
targets,
defFile,
expectedArtifact.klibFile,
extraArgsArray
)
val loggedInteropCall = LoggedData.CompilationToolCall(
toolName = "CINTEROP",
parameters = loggedCInteropParameters,
exitCode = exitCode,
toolOutput = cinteropOutput,
toolOutputHasErrors = cinteropOutputHasErrors,
duration = duration
)
val res = if (exitCode != ExitCode.OK || cinteropOutputHasErrors)
TestCompilationResult.CompilationToolFailure(loggedInteropCall)
else
TestCompilationResult.Success(expectedArtifact, loggedInteropCall)
loggedInteropCall to res
} catch (unexpectedThrowable: Throwable) {
val loggedFailure = LoggedData.CompilationToolCallUnexpectedFailure(loggedCInteropParameters, unexpectedThrowable)
val res = TestCompilationResult.UnexpectedFailure(loggedFailure)
loggedFailure to res
}
expectedArtifact.logFile.writeText(loggedCall.toString())
immediateResult
}
}
internal class ExecutableCompilation(
settings: Settings,
freeCompilerArgs: TestCompilerArgs,
@@ -18,8 +18,8 @@ internal sealed interface TestCompilationResult<A : TestCompilationArtifact> {
data class Success<A : TestCompilationArtifact>(val resultingArtifact: A, override val loggedData: LoggedData.CompilerCall) :
ImmediateResult<A>
data class CompilerFailure(override val loggedData: LoggedData.RealCompilerCall) : Failure
data class UnexpectedFailure(override val loggedData: LoggedData.CompilerCallUnexpectedFailure) : Failure
data class CompilationToolFailure(override val loggedData: LoggedData.CompilationToolCall) : Failure
data class UnexpectedFailure(override val loggedData: LoggedData) : Failure
data class DependencyFailures(val causes: Set<Failure>) : TestCompilationResult<Nothing>
companion object {
@@ -31,7 +31,7 @@ internal sealed interface TestCompilationResult<A : TestCompilationArtifact> {
private fun Failure.describeFailure() = loggedData.withErrorMessage(
when (this@describeFailure) {
is CompilerFailure -> "Compilation failed."
is CompilationToolFailure -> "Compilation failed."
is UnexpectedFailure -> "Compilation failed with unexpected exception."
}
)
@@ -20,7 +20,7 @@ internal class LocalTestNameExtractor(
override val outputFilter get() = TestOutputFilter.NO_FILTERING
override fun getLoggedParameters() = LoggedData.TestRunParameters(
compilerCall = executable.loggedCompilerCall,
compilationToolCall = executable.loggedCompilationToolCall,
testCaseId = null,
runArgs = programArgs,
runParameters = null
@@ -25,7 +25,7 @@ internal class LocalTestRunner(private val testRun: TestRun) : AbstractLocalProc
get() = if (testRun.runParameters.has<TestRunParameter.WithTCTestLogger>()) TCTestOutputFilter else TestOutputFilter.NO_FILTERING
override fun getLoggedParameters() = LoggedData.TestRunParameters(
compilerCall = executable.loggedCompilerCall,
compilationToolCall = executable.loggedCompilationToolCall,
testCaseId = testRun.testCaseId,
runArgs = programArgs,
runParameters = testRun.runParameters
@@ -18,7 +18,7 @@ import java.io.IOException
internal class TestExecutable(
val executableFile: File,
val loggedCompilerCall: LoggedData.CompilerCall,
val loggedCompilationToolCall: LoggedData.CompilerCall,
val testNames: Collection<TestName>
) {
companion object {
@@ -43,7 +43,7 @@ internal class TestExecutable(
return TestExecutable(
executableFile = compilationResult.resultingArtifact.executableFile,
loggedCompilerCall = compilationResult.loggedData,
loggedCompilationToolCall = compilationResult.loggedData,
testNames = testNames
)
}
@@ -100,6 +100,12 @@ internal sealed interface TestRunParameter {
class WithExpectedOutputData(val expectedOutputDataFile: File) : TestRunParameter {
override fun applyTo(programArgs: MutableList<String>) = Unit
}
class WithFreeCommandLineArguments(val args: List<String>) : TestRunParameter {
override fun applyTo(programArgs: MutableList<String>) {
programArgs += args
}
}
}
internal inline fun <reified T : TestRunParameter> List<TestRunParameter>.has(): Boolean =
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.konan.blackboxtest.support.util
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact
internal fun TestCompilationArtifact.KLIB.getContents(kotlinNativeClassLoader: ClassLoader): String {
val libraryClass = Class.forName("org.jetbrains.kotlin.cli.klib.Library", true, kotlinNativeClassLoader)
val entryPoint = libraryClass.declaredMethods.single { it.name == "contents" }
val lib = libraryClass.getDeclaredConstructor(String::class.java, String::class.java, String::class.java)
.newInstance(klibFile.canonicalPath, null, "host")
val output = StringBuilder()
entryPoint.invoke(lib, output, false)
return output.toString()
}