[Native][tests] Extract all external source-transformation logic into AbstractExternalNativeBlackBoxTest

This abstract class is used only for generated external codegen box tests that may have custom source transformers.
This commit is contained in:
Dmitriy Dolovov
2021-12-13 12:02:59 +03:00
parent 72bb38dc68
commit a440864de4
10 changed files with 122 additions and 114 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.generators.tests
import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5 import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
import org.jetbrains.kotlin.generators.model.annotation import org.jetbrains.kotlin.generators.model.annotation
import org.jetbrains.kotlin.konan.blackboxtest.AbstractExternalNativeBlackBoxTest
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeBlackBoxTest import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeBlackBoxTest
import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseExtTestCaseGroupProvider import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseExtTestCaseGroupProvider
import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseStandardTestCaseGroupProvider import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseStandardTestCaseGroupProvider
@@ -19,7 +20,7 @@ fun main() {
generateTestGroupSuiteWithJUnit5 { generateTestGroupSuiteWithJUnit5 {
// External box tests. // External box tests.
testGroup("native/native.tests/tests-gen", "compiler/testData") { testGroup("native/native.tests/tests-gen", "compiler/testData") {
testClass<AbstractNativeBlackBoxTest>( testClass<AbstractExternalNativeBlackBoxTest>(
suiteTestClassName = "ExternalTestGenerated", suiteTestClassName = "ExternalTestGenerated",
annotations = listOf(external(), provider<UseExtTestCaseGroupProvider>()) annotations = listOf(external(), provider<UseExtTestCaseGroupProvider>())
) { ) {
@@ -0,0 +1,27 @@
/*
* 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
import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ExternalSourceTransformer
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ExternalSourceTransformers
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ExternalSourceTransformersProvider
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ThreadSafeCache
import org.jetbrains.kotlin.konan.blackboxtest.support.util.getAbsoluteFile
import java.io.File
abstract class AbstractExternalNativeBlackBoxTest : ExternalSourceTransformersProvider, AbstractNativeBlackBoxTest() {
private val registeredSourceTransformers: ThreadSafeCache<File, MutableList<ExternalSourceTransformer>> = ThreadSafeCache()
override fun getSourceTransformers(testDataFile: File): ExternalSourceTransformers? = registeredSourceTransformers[testDataFile]
/**
* Called directly from test class constructor.
*/
fun register(@TestDataFile testDataFilePath: String, sourceTransformer: ExternalSourceTransformer) {
registeredSourceTransformers.computeIfAbsent(getAbsoluteFile(testDataFilePath)) { mutableListOf() } += sourceTransformer
}
}
@@ -7,31 +7,17 @@ package org.jetbrains.kotlin.konan.blackboxtest
import com.intellij.testFramework.TestDataFile import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.konan.blackboxtest.support.* import org.jetbrains.kotlin.konan.blackboxtest.support.*
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName import org.jetbrains.kotlin.konan.blackboxtest.support.util.TreeNode
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseId import org.jetbrains.kotlin.konan.blackboxtest.support.util.getAbsoluteFile
import org.jetbrains.kotlin.konan.blackboxtest.support.TestRun import org.jetbrains.kotlin.konan.blackboxtest.support.util.joinPackageNames
import org.jetbrains.kotlin.konan.blackboxtest.support.TestRunProvider import org.jetbrains.kotlin.konan.blackboxtest.support.util.prependPackageName
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
import org.junit.jupiter.api.DynamicNode import org.junit.jupiter.api.DynamicNode
import org.junit.jupiter.api.DynamicTest.dynamicTest import org.junit.jupiter.api.DynamicTest.dynamicTest
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
import java.io.File
@ExtendWith(NativeBlackBoxTestSupport::class) @ExtendWith(NativeBlackBoxTestSupport::class)
abstract class AbstractNativeBlackBoxTest { abstract class AbstractNativeBlackBoxTest {
internal lateinit var testRunProvider: TestRunProvider internal lateinit var testRunProvider: TestRunProvider
private val toBeRegistered = mutableListOf<Pair<File, List<(String) -> String>>>()
internal fun onRunProviderSet() {
for ((file, transformer) in toBeRegistered) {
testRunProvider.setProcessors(file, transformer)
}
}
fun register(@TestDataFile testDataFilePath: String, sourceTransformers: List<(String) -> String>) =
toBeRegistered.add(File(testDataFilePath) to sourceTransformers)
fun register(@TestDataFile testDataFilePath: String, sourceTransformer: (String) -> String) =
register(testDataFilePath, listOf(sourceTransformer))
/** /**
* Run JUnit test. * Run JUnit test.
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.test.TestMetadata
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.junit.jupiter.api.extension.BeforeAllCallback import org.junit.jupiter.api.extension.BeforeAllCallback
import org.junit.jupiter.api.extension.BeforeEachCallback import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.api.extension.ExtensionContext
@@ -32,7 +33,6 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
*/ */
override fun beforeEach(extensionContext: ExtensionContext): Unit = with(extensionContext) { override fun beforeEach(extensionContext: ExtensionContext): Unit = with(extensionContext) {
enclosingTestInstance.testRunProvider = getOrCreateTestRunProvider() enclosingTestInstance.testRunProvider = getOrCreateTestRunProvider()
enclosingTestInstance.onRunProviderSet()
// Set the essential compiler property. // Set the essential compiler property.
System.setProperty("kotlin.native.home", getOrCreateGlobalSettings().kotlinNativeHome.path) System.setProperty("kotlin.native.home", getOrCreateGlobalSettings().kotlinNativeHome.path)
@@ -46,9 +46,15 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
val enclosingTestClass = enclosingTestClass val enclosingTestClass = enclosingTestClass
return root.getStore(NAMESPACE).getOrComputeIfAbsent(enclosingTestClass.sanitizedName) { return root.getStore(NAMESPACE).getOrComputeIfAbsent(enclosingTestClass.sanitizedName) {
val (testSettings, testSettingsAnnotation) = computeTestSettings(enclosingTestClass) val computedTestSettings = computeTestSettings(enclosingTestClass)
val requiredSettings: Set<KClass<*>> = val requiredSettings: Set<KClass<*>> = buildSet {
/* Always required */ setOf(GlobalSettings::class, Binaries::class) +/* Custom */ testSettings.requiredSettings // Always required:
this += GlobalSettings::class
this += Binaries::class
// Custom:
addAll(computedTestSettings.testSettings.requiredSettings)
}
val globalSettings = getOrCreateGlobalSettings() val globalSettings = getOrCreateGlobalSettings()
@@ -62,7 +68,7 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
} }
}) })
val testCaseGroupProvider = createTestCaseGroupProvider(settings, testSettings, testSettingsAnnotation) val testCaseGroupProvider = createTestCaseGroupProvider(settings, computedTestSettings, enclosingTestInstance)
TestRunProvider(settings, testCaseGroupProvider) TestRunProvider(settings, testCaseGroupProvider)
}.cast() }.cast()
@@ -80,11 +86,11 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
GlobalSettings() GlobalSettings()
}.cast() }.cast()
private fun computeTestSettings(enclosingTestClass: Class<*>): Pair<TestSettings, Annotation?> { private fun computeTestSettings(enclosingTestClass: Class<*>): ComputedTestSettings {
val findTestSettings: Class<*>.() -> Pair<TestSettings, Annotation>? = { val findTestSettings: Class<*>.() -> ComputedTestSettings? = {
annotations.asSequence().mapNotNull { annotation -> annotations.asSequence().mapNotNull { annotation ->
val testSettings = annotation.annotationClass.findAnnotation<TestSettings>() ?: return@mapNotNull null val testSettings = annotation.annotationClass.findAnnotation<TestSettings>() ?: return@mapNotNull null
testSettings to annotation ComputedTestSettings(testSettings, annotation)
}.firstOrNull() }.firstOrNull()
} }
@@ -147,29 +153,29 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
private fun createTestCaseGroupProvider( private fun createTestCaseGroupProvider(
settings: Settings, settings: Settings,
testSettings: TestSettings, computedTestSettings: ComputedTestSettings,
testSettingsAnnotation: Annotation? enclosingTestInstance: AbstractNativeBlackBoxTest
): TestCaseGroupProvider { ): TestCaseGroupProvider {
// Try to find a constructor that accepts the setting and the annotation. val (testSettings: TestSettings, testSettingsAnnotation: Annotation?) = computedTestSettings
if (testSettingsAnnotation != null) { val providerClass: KClass<out TestCaseGroupProvider> = testSettings.providerClass
val testSettingsAnnotationClass = testSettingsAnnotation.annotationClass
testSettings.providerClass.constructors.asSequence() // Assumption: For simplicitys sake TestCaseGroupProvider has just one constructor.
.forEach { c -> val constructor = providerClass.constructors.singleOrNull()
val (p1, p2) = c.parameters.takeIf { it.size == 2 } ?: return@forEach ?: fail { "No or multiple constructors found for $providerClass" }
if (p1.hasTypeOf<Settings>() && p2.hasTypeOf(testSettingsAnnotationClass))
return c.call(settings, testSettingsAnnotation).cast() val testSettingsAnnotationClass: KClass<out Annotation>? = testSettingsAnnotation?.annotationClass
} val sourceTransformersProvider = enclosingTestInstance.safeAs<ExternalSourceTransformersProvider>()
val arguments = constructor.parameters.map { parameter ->
when {
parameter.hasTypeOf<Settings>() -> settings
sourceTransformersProvider != null && parameter.hasTypeOf<ExternalSourceTransformersProvider>() -> sourceTransformersProvider
testSettingsAnnotationClass != null && parameter.hasTypeOf(testSettingsAnnotationClass) -> testSettingsAnnotation
else -> fail { "Can't provide all arguments for $constructor" }
}
} }
// ... or the settings at least. return constructor.call(*arguments.toTypedArray()).cast()
testSettings.providerClass.constructors.asSequence()
.forEach { c ->
val p = c.parameters.singleOrNull() ?: return@forEach
if (p.hasTypeOf<Settings>())
return c.call(settings).cast()
}
fail { "No suitable constructor for ${testSettings.providerClass}" }
} }
private inline fun <reified T : Any> KParameter.hasTypeOf(): Boolean = hasTypeOf(T::class) private inline fun <reified T : Any> KParameter.hasTypeOf(): Boolean = hasTypeOf(T::class)
@@ -178,3 +184,5 @@ class NativeBlackBoxTestSupport : BeforeEachCallback {
private val TestMetadata.testRoot: File get() = getAbsoluteFile(localPath = value) private val TestMetadata.testRoot: File get() = getAbsoluteFile(localPath = value)
} }
} }
private data class ComputedTestSettings(val testSettings: TestSettings, val annotation: Annotation?)
@@ -17,15 +17,14 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestNameExtra
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestRunner import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestRunner
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.GlobalSettings 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.Settings
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ThreadSafeCache 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.TreeNode
import org.jetbrains.kotlin.konan.blackboxtest.support.util.buildTree import org.jetbrains.kotlin.konan.blackboxtest.support.util.buildTree
import org.jetbrains.kotlin.konan.blackboxtest.support.util.startsWith
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
import org.junit.jupiter.api.Assumptions.assumeTrue import org.junit.jupiter.api.Assumptions.assumeTrue
import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.api.extension.ExtensionContext
import java.io.File
internal class TestRunProvider( internal class TestRunProvider(
private val settings: Settings, private val settings: Settings,
@@ -35,10 +34,6 @@ internal class TestRunProvider(
private val cachedCompilations = ThreadSafeCache<TestCompilationCacheKey, TestCompilation>() private val cachedCompilations = ThreadSafeCache<TestCompilationCacheKey, TestCompilation>()
private val cachedTestNames = ThreadSafeCache<TestCompilationCacheKey, Collection<TestName>>() private val cachedTestNames = ThreadSafeCache<TestCompilationCacheKey, Collection<TestName>>()
fun setProcessors(testDataFile: File, sourceTransformers: List<(String) -> String>) {
testCaseGroupProvider.setPreprocessors(testDataFile, sourceTransformers)
}
/** /**
* Produces a single [TestRun] per [TestCase]. So-called "one test case/one test run" mode. * Produces a single [TestRun] per [TestCase]. So-called "one test case/one test run" mode.
* *
@@ -41,9 +41,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File import java.io.File
internal class ExtTestCaseGroupProvider( internal class ExtTestCaseGroupProvider(
private val settings: Settings private val settings: Settings,
private val sourceTransformersProvider: ExternalSourceTransformersProvider
) : TestCaseGroupProvider, TestDisposable(parentDisposable = settings) { ) : TestCaseGroupProvider, TestDisposable(parentDisposable = settings) {
private val sourceTransformers: MutableMap<String, List<(String) -> String>> = mutableMapOf()
private val structureFactory = ExtTestDataFileStructureFactory(parentDisposable = this) private val structureFactory = ExtTestDataFileStructureFactory(parentDisposable = this)
private val sharedModules = ThreadSafeCache<String, TestModule.Shared?>() private val sharedModules = ThreadSafeCache<String, TestModule.Shared?>()
@@ -61,9 +61,7 @@ internal class ExtTestCaseGroupProvider(
val testCases = mutableListOf<TestCase>() val testCases = mutableListOf<TestCase>()
testDataFiles.forEach { testDataFile -> testDataFiles.forEach { testDataFile ->
val extTestDataFile = ExtTestDataFile( val extTestDataFile = ExtTestDataFile(settings, structureFactory, sourceTransformersProvider, testDataFile)
settings, structureFactory, testDataFile, sourceTransformers[testDataFile.canonicalPath] ?: listOf()
)
if (extTestDataFile.isRelevant) if (extTestDataFile.isRelevant)
testCases += extTestDataFile.createTestCase( testCases += extTestDataFile.createTestCase(
@@ -77,13 +75,6 @@ internal class ExtTestCaseGroupProvider(
TestCaseGroup.Default(disabledTestCaseIds, testCases) TestCaseGroup.Default(disabledTestCaseIds, testCases)
} }
override fun setPreprocessors(testDataDir: File, preprocessors: List<(String) -> String>) {
if (preprocessors.isNotEmpty())
sourceTransformers[testDataDir.canonicalPath] = preprocessors
else
sourceTransformers.remove(testDataDir.canonicalPath)
}
override fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup? { override fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup? {
assertNotDisposed() assertNotDisposed()
assertTrue(testCaseGroupId is TestCaseGroupId.TestDataDir) assertTrue(testCaseGroupId is TestCaseGroupId.TestDataDir)
@@ -133,15 +124,17 @@ internal class ExtTestCaseGroupProvider(
private class ExtTestDataFile( private class ExtTestDataFile(
private val settings: Settings, private val settings: Settings,
structureFactory: ExtTestDataFileStructureFactory, structureFactory: ExtTestDataFileStructureFactory,
private val testDataFile: File, sourceTransformersProvider: ExternalSourceTransformersProvider,
sourceTransformers: List<(String) -> String> private val testDataFile: File
) { ) {
private val structure by lazy { private val structure by lazy {
structureFactory.ExtTestDataFileStructure(testDataFile, sourceTransformers) { line -> val customTransformers: ExternalSourceTransformers? = sourceTransformersProvider.getSourceTransformers(testDataFile)
// Remove all diagnostic parameters from the text. Examples: val allTransformers: ExternalSourceTransformers = if (customTransformers.isNullOrEmpty())
// <!NO_TAIL_CALLS_FOUND!>, <!NON_TAIL_RECURSIVE_CALL!>, <!>. MANDATORY_SOURCE_TRANSFORMERS
line.replace(DIAGNOSTIC_REGEX) { match -> match.groupValues[1] } else
} MANDATORY_SOURCE_TRANSFORMERS + customTransformers
structureFactory.ExtTestDataFileStructure(testDataFile, allTransformers)
} }
private val testDataFileSettings by lazy { private val testDataFileSettings by lazy {
@@ -633,14 +626,14 @@ private class ExtTestDataFile(
private fun Directives.multiValues(key: String, predicate: (String) -> Boolean = { true }): Set<String> = private fun Directives.multiValues(key: String, predicate: (String) -> Boolean = { true }): Set<String> =
listValues(key)?.flatMap { it.split(' ') }?.filter(predicate)?.toSet().orEmpty() listValues(key)?.flatMap { it.split(' ') }?.filter(predicate)?.toSet().orEmpty()
private val DIAGNOSTIC_REGEX = Regex("<!.*?!>(.*?)<!>")
private const val THREAD_LOCAL_ANNOTATION = "@kotlin.native.ThreadLocal" private const val THREAD_LOCAL_ANNOTATION = "@kotlin.native.ThreadLocal"
private val BOX_FUNCTION_NAME = Name.identifier("box") private val BOX_FUNCTION_NAME = Name.identifier("box")
private val OPT_IN_ANNOTATION_NAME = Name.identifier("OptIn") private val OPT_IN_ANNOTATION_NAME = Name.identifier("OptIn")
private val HELPERS_PACKAGE_NAME = Name.identifier("helpers") private val HELPERS_PACKAGE_NAME = Name.identifier("helpers")
private val TYPE_OF_NAME = Name.identifier("typeOf") private val TYPE_OF_NAME = Name.identifier("typeOf")
private val MANDATORY_SOURCE_TRANSFORMERS: ExternalSourceTransformers = listOf(DiagnosticsRemovingSourceTransformer)
} }
} }
@@ -659,16 +652,12 @@ private typealias SharedModuleCache = (moduleName: String, generator: SharedModu
private class ExtTestDataFileStructureFactory(parentDisposable: Disposable) : TestDisposable(parentDisposable) { private class ExtTestDataFileStructureFactory(parentDisposable: Disposable) : TestDisposable(parentDisposable) {
private val psiFactory = createPsiFactory(parentDisposable = this) private val psiFactory = createPsiFactory(parentDisposable = this)
inner class ExtTestDataFileStructure( inner class ExtTestDataFileStructure(originalTestDataFile: File, sourceTransformers: ExternalSourceTransformers) {
originalTestDataFile: File,
sourceTransformers: List<(String) -> String>,
initialCleanUpTransformation: (String) -> String
) {
init { init {
assertNotDisposed() assertNotDisposed()
} }
private val filesAndModules = FilesAndModules(originalTestDataFile, initialCleanUpTransformation, sourceTransformers) private val filesAndModules = FilesAndModules(originalTestDataFile, sourceTransformers)
val directives: Directives get() = filesAndModules.directives val directives: Directives get() = filesAndModules.directives
@@ -824,16 +813,12 @@ private class ExtTestDataFileStructureFactory(parentDisposable: Disposable) : Te
ExtTestModule(name, dependencies, friends) ExtTestModule(name, dependencies, friends)
} }
private inner class FilesAndModules( private inner class FilesAndModules(originalTestDataFile: File, sourceTransformers: ExternalSourceTransformers) {
originalTestDataFile: File,
initialCleanUpTransformation: (String) -> String,
sourceTransformers: List<(String) -> String>
) {
private val testFileFactory = ExtTestFileFactory() private val testFileFactory = ExtTestFileFactory()
private val generatedFiles = TestFiles.createTestFiles( private val generatedFiles = TestFiles.createTestFiles(
/* testFileName = */ DEFAULT_FILE_NAME, /* testFileName = */ DEFAULT_FILE_NAME,
/* expectedText = */ originalTestDataFile.applySourceTransformers(sourceTransformers), /* expectedText = */ originalTestDataFile.readText(),
/* factory = */ testFileFactory, /* factory = */ testFileFactory,
/* preserveLocations = */ true /* preserveLocations = */ true
) )
@@ -842,7 +827,7 @@ private class ExtTestDataFileStructureFactory(parentDisposable: Disposable) : Te
// Clean up contents of every individual test file. Important: This should be done only after parsing testData file, // Clean up contents of every individual test file. Important: This should be done only after parsing testData file,
// because parsing of testData file relies on certain directives which could be removed by the transformation. // because parsing of testData file relies on certain directives which could be removed by the transformation.
generatedFiles.forEach { file -> generatedFiles.forEach { file ->
file.text = file.text.lineSequence().joinToString("\n", transform = initialCleanUpTransformation) file.text = sourceTransformers.fold(file.text) { source, transformer -> transformer(source) }
} }
val modules = generatedFiles.map { it.module }.associateBy { it.name } val modules = generatedFiles.map { it.module }.associateBy { it.name }
@@ -65,10 +65,6 @@ internal class PredefinedTestCaseGroupProvider(private val settings: Settings, a
TestCaseGroup.Default(disabledTestCaseIds = emptySet(), testCases = listOf(testCase)) TestCaseGroup.Default(disabledTestCaseIds = emptySet(), testCases = listOf(testCase))
} }
override fun setPreprocessors(testDataDir: File, preprocessors: List<(String) -> String>) {
// do nothing
}
override fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup? { override fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup? {
assertTrue(testCaseGroupId is TestCaseGroupId.Named) assertTrue(testCaseGroupId is TestCaseGroupId.Named)
return lazyTestCaseGroups[testCaseGroupId.cast()] return lazyTestCaseGroups[testCaseGroupId.cast()]
@@ -12,10 +12,6 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.settings.GeneratedSources
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings 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.TestRoots
import org.jetbrains.kotlin.konan.blackboxtest.support.util.* import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
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
import org.jetbrains.kotlin.konan.blackboxtest.support.util.computePackageName
import org.jetbrains.kotlin.test.directives.model.Directive import org.jetbrains.kotlin.test.directives.model.Directive
import org.jetbrains.kotlin.test.services.JUnit5Assertions import org.jetbrains.kotlin.test.services.JUnit5Assertions
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals
@@ -45,13 +41,6 @@ internal class StandardTestCaseGroupProvider(private val settings: Settings) : T
TestCaseGroup.Default(disabledTestCaseIds = emptySet(), testCases = testCases) TestCaseGroup.Default(disabledTestCaseIds = emptySet(), testCases = testCases)
} }
override fun setPreprocessors(testDataDir: File, preprocessors: List<(String) -> String>) {
if (preprocessors.isNotEmpty())
sourceTransformers[testDataDir.canonicalPath] = preprocessors
else
sourceTransformers.remove(testDataDir.canonicalPath)
}
override fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup? { override fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup? {
assertTrue(testCaseGroupId is TestCaseGroupId.TestDataDir) assertTrue(testCaseGroupId is TestCaseGroupId.TestDataDir)
return lazyTestCaseGroups[testCaseGroupId.cast()] return lazyTestCaseGroups[testCaseGroupId.cast()]
@@ -101,7 +90,7 @@ internal class StandardTestCaseGroupProvider(private val settings: Settings) : T
fun finishTestFile(forceFinish: Boolean, location: Location) { fun finishTestFile(forceFinish: Boolean, location: Location) {
val needToFinish = forceFinish val needToFinish = forceFinish
|| currentTestFileName != null || currentTestFileName != null
|| (currentTestFileName == null /*&& testFiles.isEmpty()*/ && currentTestFileText.hasAnythingButComments()) || (/*currentTestFileName == null && testFiles.isEmpty() &&*/ currentTestFileText.hasAnythingButComments())
if (needToFinish) { if (needToFinish) {
val fileName = currentTestFileName ?: DEFAULT_FILE_NAME val fileName = currentTestFileName ?: DEFAULT_FILE_NAME
@@ -119,8 +108,7 @@ internal class StandardTestCaseGroupProvider(private val settings: Settings) : T
} }
} }
val text = testDataFile.applySourceTransformers(sourceTransformers[testDataFile.canonicalPath] ?: listOf()) testDataFile.readLines().forEachIndexed { lineNumber, line ->
text.lines().forEachIndexed { lineNumber, line ->
val location = Location(testDataFile, lineNumber) val location = Location(testDataFile, lineNumber)
val expectFileDirectiveAfterModuleDirective = val expectFileDirectiveAfterModuleDirective =
lastParsedDirective == TestDirectives.MODULE // Only FILE directive may follow MODULE directive. lastParsedDirective == TestDirectives.MODULE // Only FILE directive may follow MODULE directive.
@@ -7,15 +7,7 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.group
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseGroup import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseGroup
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseGroupId import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseGroupId
import java.io.File
internal interface TestCaseGroupProvider { internal interface TestCaseGroupProvider {
fun setPreprocessors(testDataDir: File, preprocessors: List<(String) -> String>)
fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup? fun getTestCaseGroup(testCaseGroupId: TestCaseGroupId): TestCaseGroup?
} }
internal fun String.applySourceTransformers(sourceTransformers: List<(String) -> String>) =
sourceTransformers.fold(this) { source, transformer -> transformer(source) }
internal fun File.applySourceTransformers(sourceTransformers: List<(String) -> String>) =
readText().applySourceTransformers(sourceTransformers)
@@ -0,0 +1,30 @@
/*
* 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.util
import org.jetbrains.kotlin.konan.blackboxtest.AbstractExternalNativeBlackBoxTest
import java.io.File
/**
* This relates only to external codegen tests (see [AbstractExternalNativeBlackBoxTest]) that may have their own source transformers.
*/
internal typealias ExternalSourceTransformer = (/* file contents */ String) -> /* patched file contents */ String
internal typealias ExternalSourceTransformers = List<ExternalSourceTransformer>
internal interface ExternalSourceTransformersProvider {
fun getSourceTransformers(testDataFile: File): ExternalSourceTransformers?
}
internal object DiagnosticsRemovingSourceTransformer : ExternalSourceTransformer {
override fun invoke(source: String) = source.lineSequence().joinToString("\n") { line ->
// Remove all diagnostic parameters from the text. Examples:
// <!NO_TAIL_CALLS_FOUND!>, <!NON_TAIL_RECURSIVE_CALL!>, <!>.
line.replace(DIAGNOSTIC_REGEX) { match -> match.groupValues[1] }
}
private val DIAGNOSTIC_REGEX = Regex("<!.*?!>(.*?)<!>")
}