[Native][Tests] Refactor CExport tests for future changes

1. Unify BinaryLibraryKind type and move it to TestSettings
2. Pass it via ClassSettings instead of constructor parameters.
3. Update GenerateNativeTests.kt to generate CExport tests as a matrix.
This commit is contained in:
Sergey Bogolepov
2024-02-15 18:32:02 +02:00
committed by Space Team
parent 9606a5a441
commit 06c0977408
13 changed files with 95 additions and 84 deletions
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.konan.test.blackbox;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty;
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -18,7 +20,8 @@ import java.util.regex.Pattern;
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/CExport")
@TestDataPath("$PROJECT_ROOT")
public class CExportTestStaticGenerated extends AbstractNativeCExportStaticTest {
@EnforcedProperty(property = ClassLevelProperty.BINARY_LIBRARY_KIND, propertyValue = "DYNAMIC")
public class CExportDynamicTestGenerated extends AbstractNativeCExportTest {
@Test
public void testAllFilesPresentInCExport() {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/CExport"), Pattern.compile("^([^_](.+))$"), null, false);
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.konan.test.blackbox;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty;
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -18,7 +20,8 @@ import java.util.regex.Pattern;
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/CExport")
@TestDataPath("$PROJECT_ROOT")
public class CExportTestDynamicGenerated extends AbstractNativeCExportDynamicTest {
@EnforcedProperty(property = ClassLevelProperty.BINARY_LIBRARY_KIND, propertyValue = "STATIC")
public class CExportStaticTestGenerated extends AbstractNativeCExportTest {
@Test
public void testAllFilesPresentInCExport() {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/CExport"), Pattern.compile("^([^_](.+))$"), null, false);
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.konan.test.blackbox;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty;
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty;
import org.junit.jupiter.api.Tag;
import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline;
import org.jetbrains.kotlin.test.TestMetadata;
@@ -20,11 +22,12 @@ import java.util.regex.Pattern;
@SuppressWarnings("all")
@TestMetadata("native/native.tests/testData/CExport")
@TestDataPath("$PROJECT_ROOT")
@EnforcedProperty(property = ClassLevelProperty.BINARY_LIBRARY_KIND, propertyValue = "DYNAMIC")
@Tag("frontend-fir")
@FirPipeline()
public class FirCExportTestStaticGenerated extends AbstractNativeCExportStaticTest {
public class FirCExportDynamicTestGenerated extends AbstractNativeCExportTest {
@Test
public void testAllFilesPresentInCExport() {
public void testAllFilesPresentInCExport() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/CExport"), Pattern.compile("^([^_](.+))$"), null, false);
}
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.konan.test.blackbox;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty;
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty;
import org.junit.jupiter.api.Tag;
import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline;
import org.jetbrains.kotlin.test.TestMetadata;
@@ -22,9 +24,9 @@ import java.util.regex.Pattern;
@TestDataPath("$PROJECT_ROOT")
@Tag("frontend-fir")
@FirPipeline()
public class FirCExportTestDynamicGenerated extends AbstractNativeCExportDynamicTest {
public class FirCExportStaticTestGenerated extends AbstractNativeCExportTest {
@Test
public void testAllFilesPresentInCExport() {
public void testAllFilesPresentInCExport() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/CExport"), Pattern.compile("^([^_](.+))$"), null, false);
}
@@ -459,33 +459,30 @@ fun main() {
model("standalone")
}
}
val binaryLibraryKinds = mapOf(
"Static" to binaryLibraryKind("STATIC"),
"Dynamic" to binaryLibraryKind("DYNAMIC"),
)
val frontendFlags = mapOf(
"Classic" to arrayOf(),
"Fir" to frontendFir(),
)
// C Export
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
testClass<AbstractNativeCExportDynamicTest>(
suiteTestClassName = "CExportTestDynamicGenerated"
) {
model("CExport", pattern = "^([^_](.+))$", recursive = false)
}
testClass<AbstractNativeCExportDynamicTest>(
suiteTestClassName = "FirCExportTestDynamicGenerated",
annotations = listOf(
*frontendFir()
),
) {
model("CExport", pattern = "^([^_](.+))$", recursive = false)
}
testClass<AbstractNativeCExportStaticTest>(
suiteTestClassName = "CExportTestStaticGenerated"
) {
model("CExport", pattern = "^([^_](.+))$", recursive = false)
}
testClass<AbstractNativeCExportStaticTest>(
suiteTestClassName = "FirCExportTestStaticGenerated",
annotations = listOf(
*frontendFir()
),
) {
model("CExport", pattern = "^([^_](.+))$", recursive = false)
binaryLibraryKinds.forEach { binaryKind ->
frontendFlags.forEach { frontend ->
val frontendKey = if (frontend.key == "Classic") "" else frontend.key
val suiteTestClassName = "${frontendKey}CExport${binaryKind.key}TestGenerated"
testClass<AbstractNativeCExportTest>(
suiteTestClassName,
annotations = listOf(
binaryKind.value,
*frontend.value
)
) {
model("CExport", pattern = "^([^_](.+))$", recursive = false)
}
}
}
}
// Swift Export
@@ -564,3 +561,8 @@ private fun standalone() = arrayOf(
"propertyValue" to "STANDALONE_NO_TR"
)
)
private fun binaryLibraryKind(kind: String = "DYNAMIC") = annotation(
EnforcedProperty::class.java,
"property" to ClassLevelProperty.BINARY_LIBRARY_KIND,
"propertyValue" to kind
)
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilat
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestExecutable
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestRunCheck
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestRunChecks
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.BinaryLibraryKind
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.KotlinNativeTargets
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.Timeouts
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.configurables
@@ -33,17 +34,33 @@ import org.junit.jupiter.api.Tag
import java.io.File
@Tag("cexport")
abstract class AbstractNativeCExportTest(
protected val libraryKind: BinaryLibraryKind,
) : AbstractNativeSimpleTest() {
abstract class AbstractNativeCExportTest() : AbstractNativeSimpleTest() {
enum class BinaryLibraryKind {
STATIC, DYNAMIC
private val libraryKind: BinaryLibraryKind by lazy {
testRunSettings.get<BinaryLibraryKind>()
}
internal open fun getKindSpecificClangFlags(binaryLibrary: TestCompilationArtifact.BinaryLibrary): List<String> = emptyList()
private fun getKindSpecificClangFlags(binaryLibrary: TestCompilationArtifact.BinaryLibrary): List<String> = when (libraryKind) {
BinaryLibraryKind.STATIC -> testRunSettings.configurables.linkerKonanFlags.flatMap { listOf("-Xlinker", it) }
BinaryLibraryKind.DYNAMIC -> {
if (testRunSettings.get<KotlinNativeTargets>().testTarget.family != Family.MINGW) {
listOf("-rpath", binaryLibrary.libraryFile.parentFile.absolutePath)
} else {
// --allow-multiple-definition is needed because finalLinkCommands statically links a lot of MinGW-specific libraries,
// that are already included in DLL produced by Kotlin/Native.
listOf("-Wl,--allow-multiple-definition")
}
}
}
internal open fun checkTestPrerequisites() {}
internal open fun checkTestPrerequisites() {
when (libraryKind) {
BinaryLibraryKind.STATIC -> if (targets.testTarget.family == Family.MINGW) {
Assumptions.abort<Nothing>("Testing of static libraries is not supported for MinGW targets.")
}
BinaryLibraryKind.DYNAMIC -> {}
}
}
private val testCompilationFactory = TestCompilationFactory()
@@ -67,7 +84,7 @@ abstract class AbstractNativeCExportTest(
val binaryLibrary = testCompilationFactory.testCaseToBinaryLibrary(
testCase,
testRunSettings,
kind = libraryKind.mapToArtifactKind(),
kind = libraryKind,
).result.assertSuccess().resultingArtifact
val clangExecutableName = "clangMain"
@@ -119,30 +136,4 @@ abstract class AbstractNativeCExportTest(
initialize(null, null)
}
}
private fun BinaryLibraryKind.mapToArtifactKind(): TestCompilationArtifact.BinaryLibrary.Kind = when (this) {
BinaryLibraryKind.STATIC -> TestCompilationArtifact.BinaryLibrary.Kind.STATIC
BinaryLibraryKind.DYNAMIC -> TestCompilationArtifact.BinaryLibrary.Kind.DYNAMIC
}
}
abstract class AbstractNativeCExportStaticTest() : AbstractNativeCExportTest(libraryKind = BinaryLibraryKind.STATIC) {
override fun getKindSpecificClangFlags(binaryLibrary: TestCompilationArtifact.BinaryLibrary): List<String> =
testRunSettings.configurables.linkerKonanFlags.flatMap { listOf("-Xlinker", it) }
override fun checkTestPrerequisites() {
if (targets.testTarget.family == Family.MINGW) {
Assumptions.abort<Nothing>("Testing of static libraries is not supported for MinGW targets.")
}
}
}
abstract class AbstractNativeCExportDynamicTest() : AbstractNativeCExportTest(libraryKind = BinaryLibraryKind.DYNAMIC) {
override fun getKindSpecificClangFlags(binaryLibrary: TestCompilationArtifact.BinaryLibrary): List<String> =
if (testRunSettings.get<KotlinNativeTargets>().testTarget.family != Family.MINGW) {
listOf("-rpath", binaryLibrary.libraryFile.parentFile.absolutePath)
} else {
// --allow-multiple-definition is needed because finalLinkCommands statically links a lot of MinGW-specific libraries,
// that are already included in DLL produced by Kotlin/Native.
listOf("-Wl,--allow-multiple-definition")
}
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilat
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestExecutable
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestRunCheck
import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestRunChecks
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.BinaryLibraryKind
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.Timeouts
import org.jetbrains.kotlin.konan.test.blackbox.support.util.DEFAULT_MODULE_NAME
import org.jetbrains.kotlin.konan.test.blackbox.support.util.createModuleMap
@@ -48,7 +49,7 @@ abstract class AbstractNativeSwiftExportTest() : AbstractNativeSimpleTest() {
val testCase = generateSwiftExportTestCase(testName, kotlinFiles + swiftExportOutput.kotlinBridges.toFile())
val kotlinBinaryLibrary = testCompilationFactory.testCaseToBinaryLibrary(
testCase, testRunSettings,
kind = TestCompilationArtifact.BinaryLibrary.Kind.DYNAMIC,
kind = BinaryLibraryKind.DYNAMIC,
).result.assertSuccess().resultingArtifact
val bridgeModuleFile = createModuleMap(buildDir, swiftExportOutput.cHeaderBridges.toFile())
@@ -72,6 +72,7 @@ internal enum class ClassLevelProperty(val shortName: String) {
COMPILER_OUTPUT_INTERCEPTOR("compilerOutputInterceptor"),
PIPELINE_TYPE("pipelineType"),
SHARED_TEST_EXECUTION("sharedTestExecution"),
BINARY_LIBRARY_KIND("binaryLibraryKind"),
;
internal val propertyName = fullPropertyName(shortName)
@@ -209,6 +209,7 @@ internal object NativeTestSupport {
output += computePipelineType(enforcedProperties, testClass.get())
output += computeUsedPartialLinkageConfig(enclosingTestClass)
output += computeCompilerOutputInterceptor(enforcedProperties)
output += computeBinaryLibraryKind(enforcedProperties)
return nativeTargets
}
@@ -505,6 +506,8 @@ internal object NativeTestSupport {
return UsedPartialLinkageConfig(config)
}
private fun computeBinaryLibraryKind(enforcedProperties: EnforcedProperties): BinaryLibraryKind =
ClassLevelProperty.BINARY_LIBRARY_KIND.readValue(enforcedProperties, BinaryLibraryKind.values(), BinaryLibraryKind.STATIC)
/*************** Test class settings (simplified) ***************/
private fun ExtensionContext.getOrCreateSimpleTestClassSettings(): SimpleTestClassSettings =
@@ -330,7 +330,8 @@ internal class BinaryLibraryCompilation(
freeCompilerArgs: TestCompilerArgs,
sourceModules: Collection<TestModule>,
dependencies: Iterable<TestCompilationDependency<*>>,
expectedArtifact: BinaryLibrary
expectedArtifact: BinaryLibrary,
private val kind: BinaryLibraryKind,
) : SourceBasedCompilation<BinaryLibrary>(
targets = settings.get(),
home = settings.get(),
@@ -353,9 +354,9 @@ internal class BinaryLibraryCompilation(
override val binaryOptions get() = BinaryOptions.RuntimeAssertionsMode.defaultForTesting(optimizationMode, freeCompilerArgs.assertionsMode)
override fun applySpecificArgs(argsBuilder: ArgsBuilder) = with(argsBuilder) {
val libraryKind = when (expectedArtifact.kind) {
BinaryLibrary.Kind.STATIC -> "static"
BinaryLibrary.Kind.DYNAMIC -> "dynamic"
val libraryKind = when (kind) {
BinaryLibraryKind.STATIC -> "static"
BinaryLibraryKind.DYNAMIC -> "dynamic"
}
add(
"-produce", libraryKind,
@@ -40,11 +40,7 @@ internal sealed interface TestCompilationArtifact {
val mainHeader: File get() = headersDir.resolve("$frameworkName.h")
}
data class BinaryLibrary(val libraryFile: File, val kind: Kind) : TestCompilationArtifact {
enum class Kind {
STATIC, DYNAMIC
}
data class BinaryLibrary(val libraryFile: File) : TestCompilationArtifact {
override val logFile: File get() = libraryFile.resolveSibling("${libraryFile.name}.log")
@@ -33,7 +33,7 @@ internal class TestCompilationFactory {
private data class KlibCacheKey(val sourceModules: Set<TestModule>, val freeCompilerArgs: TestCompilerArgs)
private data class ExecutableCacheKey(val sourceModules: Set<TestModule>)
private data class ObjCFrameworkCacheKey(val sourceModules: Set<TestModule>)
private data class BinaryLibraryCacheKey(val sourceModules: Set<TestModule>, val kind: BinaryLibrary.Kind)
private data class BinaryLibraryCacheKey(val sourceModules: Set<TestModule>, val kind: BinaryLibraryKind)
// A pair of compilations for a KLIB itself and for its static cache that are created together.
private data class KlibCompilations(val klib: TestCompilation<KLIB>, val staticCache: TestCompilation<KLIBStaticCache>?)
@@ -86,7 +86,7 @@ internal class TestCompilationFactory {
}
}
fun testCaseToBinaryLibrary(testCase: TestCase, settings: Settings, kind: BinaryLibrary.Kind): BinaryLibraryCompilation {
fun testCaseToBinaryLibrary(testCase: TestCase, settings: Settings, kind: BinaryLibraryKind): BinaryLibraryCompilation {
val rootModules = testCase.rootModules
val cacheKey = BinaryLibraryCacheKey(testCase.rootModules, kind)
cachedBinaryLibraryCompilations[cacheKey]?.let { return it }
@@ -97,14 +97,15 @@ internal class TestCompilationFactory {
) = getDependenciesAndSourceModules(settings, testCase.rootModules, testCase.freeCompilerArgs) {
ProduceStaticCache.No
}
val expectedArtifact = BinaryLibrary(settings.artifactFileForBinaryLibrary(rootModules, kind), kind = kind)
val expectedArtifact = BinaryLibrary(settings.artifactFileForBinaryLibrary(rootModules, kind))
return cachedBinaryLibraryCompilations.computeIfAbsent(cacheKey) {
BinaryLibraryCompilation(
settings = settings,
freeCompilerArgs = testCase.freeCompilerArgs,
sourceModules = sourceModules,
dependencies = dependencies,
expectedArtifact = expectedArtifact
expectedArtifact = expectedArtifact,
kind = kind,
)
}
}
@@ -330,17 +331,17 @@ internal class TestCompilationFactory {
private fun Settings.artifactFileForExecutable(module: TestModule.Exclusive) =
singleModuleArtifactFile(module, get<KotlinNativeTargets>().testTarget.family.exeSuffix)
private fun Settings.pickBinaryLibrarySuffix(kind: BinaryLibrary.Kind) = when (kind) {
BinaryLibrary.Kind.STATIC -> get<KotlinNativeTargets>().testTarget.family.staticSuffix
BinaryLibrary.Kind.DYNAMIC -> get<KotlinNativeTargets>().testTarget.family.dynamicSuffix
private fun Settings.pickBinaryLibrarySuffix(kind: BinaryLibraryKind) = when (kind) {
BinaryLibraryKind.STATIC -> get<KotlinNativeTargets>().testTarget.family.staticSuffix
BinaryLibraryKind.DYNAMIC -> get<KotlinNativeTargets>().testTarget.family.dynamicSuffix
}
private fun Settings.artifactFileForBinaryLibrary(modules: Set<TestModule.Exclusive>, kind: BinaryLibrary.Kind) = when (modules.size) {
private fun Settings.artifactFileForBinaryLibrary(modules: Set<TestModule.Exclusive>, kind: BinaryLibraryKind) = when (modules.size) {
1 -> artifactFileForBinaryLibrary(modules.first(), kind)
else -> multiModuleArtifactFile(modules, pickBinaryLibrarySuffix(kind))
}
private fun Settings.artifactFileForBinaryLibrary(module: TestModule.Exclusive, kind: BinaryLibrary.Kind) =
private fun Settings.artifactFileForBinaryLibrary(module: TestModule.Exclusive, kind: BinaryLibraryKind) =
singleModuleArtifactFile(module, pickBinaryLibrarySuffix(kind))
private fun Settings.artifactFileForKlib(modules: Set<TestModule>, freeCompilerArgs: TestCompilerArgs): File =
@@ -295,3 +295,7 @@ internal enum class CompilerOutputInterceptor {
DEFAULT,
NONE
}
internal enum class BinaryLibraryKind {
STATIC, DYNAMIC
}