compiler/util-klib/testFixtures/org/jetbrains/kotlin/library/AbstractKlibLoaderTest.kt (547 lines of code) (raw):
/*
* Copyright 2010-2025 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.library
import org.jetbrains.kotlin.konan.file.zipDirAs
import org.jetbrains.kotlin.library.loader.DefaultKlibLibraryProvider
import org.jetbrains.kotlin.library.loader.KlibLoader
import org.jetbrains.kotlin.library.loader.KlibLoaderResult
import org.jetbrains.kotlin.library.loader.KlibLoaderResult.ProblemCase
import org.jetbrains.kotlin.library.loader.KlibPlatformChecker
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInfo
import java.io.File
import java.nio.file.Files.createTempDirectory
import java.nio.file.Path
import java.nio.file.Paths
import java.util.Properties
import kotlin.collections.forEach
import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.relativeTo
import org.jetbrains.kotlin.konan.file.File as KFile
abstract class AbstractKlibLoaderTest {
protected lateinit var tmpDir: File
private set
/** Path to platform-specific stdlib. */
protected abstract val stdlib: String
private var generatedLibsCounter = 0
// These are the paths that are invalid in macOS, Linux and Windows:
private val invalidPaths: List<String>
get() = listOf(
"foo\u0000bar",
""
)
private val nonExistingPaths: List<String>
get() = listOf(
tmpDir.resolve("non-existing-library1").path,
"non-existing-library2",
"../non-existing-library3",
"./non-existing-library4",
)
@Suppress("LocalVariableName")
private val corruptedLibraryPaths: List<String> by lazy {
buildList {
// Just an empty directory.
this += tmpDir.resolve("corrupted-library1").apply { mkdirs() }
// Just an empty file.
this += tmpDir.resolve("corrupted-library2").apply { createNewFile() }
// Copy of a real KLIB without the "default" component. As a directory.
val noDefaultComponentDir = tmpDir.resolve("corrupted-library3")
File(stdlib).copyRecursively(noDefaultComponentDir)
with(noDefaultComponentDir.resolve("default")) { renameTo(resolveSibling("non-default")) }
this += noDefaultComponentDir
// Copy of a real KLIB without the "default" component. As a file.
val noDefaultComponentFile = tmpDir.resolve("corrupted-library4")
KFile(noDefaultComponentDir.path).zipDirAs(KFile(noDefaultComponentFile.path))
this += noDefaultComponentFile
// Copy of a real KLIB without a manifest. As a directory.
val noManifestDir = tmpDir.resolve("corrupted-library5")
File(stdlib).copyRecursively(noManifestDir)
noManifestDir.resolve("default/manifest").delete()
this += noManifestDir
// Copy of a real KLIB without a manifest. As a file.
val noManifestFile = tmpDir.resolve("corrupted-library6")
KFile(noManifestDir.path).zipDirAs(KFile(noManifestFile.path))
this += noManifestFile
}.flatMap { libraryFile ->
val libraryPath = libraryFile.path
// Just make a copy of the original file/directory but with an extension.
val libraryFile_klib = File("$libraryPath.klib")
libraryFile.copyRecursively(libraryFile_klib)
val libraryFile_txt = File("$libraryPath.txt")
libraryFile.copyRecursively(libraryFile_txt)
listOf(libraryFile, libraryFile_klib, libraryFile_txt)
}.map { it.path }
}
@BeforeEach
fun setup(info: TestInfo) {
tmpDir = createTempDirectory(info.testClass.get().simpleName + "-" + info.testMethod.get().name).toRealPath().toFile()
}
@AfterEach
fun tearDown() {
tmpDir.deleteRecursively()
}
@Test
fun testNoPathsToResolve() {
KlibLoader {}.load()
.assertNoLoadedLibraries()
.assertNoProblematicLibraries()
}
@Test
fun testInvalidAndNonExistingPaths() {
KlibLoader {
libraryPaths(invalidPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(notFoundPaths = invalidPaths)
KlibLoader {
libraryPaths(invalidPaths + invalidPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(notFoundPaths = invalidPaths)
KlibLoader {
libraryPaths(nonExistingPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(notFoundPaths = nonExistingPaths)
KlibLoader {
libraryPaths(nonExistingPaths + nonExistingPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(notFoundPaths = nonExistingPaths)
KlibLoader {
libraryPaths(invalidPaths + nonExistingPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(notFoundPaths = invalidPaths + nonExistingPaths)
KlibLoader {
libraryPaths(nonExistingPaths + invalidPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(notFoundPaths = nonExistingPaths + invalidPaths)
}
@Test
fun testCorruptedLibraries() {
KlibLoader {
libraryPaths(corruptedLibraryPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(invalidFormatPaths = corruptedLibraryPaths)
KlibLoader {
libraryPaths(corruptedLibraryPaths + corruptedLibraryPaths)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(invalidFormatPaths = corruptedLibraryPaths)
}
@Test
fun testValidLibraries() {
// no extension, but both file and directory KLIBs should be valid:
val a = generateNewKlib(asFile = false, fileExtension = "")
val b = generateNewKlib(asFile = true, fileExtension = "")
// "klib" extension, but both file and directory KLIBs should be valid:
val c = generateNewKlib(asFile = false, fileExtension = "klib")
val d = generateNewKlib(asFile = true, fileExtension = "klib")
// irrelevant extension, but still KLIBs should still be valid:
val e = generateNewKlib(asFile = false, fileExtension = "txt")
val f = generateNewKlib(asFile = true, fileExtension = "txt")
KlibLoader {
libraryPaths(stdlib, a, b, c, d, e, f)
}.load()
.assertLoadedLibraries(stdlib, a, b, c, d, e, f)
KlibLoader {
libraryPaths(a, stdlib, b, c, d, e, f)
}.load()
.assertLoadedLibraries(stdlib, a, b, c, d, e, f)
KlibLoader {
libraryPaths(a, b, c, d, stdlib, e, f)
}.load()
.assertLoadedLibraries(stdlib, a, b, c, d, e, f)
KlibLoader {
libraryPaths(a, b, c, d, e, f, stdlib)
}.load()
.assertLoadedLibraries(stdlib, a, b, c, d, e, f)
KlibLoader {
libraryPaths(a, b, c, d, e, f)
}.load()
.assertLoadedLibraries(a, b, c, d, e, f)
KlibLoader {
libraryPaths(a, b, a, c, a, b, d, e, b, f, b, b, f)
}.load()
.assertLoadedLibraries(a, b, c, d, e, f)
KlibLoader {
libraryPaths(a, b, a, c, a, b, d, stdlib, e, b, f, b, b, f)
}.load()
.assertLoadedLibraries(stdlib, a, b, c, d, e, f)
}
@Test
fun testMixedLibraries() {
val a = generateNewKlib(asFile = false, fileExtension = "")
val b = generateNewKlib(asFile = true, fileExtension = "klib")
KlibLoader {
libraryPaths(a)
libraryPaths(corruptedLibraryPaths)
libraryPaths(stdlib)
libraryPaths(invalidPaths)
libraryPaths(b)
}.load()
.assertLoadedLibraries(stdlib, a, b)
.assertProblematicLibraries(
notFoundPaths = invalidPaths,
invalidFormatPaths = corruptedLibraryPaths
)
}
@Test
fun testRelativePaths1() {
val foo: Path = Paths.get(generateNewKlib(asFile = false, fileExtension = ""))
val bar: Path = Paths.get(nonExistingPaths.first())
val baz: Path = Paths.get(generateNewKlib(asFile = true, fileExtension = "klib"))
val qux: Path = Paths.get(corruptedLibraryPaths.first())
val absolutePaths: List<Path> = listOf(foo, bar, baz, qux)
absolutePaths.forEach {
if (it.exists()) {
assertEquals(it.toRealPath(), it)
}
assertTrue(it.startsWith(tmpDir.path))
}
val cwd: Path = Paths.get("").toRealPath()
val transformations: List<(Path) -> Path> = listOf(
{ it }, // no changes, absolute paths
{ it.relativeTo(cwd) }, // relative paths to `tmpDir`
{ Paths.get("./").resolve(it.relativeTo(cwd)) },
{
if (it.isDirectory()) {
it.relativeTo(cwd).resolve("..").resolve(it.last())
} else it
},
)
for (transformation in transformations) {
val transformedPaths = absolutePaths.map { transformation(it).toString() }
KlibLoader {
libraryPaths(transformedPaths)
}.load()
.assertLoadedLibraries(foo, baz) // check against the original (absolute) paths
.assertProblematicLibraries(
notFoundPaths = listOf(transformation(bar)), // check against transformed paths
invalidFormatPaths = listOf(transformation(qux)), // check against transformed paths
)
}
}
/**
* This test is needed to ensure that [KlibLoader] does not mix up libraries without extension and with "klib" extension,
* and always treats them as distinct libraries, even if they have repeating "unique names".
*/
@Suppress("LocalVariableName")
@Test
fun testNoFileExtensionHeuristics() {
val libsDir = tmpDir.resolve("libs-with-distinct-names").apply { mkdirs() }
val foo = libsDir.resolve("foo").path
val foo_klib = libsDir.resolve("foo.klib").path
val bar = libsDir.resolve("bar").path
val bar_klib = libsDir.resolve("bar.klib").path
val baz = libsDir.resolve("baz").path
val baz_klib = libsDir.resolve("baz.klib").path
val qux = libsDir.resolve("qux").path
val qux_klib = libsDir.resolve("qux.klib").path
with(File(generateNewKlib(asFile = false, fileExtension = ""))) {
copyRecursively(File(foo))
copyRecursively(File(foo_klib))
copyRecursively(File(bar))
copyRecursively(File(baz_klib))
}
with(File(generateNewKlib(asFile = true, fileExtension = "klib"))) {
copyRecursively(File(bar_klib))
copyRecursively(File(baz))
copyRecursively(File(qux))
copyRecursively(File(qux_klib))
}
assertEquals(
listOf("bar", "bar.klib", "baz", "baz.klib", "foo", "foo.klib", "qux", "qux.klib"),
libsDir.list().orEmpty().sorted()
)
KlibLoader {
libraryPaths(foo, foo_klib)
libraryPaths(bar, bar_klib)
libraryPaths(baz, baz_klib)
libraryPaths(qux, qux_klib)
}.load()
.assertLoadedLibraries(foo, foo_klib, bar, bar_klib, baz, baz_klib, qux, qux_klib)
.assertNoProblematicLibraries()
KlibLoader {
libraryPaths(foo_klib, foo)
libraryPaths(bar_klib, bar)
libraryPaths(baz_klib, baz)
libraryPaths(qux_klib, qux)
}.load()
.assertLoadedLibraries(foo_klib, foo, bar_klib, bar, baz_klib, baz, qux_klib, qux)
.assertNoProblematicLibraries()
KlibLoader {
libraryPaths(bar, bar_klib)
libraryPaths(baz, baz_klib)
libraryPaths(qux, qux_klib)
libraryPaths(foo, foo_klib)
}.load()
.assertLoadedLibraries(bar, bar_klib, baz, baz_klib, qux, qux_klib, foo, foo_klib)
.assertNoProblematicLibraries()
KlibLoader {
libraryPaths(bar_klib, bar)
libraryPaths(baz_klib, baz)
libraryPaths(qux_klib, qux)
libraryPaths(foo_klib, foo)
}.load()
.assertLoadedLibraries(bar_klib, bar, baz_klib, baz, qux_klib, qux, foo_klib, foo)
.assertNoProblematicLibraries()
KlibLoader {
libraryPaths(baz, baz_klib)
libraryPaths(qux, qux_klib)
libraryPaths(foo, foo_klib)
libraryPaths(bar, bar_klib)
}.load()
.assertLoadedLibraries(baz, baz_klib, qux, qux_klib, foo, foo_klib, bar, bar_klib)
.assertNoProblematicLibraries()
KlibLoader {
libraryPaths(baz_klib, baz)
libraryPaths(qux_klib, qux)
libraryPaths(foo_klib, foo)
libraryPaths(bar_klib, bar)
}.load()
.assertLoadedLibraries(baz_klib, baz, qux_klib, qux, foo_klib, foo, bar_klib, bar)
.assertNoProblematicLibraries()
KlibLoader {
libraryPaths(qux, qux_klib)
libraryPaths(foo, foo_klib)
libraryPaths(bar, bar_klib)
libraryPaths(baz, baz_klib)
}.load()
.assertLoadedLibraries(qux, qux_klib, foo, foo_klib, bar, bar_klib, baz, baz_klib)
.assertNoProblematicLibraries()
KlibLoader {
libraryPaths(qux_klib, qux)
libraryPaths(foo_klib, foo)
libraryPaths(bar_klib, bar)
libraryPaths(baz_klib, baz)
}.load()
.assertLoadedLibraries(qux_klib, qux, foo_klib, foo, bar_klib, bar, baz_klib, baz)
.assertNoProblematicLibraries()
}
@Test
fun testRelativePaths2() {
val lib: Path = Paths.get(generateNewKlib(asFile = false, fileExtension = ""))
assertEquals(lib.toRealPath(), lib)
assertTrue(lib.startsWith(tmpDir.path))
val cwd: Path = Paths.get("").toRealPath()
val equivalentPaths: List<String> = listOf(
lib.relativeTo(cwd), // the path relative for `tmpDir`
Paths.get("./").resolve(lib.relativeTo(cwd)), // the path relative for `tmpDir`
lib, // the original absolute path
lib.relativeTo(cwd).resolve("..").resolve(lib.last()), // the path relative for `tmpDir`
).map { it.toString() }
assertEquals(equivalentPaths.size, equivalentPaths.toSet().size)
KlibLoader {
libraryPaths(equivalentPaths)
}.load()
.assertLoadedLibraries(lib) // check against original (absolute) paths
.assertNoProblematicLibraries()
}
@Test
fun testMaxPermittedAbiVersion() {
// This list of ABI versions only starts from the current version.
// Thus, it contains 4 more versions that are definitely not supported by the current compiler.
val abiVersionsStartingFromCurrent: List<KotlinAbiVersion> =
generateSequence(KotlinAbiVersion.CURRENT) { it.next() }.take(5).toList()
val abiVersionsToLibraryPaths: List<Pair<KotlinAbiVersion, String>> = abiVersionsStartingFromCurrent.map { abiVersion ->
val library = generateNewKlib(asFile = false, fileExtension = "", abiVersion = abiVersion)
abiVersion to library
}
val libraryPaths: List<String> = abiVersionsToLibraryPaths.map { (_, libraryPath) -> libraryPath }
// Load without ABI version check.
KlibLoader {
libraryPaths(libraryPaths)
}.load()
.assertLoadedLibraries(libraryPaths) // All libraries are loaded.
.assertNoProblematicLibraries()
.run {
// Check that the requested ABI versions are indeed written to KLIBs.
(abiVersionsStartingFromCurrent zip librariesStdlibFirst).forEach { (abiVersion, library) ->
assertEquals(abiVersion, library.versions.abiVersion)
}
}
for (i in abiVersionsStartingFromCurrent.indices) {
KlibLoader {
libraryPaths(libraryPaths)
maxPermittedAbiVersion(abiVersionsStartingFromCurrent[i])
}.load()
.assertLoadedLibraries(libraryPaths.take(i + 1))
.assertProblematicLibraries(incompatibleAbiVersionPaths = libraryPaths.drop(i + 1))
}
}
@Test
fun testMaxPermittedAbiVersionAndNoAbiVersionInManifest() {
// This list of ABI versions only starts from the current version.
// Thus, it contains 4 more versions that are definitely not supported by the current compiler.
val abiVersionsStartingFromCurrent: List<KotlinAbiVersion> =
generateSequence(KotlinAbiVersion.CURRENT) { it.next() }.take(5).toList()
val libraryPath = generateNewKlib(asFile = false, fileExtension = "")
// There is no ability to save no ABI version in manifest at all.
// Thus, we need to patch the manifest manually.
val manifestFile = File(libraryPath).resolve("default/manifest")
Properties().apply {
manifestFile.inputStream().use { load(it) }
assertTrue(containsKey(KLIB_PROPERTY_ABI_VERSION))
remove(KLIB_PROPERTY_ABI_VERSION)
assertFalse(containsKey(KLIB_PROPERTY_ABI_VERSION))
manifestFile.outputStream().use { store(it, null) }
}
// Load without ABI version check.
KlibLoader {
libraryPaths(libraryPath)
}.load()
.assertLoadedLibraries(libraryPath) // The library are loaded.
.assertNoProblematicLibraries()
.run {
assertEquals(null, librariesStdlibFirst.single().versions.abiVersion)
}
for (i in abiVersionsStartingFromCurrent.indices) {
KlibLoader {
libraryPaths(libraryPath)
maxPermittedAbiVersion(abiVersionsStartingFromCurrent[i])
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(incompatibleAbiVersionPaths = listOf(libraryPath))
}
}
@Test
fun testPlatformCheckers() {
val a = generateNewKlib(asFile = false, fileExtension = "")
val b = generateNewKlib(asFile = false, fileExtension = "")
val c = generateNewKlib(asFile = false, fileExtension = "")
assertTrue(ownPlatformCheckers.isNotEmpty())
assertTrue(alienPlatformCheckers.isNotEmpty())
(listOf(null) + ownPlatformCheckers).forEach { checker ->
KlibLoader {
libraryPaths(a, b, c)
if (checker != null) platformChecker(checker)
}.load()
.assertLoadedLibraries(a, b, c)
.assertNoProblematicLibraries()
}
alienPlatformCheckers.forEach { checker ->
KlibLoader {
libraryPaths(a, b, c)
platformChecker(checker)
}.load()
.assertNoLoadedLibraries()
.assertProblematicLibraries(platformCheckMismatchPaths = listOf(a, b, c))
}
}
@Test
fun testMultipleLibraryProviders() {
val a = generateNewKlib(asFile = false, fileExtension = "")
val b = generateNewKlib(asFile = true, fileExtension = "klib")
val allPaths = buildList {
add(a)
addAll(corruptedLibraryPaths)
add(stdlib)
addAll(invalidPaths)
add(b)
}
// Load libraries through `libraryPaths`.
KlibLoader {
libraryPaths(allPaths)
}.load()
.assertLoadedLibraries(stdlib, a, b)
.assertProblematicLibraries(
notFoundPaths = invalidPaths,
invalidFormatPaths = corruptedLibraryPaths
)
// Load libraries through a single provider.
KlibLoader {
libraryProviders(DefaultKlibLibraryProvider(allPaths))
}.load()
.assertLoadedLibraries(stdlib, a, b)
.assertProblematicLibraries(
notFoundPaths = invalidPaths,
invalidFormatPaths = corruptedLibraryPaths
)
// Load libraries through a mix of `libraryPaths` and multiple providers.
KlibLoader {
libraryProviders(DefaultKlibLibraryProvider(allPaths.shuffled())) // paths are shuffled
libraryPaths(allPaths) // paths provided through `libraryPaths` are loaded first
libraryProviders(DefaultKlibLibraryProvider(allPaths.shuffled())) // paths are shuffled
}.load()
.assertLoadedLibraries(stdlib, a, b)
.assertProblematicLibraries(
notFoundPaths = invalidPaths,
invalidFormatPaths = corruptedLibraryPaths
)
}
protected abstract val ownPlatformCheckers: List<KlibPlatformChecker>
protected abstract val alienPlatformCheckers: List<KlibPlatformChecker>
private fun KotlinAbiVersion.next() = KotlinAbiVersion(major, minor + 1, patch)
private fun KlibLoaderResult.assertNoLoadedLibraries(): KlibLoaderResult {
assertTrue(librariesStdlibFirst.isEmpty())
return this
}
private fun KlibLoaderResult.assertLoadedLibraries(libraryPaths: List<String>): KlibLoaderResult {
assertEquals(libraryPaths.size, librariesStdlibFirst.size)
val stdlib: KotlinLibrary? = librariesStdlibFirst.firstOrNull()?.takeIf { it.isAnyPlatformStdlib }
val otherLibraries: List<KotlinLibrary> = if (stdlib != null) librariesStdlibFirst.drop(1) else librariesStdlibFirst
var stdlibExpectedInPaths = stdlib != null
val otherLibrariesCanonicalPaths = libraryPaths.mapNotNull { libraryPath ->
val canonicalLibraryPath: String = File(libraryPath).canonicalPath
if (canonicalLibraryPath == stdlib?.libraryFile?.canonicalPath) {
assertTrue(stdlibExpectedInPaths)
stdlibExpectedInPaths = false
return@mapNotNull null
}
canonicalLibraryPath
}
assertEquals(otherLibrariesCanonicalPaths, otherLibraries.map { it.libraryFile.canonicalPath })
return this
}
private fun KlibLoaderResult.assertLoadedLibraries(vararg libraryPaths: String): KlibLoaderResult =
assertLoadedLibraries(libraryPaths.toList())
private fun KlibLoaderResult.assertLoadedLibraries(vararg libraryPaths: Path): KlibLoaderResult =
assertLoadedLibraries(libraryPaths.map { it.toString() })
private fun KlibLoaderResult.assertNoProblematicLibraries(): KlibLoaderResult {
assertFalse(hasProblems)
assertTrue(problematicLibraries.isEmpty())
return this
}
private fun KlibLoaderResult.assertProblematicLibraries(
notFoundPaths: List<String> = emptyList(),
invalidFormatPaths: List<String> = emptyList(),
platformCheckMismatchPaths: List<String> = emptyList(),
incompatibleAbiVersionPaths: List<String> = emptyList(),
): KlibLoaderResult {
assertEquals(
notFoundPaths.isNotEmpty() ||
invalidFormatPaths.isNotEmpty() ||
platformCheckMismatchPaths.isNotEmpty() ||
incompatibleAbiVersionPaths.isNotEmpty(),
hasProblems
)
assertEquals(
notFoundPaths.size +
invalidFormatPaths.size +
platformCheckMismatchPaths.size +
incompatibleAbiVersionPaths.size,
problematicLibraries.size
)
assertEquals(notFoundPaths, allByCase<ProblemCase.LibraryNotFound>())
assertEquals(invalidFormatPaths, allByCase<ProblemCase.InvalidLibraryFormat>())
assertEquals(platformCheckMismatchPaths, allByCase<ProblemCase.PlatformCheckMismatch>())
assertEquals(incompatibleAbiVersionPaths, allByCase<ProblemCase.IncompatibleAbiVersion>())
return this
}
@JvmName("assertProblematicLibrariesPaths")
private fun KlibLoaderResult.assertProblematicLibraries(
notFoundPaths: List<Path> = emptyList(),
invalidFormatPaths: List<Path> = emptyList(),
platformCheckMismatchPaths: List<Path> = emptyList(),
incompatibleAbiVersionPaths: List<Path> = emptyList(),
): KlibLoaderResult = assertProblematicLibraries(
notFoundPaths = notFoundPaths.map { it.toString() },
invalidFormatPaths = invalidFormatPaths.map { it.toString() },
platformCheckMismatchPaths = platformCheckMismatchPaths.map { it.toString() },
incompatibleAbiVersionPaths = incompatibleAbiVersionPaths.map { it.toString() },
)
private inline fun <reified T : ProblemCase> KlibLoaderResult.allByCase(): List<String> =
problematicLibraries.filter { it.problemCase is T }.map { it.libraryPath }
private fun generateNewKlib(asFile: Boolean, fileExtension: String, abiVersion: KotlinAbiVersion = KotlinAbiVersion.CURRENT): String {
val uid = (generatedLibsCounter++).toString().padStart(3, '0')
val baseName = "klib-as_${if (asFile) "file" else "dir"}-ext_$fileExtension-$uid"
val sourceFile = tmpDir.resolve("$baseName.kt")
sourceFile.writeText("private fun f() = Unit")
val klibLocation = tmpDir.resolve(if (fileExtension.isNotEmpty()) "$baseName.$fileExtension" else baseName)
assertFalse(klibLocation.exists()) { "KLIB should not exist before compilation: $klibLocation" }
compileKlib(
asFile = asFile,
sourceFile = sourceFile,
klibLocation = klibLocation,
abiVersion = abiVersion
)
// Sometimes the compiler sets file extension on its own. This needs to be fixed specifically for KLIB loader tests.
if (asFile && !klibLocation.exists()) {
val altKlibLocation = klibLocation.resolveSibling(klibLocation.nameWithoutExtension + ".klib")
if (altKlibLocation.exists()) altKlibLocation.renameTo(klibLocation)
}
assertTrue(klibLocation.exists()) { "KLIB should exist after compilation: $klibLocation" }
assertEquals(fileExtension, klibLocation.extension)
return klibLocation.path
}
protected abstract fun compileKlib(asFile: Boolean, sourceFile: File, klibLocation: File, abiVersion: KotlinAbiVersion)
}