[Native][tests] Refactoring: Rework Settings/GlobalSettings
This commit is contained in:
+51
-37
@@ -6,9 +6,11 @@
|
||||
package org.jetbrains.kotlin.konan.blackboxtest.support
|
||||
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeBlackBoxTest
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.StandardTestCaseGroupProvider
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.TestCaseGroupProvider
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.TestCaseGroupProviding
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.GlobalSettings
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.TestRoots
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.TestSettings
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||
import org.jetbrains.kotlin.test.TestMetadata
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals
|
||||
@@ -35,7 +37,7 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
|
||||
enclosingTestInstance.onRunProviderSet()
|
||||
|
||||
// Set the essential compiler property.
|
||||
System.setProperty("kotlin.native.home", getOrCreateGlobalEnvironment().kotlinNativeHome.path)
|
||||
System.setProperty("kotlin.native.home", getOrCreateGlobalSettings().kotlinNativeHome.path)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -46,13 +48,14 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
|
||||
val enclosingTestClass = enclosingTestClass
|
||||
|
||||
return root.getStore(NAMESPACE).getOrComputeIfAbsent(enclosingTestClass.sanitizedName) {
|
||||
val globalEnvironment = getOrCreateGlobalEnvironment()
|
||||
val globalSettings = getOrCreateGlobalSettings()
|
||||
val (testSettings, testSettingsAnnotation) = computeTestSettings(enclosingTestClass)
|
||||
|
||||
val testRoots = computeTestRoots()
|
||||
val testRoots = computeTestRoots(enclosingTestClass)
|
||||
|
||||
val uniqueEnclosingClassDirName = globalEnvironment.target.compressedName + "_" + enclosingTestClass.compressedSimpleName
|
||||
val uniqueEnclosingClassDirName = globalSettings.target.compressedName + "_" + enclosingTestClass.compressedSimpleName
|
||||
|
||||
val testSourcesDir = globalEnvironment.baseBuildDir
|
||||
val testSourcesDir = globalSettings.baseBuildDir
|
||||
.resolve("bbtest.src")
|
||||
.resolve(uniqueEnclosingClassDirName)
|
||||
.ensureExistsAndIsEmptyDirectory() // Clean-up the directory with all potentially stale generated sources.
|
||||
@@ -61,7 +64,7 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
|
||||
.resolve("__shared_modules__")
|
||||
.ensureExistsAndIsEmptyDirectory()
|
||||
|
||||
val testBinariesDir = globalEnvironment.baseBuildDir
|
||||
val testBinariesDir = globalSettings.baseBuildDir
|
||||
.resolve("bbtest.bin")
|
||||
.resolve(uniqueEnclosingClassDirName)
|
||||
.ensureExistsAndIsEmptyDirectory() // Clean-up the directory with all potentially stale artifacts.
|
||||
@@ -70,8 +73,8 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
|
||||
.resolve("__shared_modules__")
|
||||
.ensureExistsAndIsEmptyDirectory()
|
||||
|
||||
val environment = TestEnvironment(
|
||||
globalEnvironment = globalEnvironment,
|
||||
val settings = Settings(
|
||||
global = globalSettings,
|
||||
testRoots = testRoots,
|
||||
testSourcesDir = testSourcesDir,
|
||||
sharedSourcesDir = sharedSourcesDir,
|
||||
@@ -79,16 +82,16 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
|
||||
sharedBinariesDir = sharedBinariesDir
|
||||
)
|
||||
|
||||
val testCaseGroupProvider = requiredTestClass.createTestCaseGroupProvider(environment)
|
||||
val testCaseGroupProvider = createTestCaseGroupProvider(settings, testSettings, testSettingsAnnotation)
|
||||
|
||||
TestRunProvider(environment, testCaseGroupProvider)
|
||||
TestRunProvider(settings, testCaseGroupProvider)
|
||||
}.cast()
|
||||
}
|
||||
|
||||
private fun ExtensionContext.getOrCreateGlobalEnvironment(): GlobalTestEnvironment =
|
||||
root.getStore(NAMESPACE).getOrComputeIfAbsent(GlobalTestEnvironment::class.java.sanitizedName) {
|
||||
private fun ExtensionContext.getOrCreateGlobalSettings(): GlobalSettings =
|
||||
root.getStore(NAMESPACE).getOrComputeIfAbsent(GlobalSettings::class.java.sanitizedName) {
|
||||
// Create with the default settings.
|
||||
GlobalTestEnvironment()
|
||||
GlobalSettings()
|
||||
}.cast()
|
||||
|
||||
private val ExtensionContext.enclosingTestInstance: AbstractNativeBlackBoxTest
|
||||
@@ -97,9 +100,7 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
|
||||
private val ExtensionContext.enclosingTestClass: Class<*>
|
||||
get() = generateSequence(requiredTestClass) { it.enclosingClass }.last()
|
||||
|
||||
private fun ExtensionContext.computeTestRoots(): TestRoots {
|
||||
val enclosingTestClass = enclosingTestClass
|
||||
|
||||
private fun computeTestRoots(enclosingTestClass: Class<*>): TestRoots {
|
||||
val testRoots: Set<File> = when (val outermostTestMetadata = enclosingTestClass.getAnnotation(TestMetadata::class.java)) {
|
||||
null -> {
|
||||
enclosingTestClass.declaredClasses.mapNotNullToSet { nestedClass ->
|
||||
@@ -125,35 +126,48 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
|
||||
return TestRoots(testRoots, baseDir)
|
||||
}
|
||||
|
||||
private fun Class<*>.createTestCaseGroupProvider(environment: TestEnvironment): TestCaseGroupProvider {
|
||||
val (providerAnnotation, providerAnnotationClass, providerClass) = annotations.asSequence()
|
||||
.mapNotNull { annotation ->
|
||||
val annotationClass = annotation.annotationClass
|
||||
val providerClass = annotationClass.findAnnotation<TestCaseGroupProviding>()?.providerClass ?: return@mapNotNull null
|
||||
Triple(annotation, annotationClass, providerClass)
|
||||
private fun computeTestSettings(enclosingTestClass: Class<*>): Pair<TestSettings, Annotation?> {
|
||||
val findTestSettings: Class<*>.() -> Pair<TestSettings, Annotation>? = {
|
||||
annotations.asSequence().mapNotNull { annotation ->
|
||||
val testSettings = annotation.annotationClass.findAnnotation<TestSettings>() ?: return@mapNotNull null
|
||||
testSettings to annotation
|
||||
}.firstOrNull()
|
||||
?: return StandardTestCaseGroupProvider(environment) // Fallback if there is no annotation.
|
||||
}
|
||||
|
||||
return enclosingTestClass.findTestSettings()
|
||||
?: enclosingTestClass.declaredClasses.firstNotNullOfOrNull { it.findTestSettings() }
|
||||
?: (TestSettings.DEFAULT to null) // Fallback if there is no annotation.
|
||||
}
|
||||
|
||||
private fun createTestCaseGroupProvider(
|
||||
settings: Settings,
|
||||
testSettings: TestSettings,
|
||||
testSettingsAnnotation: Annotation?
|
||||
): TestCaseGroupProvider {
|
||||
// First, try to find two-argument constructor.
|
||||
providerClass.constructors.asSequence()
|
||||
.forEach { c ->
|
||||
val (p1, p2) = c.parameters.takeIf { it.size == 2 } ?: return@forEach
|
||||
val provider = when {
|
||||
p1.hasTypeOf<TestEnvironment>() && p2.hasTypeOf(providerAnnotationClass) -> c.call(environment, providerAnnotation)
|
||||
p1.hasTypeOf(providerAnnotationClass) && p2.hasTypeOf<TestEnvironment>() -> c.call(providerAnnotation, environment)
|
||||
else -> return@forEach
|
||||
if (testSettingsAnnotation != null) {
|
||||
val testSettingsAnnotationClass = testSettingsAnnotation.annotationClass
|
||||
|
||||
testSettings.providerClass.constructors.asSequence()
|
||||
.forEach { c ->
|
||||
val (p1, p2) = c.parameters.takeIf { it.size == 2 } ?: return@forEach
|
||||
@Suppress("Reformat") val provider = when {
|
||||
p1.hasTypeOf<Settings>() && p2.hasTypeOf(testSettingsAnnotationClass) -> c.call(settings, testSettingsAnnotation)
|
||||
p1.hasTypeOf(testSettingsAnnotationClass) && p2.hasTypeOf<Settings>() -> c.call(testSettingsAnnotation, settings)
|
||||
else -> return@forEach
|
||||
}
|
||||
return provider.cast()
|
||||
}
|
||||
return provider.cast()
|
||||
}
|
||||
}
|
||||
|
||||
// Next, try to find a single-argument constructor.
|
||||
providerClass.constructors.asSequence()
|
||||
testSettings.providerClass.constructors.asSequence()
|
||||
.forEach { c ->
|
||||
val p = c.parameters.singleOrNull() ?: return@forEach
|
||||
if (p.hasTypeOf<TestEnvironment>()) return c.call(environment).cast()
|
||||
if (p.hasTypeOf<Settings>()) return c.call(settings).cast()
|
||||
}
|
||||
|
||||
fail { "No suitable constructor for $providerClass" }
|
||||
fail { "No suitable constructor for ${testSettings.providerClass}" }
|
||||
}
|
||||
|
||||
private inline fun <reified T : Any> KParameter.hasTypeOf(): Boolean = hasTypeOf(T::class)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package org.jetbrains.kotlin.konan.blackboxtest.support
|
||||
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule.Companion.allDependencies
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.TestMode
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
|
||||
|
||||
+13
-12
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilation.Companion
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilationResult.Companion.assertSuccess
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule.Companion.allDependencies
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule.Companion.allFriends
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
|
||||
import java.io.*
|
||||
@@ -22,7 +23,7 @@ import kotlin.time.Duration
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
|
||||
internal class TestCompilationFactory(private val environment: TestEnvironment) {
|
||||
internal class TestCompilationFactory(private val settings: Settings) {
|
||||
private val cachedCompilations = ThreadSafeCache<TestCompilationCacheKey, TestCompilation>()
|
||||
|
||||
private sealed interface TestCompilationCacheKey {
|
||||
@@ -46,7 +47,7 @@ internal class TestCompilationFactory(private val environment: TestEnvironment)
|
||||
val entryPoint = testCases.singleOrNull()?.safeExtras<NoTestRunnerExtras>()?.entryPoint
|
||||
|
||||
TestCompilationImpl(
|
||||
environment = environment,
|
||||
settings = settings,
|
||||
freeCompilerArgs = freeCompilerArgs,
|
||||
sourceModules = rootModules,
|
||||
dependencies = TestCompilationDependencies(libraries = libraries, friends = friends),
|
||||
@@ -54,7 +55,7 @@ internal class TestCompilationFactory(private val environment: TestEnvironment)
|
||||
specificCompilerArgs = {
|
||||
add("-produce", "program")
|
||||
if (entryPoint != null) add("-entry", entryPoint) else add("-generate-test-runner")
|
||||
environment.globalEnvironment.getRootCacheDirectory(debuggable = true)?.let { rootCacheDir ->
|
||||
settings.global.getRootCacheDirectory(debuggable = true)?.let { rootCacheDir ->
|
||||
add("-Xcache-directory=$rootCacheDir")
|
||||
}
|
||||
}
|
||||
@@ -75,7 +76,7 @@ internal class TestCompilationFactory(private val environment: TestEnvironment)
|
||||
|
||||
return cachedCompilations.computeIfAbsent(cacheKey) {
|
||||
TestCompilationImpl(
|
||||
environment = environment,
|
||||
settings = settings,
|
||||
freeCompilerArgs = freeCompilerArgs,
|
||||
sourceModules = sourceModules,
|
||||
dependencies = TestCompilationDependencies(libraries = libraries, friends = friends),
|
||||
@@ -87,15 +88,15 @@ internal class TestCompilationFactory(private val environment: TestEnvironment)
|
||||
|
||||
private fun artifactFileForExecutable(modules: Set<TestModule.Exclusive>) = when (modules.size) {
|
||||
1 -> artifactFileForExecutable(modules.first())
|
||||
else -> multiModuleArtifactFile(modules, environment.globalEnvironment.target.family.exeSuffix)
|
||||
else -> multiModuleArtifactFile(modules, settings.global.target.family.exeSuffix)
|
||||
}
|
||||
|
||||
private fun artifactFileForExecutable(module: TestModule.Exclusive) =
|
||||
singleModuleArtifactFile(module, environment.globalEnvironment.target.family.exeSuffix)
|
||||
singleModuleArtifactFile(module, settings.global.target.family.exeSuffix)
|
||||
|
||||
private fun artifactFileForKlib(module: TestModule, freeCompilerArgs: TestCompilerArgs) = when (module) {
|
||||
is TestModule.Exclusive -> singleModuleArtifactFile(module, "klib")
|
||||
is TestModule.Shared -> environment.sharedBinariesDir.resolve("${module.name}-${prettyHash(freeCompilerArgs.hashCode())}.klib")
|
||||
is TestModule.Shared -> settings.sharedBinariesDir.resolve("${module.name}-${prettyHash(freeCompilerArgs.hashCode())}.klib")
|
||||
}
|
||||
|
||||
private fun singleModuleArtifactFile(module: TestModule.Exclusive, extension: String): File {
|
||||
@@ -141,7 +142,7 @@ internal class TestCompilationFactory(private val environment: TestEnvironment)
|
||||
}
|
||||
|
||||
private fun artifactDirForPackageName(packageName: PackageFQN?): File {
|
||||
val baseDir = environment.testBinariesDir
|
||||
val baseDir = settings.testBinariesDir
|
||||
val outputDir = if (packageName != null) baseDir.resolve(packageName.compressedPackageName) else baseDir
|
||||
|
||||
outputDir.mkdirs()
|
||||
@@ -221,7 +222,7 @@ internal class TestCompilationDependencies(
|
||||
}
|
||||
|
||||
private class TestCompilationImpl(
|
||||
private val environment: TestEnvironment,
|
||||
private val settings: Settings,
|
||||
private val freeCompilerArgs: TestCompilerArgs,
|
||||
private val sourceModules: Collection<TestModule>,
|
||||
private val dependencies: TestCompilationDependencies,
|
||||
@@ -241,8 +242,8 @@ private class TestCompilationImpl(
|
||||
add(
|
||||
"-enable-assertions",
|
||||
"-g",
|
||||
"-target", environment.globalEnvironment.target.name,
|
||||
"-repo", environment.globalEnvironment.kotlinNativeHome.resolve("klib").path,
|
||||
"-target", settings.global.target.name,
|
||||
"-repo", settings.global.kotlinNativeHome.resolve("klib").path,
|
||||
"-output", expectedArtifactFile.path,
|
||||
"-Xskip-prerelease-check",
|
||||
"-Xverify-ir",
|
||||
@@ -273,7 +274,7 @@ private class TestCompilationImpl(
|
||||
val (loggedCompilerCall: LoggedData, result: TestCompilationResult.ImmediateResult) = try {
|
||||
val (exitCode, compilerOutput, compilerOutputHasErrors, duration) = callCompiler(
|
||||
compilerArgs = compilerArgs,
|
||||
lazyKotlinNativeClassLoader = environment.globalEnvironment.lazyKotlinNativeClassLoader
|
||||
lazyKotlinNativeClassLoader = settings.global.lazyKotlinNativeClassLoader
|
||||
)
|
||||
|
||||
val loggedCompilerCall =
|
||||
|
||||
+8
-7
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilationResult.Com
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.TestCaseGroupProvider
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.AbstractRunner
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestRunner
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ThreadSafeCache
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TreeNode
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.buildTree
|
||||
@@ -24,10 +25,10 @@ import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import java.io.File
|
||||
|
||||
internal class TestRunProvider(
|
||||
private val environment: TestEnvironment,
|
||||
private val settings: Settings,
|
||||
private val testCaseGroupProvider: TestCaseGroupProvider
|
||||
) : ExtensionContext.Store.CloseableResource {
|
||||
private val compilationFactory = TestCompilationFactory(environment)
|
||||
private val compilationFactory = TestCompilationFactory(settings)
|
||||
private val cachedCompilations = ThreadSafeCache<TestCompilationCacheKey, TestCompilation>()
|
||||
|
||||
fun setProcessors(testDataFile: File, sourceTransformers: List<(String) -> String>) {
|
||||
@@ -114,7 +115,7 @@ internal class TestRunProvider(
|
||||
}
|
||||
|
||||
private fun <T> withTestExecutable(testDataFile: File, action: (TestCase, TestExecutable) -> T): T {
|
||||
environment.assertNotDisposed()
|
||||
settings.assertNotDisposed()
|
||||
|
||||
val testDataDir = testDataFile.parentFile
|
||||
val testDataFileName = testDataFile.name
|
||||
@@ -173,19 +174,19 @@ internal class TestRunProvider(
|
||||
}
|
||||
|
||||
// Currently, only local test runner is supported.
|
||||
fun createRunner(testRun: TestRun): AbstractRunner<*> = when (val target = environment.globalEnvironment.target) {
|
||||
environment.globalEnvironment.hostTarget -> LocalTestRunner(testRun, environment.globalEnvironment.executionTimeout)
|
||||
fun createRunner(testRun: TestRun): AbstractRunner<*> = when (val target = settings.global.target) {
|
||||
settings.global.hostTarget -> LocalTestRunner(testRun, settings.global.executionTimeout)
|
||||
else -> fail {
|
||||
"""
|
||||
Running at non-host target is not supported yet.
|
||||
Compilation target: $target
|
||||
Host target: ${environment.globalEnvironment.hostTarget}
|
||||
Host target: ${settings.global.hostTarget}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
Disposer.dispose(environment)
|
||||
Disposer.dispose(settings)
|
||||
}
|
||||
|
||||
private sealed class TestCompilationCacheKey {
|
||||
|
||||
+19
-18
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.WithTestRunnerExtras
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -37,8 +38,8 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.File
|
||||
|
||||
internal class ExtTestCaseGroupProvider(
|
||||
private val environment: TestEnvironment
|
||||
) : TestCaseGroupProvider, TestDisposable(parentDisposable = environment) {
|
||||
private val settings: Settings
|
||||
) : TestCaseGroupProvider, TestDisposable(parentDisposable = settings) {
|
||||
private val sourceTransformers: MutableMap<String, List<(String) -> String>> = mutableMapOf()
|
||||
private val structureFactory = ExtTestDataFileStructureFactory(parentDisposable = this)
|
||||
private val sharedModules = ThreadSafeCache<String, TestModule.Shared?>()
|
||||
@@ -58,7 +59,7 @@ internal class ExtTestCaseGroupProvider(
|
||||
|
||||
testDataFiles.forEach { testDataFile ->
|
||||
val extTestDataFile = ExtTestDataFile(
|
||||
environment, structureFactory, testDataFile, sourceTransformers[testDataFile.canonicalPath] ?: listOf()
|
||||
settings, structureFactory, testDataFile, sourceTransformers[testDataFile.canonicalPath] ?: listOf()
|
||||
)
|
||||
|
||||
if (extTestDataFile.isRelevant)
|
||||
@@ -126,7 +127,7 @@ internal class ExtTestCaseGroupProvider(
|
||||
}
|
||||
|
||||
private class ExtTestDataFile(
|
||||
private val environment: TestEnvironment,
|
||||
private val settings: Settings,
|
||||
structureFactory: ExtTestDataFileStructureFactory,
|
||||
private val testDataFile: File,
|
||||
sourceTransformers: List<(String) -> String>
|
||||
@@ -139,7 +140,7 @@ private class ExtTestDataFile(
|
||||
}
|
||||
}
|
||||
|
||||
private val settings by lazy {
|
||||
private val testDataFileSettings by lazy {
|
||||
val optIns = structure.directives.multiValues(OPT_IN_DIRECTIVE)
|
||||
val optInsForSourceCode = optIns subtract OPT_INS_PURELY_FOR_COMPILER
|
||||
val optInsForCompiler = optIns intersect OPT_INS_PURELY_FOR_COMPILER
|
||||
@@ -154,12 +155,12 @@ private class ExtTestDataFile(
|
||||
optInsForCompiler = optInsForCompiler,
|
||||
expectActualLinker = EXPECT_ACTUAL_LINKER_DIRECTIVE in structure.directives,
|
||||
generatedSourcesDir = computeGeneratedSourcesDir(
|
||||
testDataBaseDir = environment.testRoots.baseDir,
|
||||
testDataBaseDir = settings.testRoots.baseDir,
|
||||
testDataFile = testDataFile,
|
||||
generatedSourcesBaseDir = environment.testSourcesDir
|
||||
generatedSourcesBaseDir = settings.testSourcesDir
|
||||
),
|
||||
nominalPackageName = computePackageName(
|
||||
testDataBaseDir = environment.testRoots.baseDir,
|
||||
testDataBaseDir = settings.testRoots.baseDir,
|
||||
testDataFile = testDataFile
|
||||
)
|
||||
)
|
||||
@@ -168,16 +169,16 @@ private class ExtTestDataFile(
|
||||
val isRelevant: Boolean =
|
||||
isCompatibleTarget(TargetBackend.NATIVE, testDataFile) // Checks TARGET_BACKEND/DONT_TARGET_EXACT_BACKEND directives.
|
||||
&& !isIgnoredTarget(TargetBackend.NATIVE, testDataFile) // Checks IGNORE_BACKEND directive.
|
||||
&& settings.languageSettings.none { it in INCOMPATIBLE_LANGUAGE_SETTINGS }
|
||||
&& testDataFileSettings.languageSettings.none { it in INCOMPATIBLE_LANGUAGE_SETTINGS }
|
||||
&& INCOMPATIBLE_DIRECTIVES.none { it in structure.directives }
|
||||
&& structure.directives[API_VERSION_DIRECTIVE] !in INCOMPATIBLE_API_VERSIONS
|
||||
&& structure.directives[LANGUAGE_VERSION_DIRECTIVE] !in INCOMPATIBLE_LANGUAGE_VERSIONS
|
||||
|
||||
private fun assembleFreeCompilerArgs(): TestCompilerArgs {
|
||||
val args = mutableListOf<String>()
|
||||
settings.languageSettings.sorted().mapTo(args) { "-XXLanguage:$it" }
|
||||
settings.optInsForCompiler.sorted().mapTo(args) { "-Xopt-in=$it" }
|
||||
if (settings.expectActualLinker) args += "-Xexpect-actual-linker"
|
||||
testDataFileSettings.languageSettings.sorted().mapTo(args) { "-XXLanguage:$it" }
|
||||
testDataFileSettings.optInsForCompiler.sorted().mapTo(args) { "-Xopt-in=$it" }
|
||||
if (testDataFileSettings.expectActualLinker) args += "-Xexpect-actual-linker"
|
||||
return TestCompilerArgs(args)
|
||||
}
|
||||
|
||||
@@ -274,7 +275,7 @@ private class ExtTestDataFile(
|
||||
private fun patchPackageNames(isStandaloneTest: Boolean) = with(structure) {
|
||||
if (isStandaloneTest) return // Don't patch packages for standalone tests.
|
||||
|
||||
val basePackageName = FqName(settings.nominalPackageName)
|
||||
val basePackageName = FqName(testDataFileSettings.nominalPackageName)
|
||||
|
||||
val oldPackageNames: Set<FqName> = filesToTransform.mapToSet { it.packageFqName }
|
||||
val oldToNewPackageNameMapping: Map<FqName, FqName> = oldPackageNames.associateWith { oldPackageName ->
|
||||
@@ -450,7 +451,7 @@ private class ExtTestDataFile(
|
||||
fun getAnnotationText(fullyQualifiedName: String) = "@file:${OPT_IN_ANNOTATION_NAME.asString()}($fullyQualifiedName::class)"
|
||||
|
||||
// Every OptIn specified in test directive should be represented as a file-level annotation.
|
||||
settings.optInsForSourceCode.mapTo(allFileLevelAnnotations, ::getAnnotationText)
|
||||
testDataFileSettings.optInsForSourceCode.mapTo(allFileLevelAnnotations, ::getAnnotationText)
|
||||
|
||||
// Now, collect file-level annotations already present in test files.
|
||||
filesToTransform.forEach { handler ->
|
||||
@@ -550,7 +551,7 @@ private class ExtTestDataFile(
|
||||
}
|
||||
|
||||
if (!isStandaloneTest) {
|
||||
append("package ").appendLine(settings.nominalPackageName)
|
||||
append("package ").appendLine(testDataFileSettings.nominalPackageName)
|
||||
appendLine()
|
||||
}
|
||||
|
||||
@@ -574,10 +575,10 @@ private class ExtTestDataFile(
|
||||
sharedModules: ThreadSafeCache<String, TestModule.Shared?>
|
||||
): TestCase = with(structure) {
|
||||
val modules = generateModules(
|
||||
testCaseDir = settings.generatedSourcesDir,
|
||||
testCaseDir = testDataFileSettings.generatedSourcesDir,
|
||||
findOrGenerateSharedModule = { moduleName: String, generator: SharedModuleGenerator ->
|
||||
sharedModules.computeIfAbsent(moduleName) {
|
||||
generator(environment.sharedSourcesDir)
|
||||
generator(settings.sharedSourcesDir)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -587,7 +588,7 @@ private class ExtTestDataFile(
|
||||
modules = modules,
|
||||
freeCompilerArgs = assembleFreeCompilerArgs(),
|
||||
origin = TestOrigin.SingleTestDataFile(testDataFile),
|
||||
nominalPackageName = settings.nominalPackageName,
|
||||
nominalPackageName = testDataFileSettings.nominalPackageName,
|
||||
expectedOutputDataFile = null,
|
||||
extras = WithTestRunnerExtras.EMPTY
|
||||
)
|
||||
|
||||
+5
-4
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.group
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.NoTestRunnerExtras
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.WithTestRunnerExtras
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.DEFAULT_FILE_NAME
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ThreadSafeFactory
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.computeGeneratedSourcesDir
|
||||
@@ -22,7 +23,7 @@ import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
|
||||
import org.jetbrains.kotlin.test.services.impl.RegisteredDirectivesParser
|
||||
import java.io.File
|
||||
|
||||
internal class StandardTestCaseGroupProvider(private val environment: TestEnvironment) : TestCaseGroupProvider {
|
||||
internal class StandardTestCaseGroupProvider(private val settings: Settings) : TestCaseGroupProvider {
|
||||
val sourceTransformers: MutableMap<String, List<(String) -> String>> = mutableMapOf()
|
||||
|
||||
// Load test cases in groups on demand.
|
||||
@@ -51,13 +52,13 @@ internal class StandardTestCaseGroupProvider(private val environment: TestEnviro
|
||||
|
||||
private fun createTestCase(testDataFile: File): TestCase {
|
||||
val generatedSourcesDir = computeGeneratedSourcesDir(
|
||||
testDataBaseDir = environment.testRoots.baseDir,
|
||||
testDataBaseDir = settings.testRoots.baseDir,
|
||||
testDataFile = testDataFile,
|
||||
generatedSourcesBaseDir = environment.testSourcesDir
|
||||
generatedSourcesBaseDir = settings.testSourcesDir
|
||||
)
|
||||
|
||||
val nominalPackageName = computePackageName(
|
||||
testDataBaseDir = environment.testRoots.baseDir,
|
||||
testDataBaseDir = settings.testRoots.baseDir,
|
||||
testDataFile = testDataFile
|
||||
)
|
||||
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.group
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS)
|
||||
internal annotation class TestCaseGroupProviding(val providerClass: KClass<out TestCaseGroupProvider>)
|
||||
+3
-1
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.konan.blackboxtest.support.group
|
||||
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.TestSettings
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@TestCaseGroupProviding(ExtTestCaseGroupProvider::class)
|
||||
@TestSettings(ExtTestCaseGroupProvider::class)
|
||||
annotation class UseExtTestCaseGroupProvider
|
||||
|
||||
+18
-47
@@ -3,44 +3,34 @@
|
||||
* 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
|
||||
package org.jetbrains.kotlin.konan.blackboxtest.support.settings
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestDisposable
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
internal class TestEnvironment(
|
||||
val globalEnvironment: GlobalTestEnvironment,
|
||||
val testRoots: TestRoots, // The directories with original sources (aka testData).
|
||||
val testSourcesDir: File, // The directory with generated (preprocessed) test sources.
|
||||
val sharedSourcesDir: File, // The directory with the sources of the shared modules (i.e. the modules that are widely used in multiple tests).
|
||||
val testBinariesDir: File, // The directory with compiled test binaries (klibs) and executable files).
|
||||
val sharedBinariesDir: File // The directory with compiled shared modules (klibs).
|
||||
) : TestDisposable(parentDisposable = null)
|
||||
|
||||
internal class GlobalTestEnvironment(
|
||||
internal class GlobalSettings(
|
||||
val target: KonanTarget = HostManager.host,
|
||||
val kotlinNativeHome: File = defaultKotlinNativeHome,
|
||||
val lazyKotlinNativeClassLoader: Lazy<ClassLoader> = defaultKotlinNativeClassLoader,
|
||||
val testMode: TestMode = defaultTestMode,
|
||||
val cacheSettings: TestCacheSettings = defaultCacheSettings,
|
||||
val cacheSettings: CacheSettings = defaultCacheSettings,
|
||||
val executionTimeout: Duration = defaultExecutionTimeout,
|
||||
val baseBuildDir: File = projectBuildDir
|
||||
) {
|
||||
val hostTarget: KonanTarget = HostManager.host
|
||||
|
||||
fun getRootCacheDirectory(debuggable: Boolean): File? =
|
||||
(cacheSettings as? TestCacheSettings.WithCache)?.getRootCacheDirectory(this, debuggable)
|
||||
(cacheSettings as? CacheSettings.WithCache)?.getRootCacheDirectory(this, debuggable)
|
||||
|
||||
companion object {
|
||||
private val defaultKotlinNativeHome: File
|
||||
get() = System.getProperty(KOTLIN_NATIVE_HOME)?.let(::File) ?: fail { "Non-specified $KOTLIN_NATIVE_HOME system property" }
|
||||
get() = System.getProperty(KOTLIN_NATIVE_HOME)?.let(::File) ?: JUnit5Assertions.fail { "Non-specified $KOTLIN_NATIVE_HOME system property" }
|
||||
|
||||
// Use isolated cached class loader.
|
||||
private val defaultKotlinNativeClassLoader: Lazy<ClassLoader> = lazy {
|
||||
@@ -48,7 +38,7 @@ internal class GlobalTestEnvironment(
|
||||
?.split(':', ';')
|
||||
?.map { File(it).toURI().toURL() }
|
||||
?.toTypedArray()
|
||||
?: fail { "Non-specified $COMPILER_CLASSPATH system property" }
|
||||
?: JUnit5Assertions.fail { "Non-specified $COMPILER_CLASSPATH system property" }
|
||||
|
||||
URLClassLoader(nativeClassPath, /* no parent class loader */ null).apply { setDefaultAssertionStatus(true) }
|
||||
}
|
||||
@@ -56,7 +46,7 @@ internal class GlobalTestEnvironment(
|
||||
private val defaultTestMode: TestMode = run {
|
||||
val testModeName = System.getProperty(TEST_MODE) ?: return@run TestMode.WITH_MODULES
|
||||
|
||||
TestMode.values().firstOrNull { it.name == testModeName } ?: fail {
|
||||
TestMode.values().firstOrNull { it.name == testModeName } ?: JUnit5Assertions.fail {
|
||||
buildString {
|
||||
appendLine("Unknown test mode name $testModeName.")
|
||||
appendLine("One of the following test modes should be passed through $TEST_MODE system property:")
|
||||
@@ -67,27 +57,27 @@ internal class GlobalTestEnvironment(
|
||||
}
|
||||
}
|
||||
|
||||
private val defaultCacheSettings: TestCacheSettings = run {
|
||||
private val defaultCacheSettings: CacheSettings = run {
|
||||
val useCacheValue = System.getProperty(USE_CACHE)
|
||||
val useCache = if (useCacheValue != null) {
|
||||
useCacheValue.toBooleanStrictOrNull() ?: fail { "Invalid value for $USE_CACHE system property: $useCacheValue" }
|
||||
useCacheValue.toBooleanStrictOrNull() ?: JUnit5Assertions.fail { "Invalid value for $USE_CACHE system property: $useCacheValue" }
|
||||
} else
|
||||
true
|
||||
|
||||
if (useCache) TestCacheSettings.WithCache else TestCacheSettings.WithoutCache
|
||||
if (useCache) CacheSettings.WithCache else CacheSettings.WithoutCache
|
||||
}
|
||||
|
||||
private val defaultExecutionTimeout: Duration = run {
|
||||
val executionTimeoutValue = System.getProperty(EXECUTION_TIMEOUT)
|
||||
if (executionTimeoutValue != null) {
|
||||
executionTimeoutValue.toLongOrNull()?.milliseconds
|
||||
?: fail { "Invalid value for $EXECUTION_TIMEOUT system property: $executionTimeoutValue" }
|
||||
?: JUnit5Assertions.fail { "Invalid value for $EXECUTION_TIMEOUT system property: $executionTimeoutValue" }
|
||||
} else
|
||||
DEFAULT_EXECUTION_TIMEOUT
|
||||
}
|
||||
|
||||
private val projectBuildDir: File
|
||||
get() = System.getenv(PROJECT_BUILD_DIR)?.let(::File) ?: fail { "Non-specified $PROJECT_BUILD_DIR environment variable" }
|
||||
get() = System.getenv(PROJECT_BUILD_DIR)?.let(::File) ?: JUnit5Assertions.fail { "Non-specified $PROJECT_BUILD_DIR environment variable" }
|
||||
|
||||
private const val KOTLIN_NATIVE_HOME = "kotlin.internal.native.test.nativeHome"
|
||||
private const val COMPILER_CLASSPATH = "kotlin.internal.native.test.compilerClasspath"
|
||||
@@ -100,30 +90,11 @@ internal class GlobalTestEnvironment(
|
||||
}
|
||||
}
|
||||
|
||||
internal class TestRoots(
|
||||
val roots: Set<File>,
|
||||
val baseDir: File
|
||||
)
|
||||
internal sealed interface CacheSettings {
|
||||
object WithoutCache : CacheSettings
|
||||
|
||||
// TODO: in fact, only WITH_MODULES mode is supported now
|
||||
internal enum class TestMode(val description: String) {
|
||||
ONE_STAGE(
|
||||
description = "Compile test files altogether without producing intermediate KLIBs."
|
||||
),
|
||||
TWO_STAGE(
|
||||
description = "Compile test files altogether and produce an intermediate KLIB. Then produce a program from the KLIB using -Xinclude."
|
||||
),
|
||||
WITH_MODULES(
|
||||
description = "Compile each test file as one or many modules (depending on MODULE directives declared in the file)." +
|
||||
" Then link the KLIBs into the single executable file."
|
||||
)
|
||||
}
|
||||
|
||||
internal sealed interface TestCacheSettings {
|
||||
object WithoutCache : TestCacheSettings
|
||||
|
||||
object WithCache : TestCacheSettings {
|
||||
fun getRootCacheDirectory(globalEnvironment: GlobalTestEnvironment, debuggable: Boolean): File? = with(globalEnvironment) {
|
||||
object WithCache : CacheSettings {
|
||||
fun getRootCacheDirectory(settings: GlobalSettings, debuggable: Boolean): File? = with(settings) {
|
||||
kotlinNativeHome.resolve("klib/cache").resolve(getCacheDirName(target, debuggable)).takeIf { it.exists() }
|
||||
}
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.settings
|
||||
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestDisposable
|
||||
import java.io.File
|
||||
|
||||
internal class Settings(
|
||||
val global: GlobalSettings,
|
||||
val testRoots: TestRoots, // The directories with original sources (aka testData).
|
||||
val testSourcesDir: File, // The directory with generated (preprocessed) test sources.
|
||||
val sharedSourcesDir: File, // The directory with the sources of the shared modules (i.e. the modules that are widely used in multiple tests).
|
||||
val testBinariesDir: File, // The directory with compiled test binaries (klibs) and executable files).
|
||||
val sharedBinariesDir: File // The directory with compiled shared modules (klibs).
|
||||
) : TestDisposable(parentDisposable = null)
|
||||
|
||||
internal class TestRoots(
|
||||
val roots: Set<File>,
|
||||
val baseDir: File
|
||||
)
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.settings
|
||||
|
||||
// TODO: in fact, only WITH_MODULES mode is supported now
|
||||
internal enum class TestMode(val description: String) {
|
||||
ONE_STAGE(
|
||||
description = "Compile test files altogether without producing intermediate KLIBs."
|
||||
),
|
||||
TWO_STAGE(
|
||||
description = "Compile test files altogether and produce an intermediate KLIB. Then produce a program from the KLIB using -Xinclude."
|
||||
),
|
||||
WITH_MODULES(
|
||||
description = "Compile each test file as one or many modules (depending on MODULE directives declared in the file)." +
|
||||
" Then link the KLIBs into the single executable file."
|
||||
)
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.settings
|
||||
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.StandardTestCaseGroupProvider
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.TestCaseGroupProvider
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS)
|
||||
internal annotation class TestSettings(val providerClass: KClass<out TestCaseGroupProvider>) {
|
||||
companion object {
|
||||
val DEFAULT = TestSettings(StandardTestCaseGroupProvider::class)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user