diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/NewTestGeneratorImpl.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/NewTestGeneratorImpl.kt index 9fa57a21f08..560e60e2746 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/NewTestGeneratorImpl.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/NewTestGeneratorImpl.kt @@ -208,6 +208,17 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { var first = true + val transformers = testClassModel.predefinedTransformers(false) + + if (transformers.isNotEmpty()) { + p.println("public ${testClassModel.name}() {") + p.pushIndent() + transformers.forEach { (path, transformer) -> p.println("register(\"$path\", $transformer);") } + p.popIndent() + p.println("}") + first = false + } + for (methodModel in testMethods) { if (methodModel is RunTestMethodModel) continue // should also skip its imports if (!methodModel.shouldBeGenerated()) continue // should also skip its imports @@ -274,4 +285,9 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { } return false } + + private fun TestClassModel.predefinedTransformers(recursive: Boolean): List> = + methods.mapNotNull { method -> + (method as? TransformingTestMethodModel)?.takeIf { it.isNative }?.let { it.source.file.path to it.transformer } + } + if (recursive) innerTestClasses.flatMap { it.predefinedTransformers(recursive) } else listOf() } diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/TestGenerationDSL.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/TestGenerationDSL.kt index cc7c8d44585..e5cef3a31a4 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/TestGenerationDSL.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/TestGenerationDSL.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.generators.util.TestGeneratorUtil import org.jetbrains.kotlin.generators.util.extractTagsFromDirectory import org.jetbrains.kotlin.test.TargetBackend import java.io.File -import java.util.* import java.util.regex.Pattern import kotlin.reflect.KClass @@ -96,7 +95,7 @@ class TestGroup( pattern: String = if (extension == null) """^([^\.]+)$""" else "^(.+)\\.$extension\$", excludedPattern: String? = null, testMethod: String = "doTest", - singleClass: Boolean = false, // if true then tests from subdirectories will be flatten to single class + singleClass: Boolean = false, // if true then tests from subdirectories will be flattened to single class testClassName: String? = null, // specific name for generated test class // which backend will be used in test. Specifying value may affect some test with // directives TARGET_BACKEND/DONT_TARGET_EXACT_BACKEND won't be generated diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/impl/TransformingTestMethodGenerator.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/impl/TransformingTestMethodGenerator.kt index f732fa06cef..7be87b3d8c3 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/impl/TransformingTestMethodGenerator.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/impl/TransformingTestMethodGenerator.kt @@ -24,7 +24,13 @@ object TransformingTestMethodGenerator : MethodGenerator ) : MethodModel { diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TransformingTestMethodModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TransformingTestMethodModel.kt index 843fe4275c6..a6ca4ed13f5 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TransformingTestMethodModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TransformingTestMethodModel.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.generators.model +import org.jetbrains.kotlin.test.TargetBackend + abstract class TransformingTestMethodModel(val source: SimpleTestMethodModel, val transformer: String) : MethodModel { override val kind: MethodModel.Kind get() = Kind @@ -15,4 +17,9 @@ abstract class TransformingTestMethodModel(val source: SimpleTestMethodModel, va get() = source.tags object Kind : MethodModel.Kind() + + internal val isNative + get() = source.targetBackend in listOf(TargetBackend.NATIVE, TargetBackend.ANY) + // Native tests load sources before runTest call if more than 1 test is called, so we need to register it before. + // Existing native tests specify target backend as ANY, setting it to NATIVE removes some previously generated tests. } \ No newline at end of file diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java index 3f6e9d0e718..8a737be95e9 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java @@ -15644,6 +15644,10 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest { @TestDataPath("$PROJECT_ROOT") @NativeBlackBoxTestCaseGroupProvider(ExtTestCaseGroupProvider.class) public class InlineClasses { + public InlineClasses() { + register("compiler/testData/codegen/box/inlineClasses/boxResultInlineClassOfConstructorCall.kt", s -> s.replaceAll("OPTIONAL_JVM_INLINE_ANNOTATION", "")); + } + @Test public void testAllFilesPresentInInlineClasses() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); @@ -15700,7 +15704,11 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest { @Test @TestMetadata("boxResultInlineClassOfConstructorCall.kt") public void testBoxResultInlineClassOfConstructorCall_valueClasses() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/boxResultInlineClassOfConstructorCall.kt", s -> s.replaceAll("OPTIONAL_JVM_INLINE_ANNOTATION", "")); + runTest("compiler/testData/codegen/box/inlineClasses/boxResultInlineClassOfConstructorCall.kt"); + /* + There is a registered source transformer for the testcase: + s -> s.replaceAll("OPTIONAL_JVM_INLINE_ANNOTATION", "") + */ } @Test diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeBlackBoxTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeBlackBoxTest.kt index 9ee9aa08ddd..faeaf6d5d15 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeBlackBoxTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeBlackBoxTest.kt @@ -10,14 +10,25 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.NativeBlackBoxTestSupport import org.jetbrains.kotlin.konan.blackboxtest.support.TestRunProvider import org.jetbrains.kotlin.konan.blackboxtest.support.util.getAbsoluteFile import org.junit.jupiter.api.extension.ExtendWith +import java.io.File @ExtendWith(NativeBlackBoxTestSupport::class) abstract class AbstractNativeBlackBoxTest { internal lateinit var testRunProvider: TestRunProvider + private val toBeRegistered = mutableListOf String>>>() + internal fun onRunProviderSet() { + for ((file, transformer) in toBeRegistered) { + testRunProvider.setProcessors(file, transformer) + } + } - @Suppress("UNUSED_PARAMETER") - @JvmOverloads - fun runTest(@TestDataFile testDataFilePath: String, sourceTransformer: (String) -> String = { it }): Unit = with(testRunProvider) { + 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)) + + fun runTest(@TestDataFile testDataFilePath: String): Unit = with(testRunProvider) { val testDataFile = getAbsoluteFile(testDataFilePath) val testRun = getSingleTestRun(testDataFile) val testRunner = createRunner(testRun) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeBlackBoxTestSupport.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeBlackBoxTestSupport.kt index 8ffe241d734..4b69e2bfe12 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeBlackBoxTestSupport.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeBlackBoxTestSupport.kt @@ -30,6 +30,7 @@ class NativeBlackBoxTestSupport : BeforeEachCallback { */ override fun beforeEach(extensionContext: ExtensionContext): Unit = with(extensionContext) { enclosingTestInstance.testRunProvider = getOrCreateTestRunProvider() + enclosingTestInstance.onRunProviderSet() // Set the essential compiler property. System.setProperty("kotlin.native.home", getOrCreateGlobalEnvironment().kotlinNativeHome.path) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/TestRunProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/TestRunProvider.kt index 89238ea078e..d95407f75f7 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/TestRunProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/TestRunProvider.kt @@ -24,6 +24,10 @@ internal class TestRunProvider( private val compilationFactory = TestCompilationFactory(environment) private val cachedCompilations = ThreadSafeCache() + fun setProcessors(testDataFile: File, sourceTransformers: List<(String) -> String>) { + testCaseGroupProvider.setPreprocessors(testDataFile, sourceTransformers) + } + fun getSingleTestRun(testDataFile: File): TestRun { environment.assertNotDisposed() diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt index a3cdf2040dc..830df2d99a7 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt @@ -38,6 +38,7 @@ import java.io.File internal class ExtTestCaseGroupProvider( private val environment: TestEnvironment ) : TestCaseGroupProvider, TestDisposable(parentDisposable = environment) { + private val sourceTransformers: MutableMap String>> = mutableMapOf() private val structureFactory = ExtTestDataFileStructureFactory(parentDisposable = this) private val sharedModules = ThreadSafeCache() @@ -55,7 +56,9 @@ internal class ExtTestCaseGroupProvider( val testCases = mutableListOf() testDataFiles.forEach { testDataFile -> - val extTestDataFile = ExtTestDataFile(environment, structureFactory, testDataFile) + val extTestDataFile = ExtTestDataFile( + environment, structureFactory, testDataFile, sourceTransformers[testDataFile.canonicalPath] ?: listOf() + ) if (extTestDataFile.isRelevant) testCases += extTestDataFile.createTestCase( @@ -69,6 +72,13 @@ internal class ExtTestCaseGroupProvider( TestCaseGroup.Default(disabledTestDataFileNames, 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(testDataDir: File): TestCaseGroup? { assertNotDisposed() return lazyTestCaseGroups[testDataDir] @@ -117,10 +127,11 @@ internal class ExtTestCaseGroupProvider( private class ExtTestDataFile( private val environment: TestEnvironment, structureFactory: ExtTestDataFileStructureFactory, - private val testDataFile: File + private val testDataFile: File, + sourceTransformers: List<(String) -> String> ) { private val structure by lazy { - structureFactory.ExtTestDataFileStructure(testDataFile) { line -> + structureFactory.ExtTestDataFileStructure(testDataFile, sourceTransformers) { line -> // Remove all diagnostic parameters from the text. Examples: // , , . line.replace(DIAGNOSTIC_REGEX) { match -> match.groupValues[1] } @@ -642,12 +653,16 @@ private typealias SharedModuleCache = (moduleName: String, generator: SharedModu private class ExtTestDataFileStructureFactory(parentDisposable: Disposable) : TestDisposable(parentDisposable) { private val psiFactory = createPsiFactory(parentDisposable = this) - inner class ExtTestDataFileStructure(originalTestDataFile: File, initialCleanUpTransformation: (String) -> String) { + inner class ExtTestDataFileStructure( + originalTestDataFile: File, + sourceTransformers: List<(String) -> String>, + initialCleanUpTransformation: (String) -> String + ) { init { assertNotDisposed() } - private val filesAndModules = FilesAndModules(originalTestDataFile, initialCleanUpTransformation) + private val filesAndModules = FilesAndModules(originalTestDataFile, initialCleanUpTransformation, sourceTransformers) val directives: Directives get() = filesAndModules.directives @@ -803,12 +818,16 @@ private class ExtTestDataFileStructureFactory(parentDisposable: Disposable) : Te ExtTestModule(name, dependencies, friends) } - private inner class FilesAndModules(originalTestDataFile: File, initialCleanUpTransformation: (String) -> String) { + private inner class FilesAndModules( + originalTestDataFile: File, + initialCleanUpTransformation: (String) -> String, + sourceTransformers: List<(String) -> String> + ) { private val testFileFactory = ExtTestFileFactory() private val generatedFiles = TestFiles.createTestFiles( /* testFileName = */ DEFAULT_FILE_NAME, - /* expectedText = */ originalTestDataFile.readText(), + /* expectedText = */ originalTestDataFile.applySourceTransformers(sourceTransformers), /* factory = */ testFileFactory, /* preserveLocations = */ true ) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/StandardTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/StandardTestCaseGroupProvider.kt index c177b54b55e..ff90c160070 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/StandardTestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/StandardTestCaseGroupProvider.kt @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.test.services.impl.RegisteredDirectivesParser import java.io.File internal class StandardTestCaseGroupProvider(private val environment: TestEnvironment) : TestCaseGroupProvider { + val sourceTransformers: MutableMap String>> = mutableMapOf() + // Load test cases in groups on demand. private val lazyTestCaseGroups = ThreadSafeFactory { testDataDir -> val testDataFiles = testDataDir.listFiles() @@ -36,6 +38,13 @@ internal class StandardTestCaseGroupProvider(private val environment: TestEnviro TestCaseGroup.Default(disabledTestDataFileNames = 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(testDataDir: File) = lazyTestCaseGroups[testDataDir] private fun createTestCase(testDataFile: File): TestCase { @@ -100,7 +109,8 @@ internal class StandardTestCaseGroupProvider(private val environment: TestEnviro } } - testDataFile.readLines().forEachIndexed { lineNumber, line -> + val text = testDataFile.applySourceTransformers(sourceTransformers[testDataFile.canonicalPath] ?: listOf()) + text.lines().forEachIndexed { lineNumber, line -> val location = Location(testDataFile, lineNumber) val expectFileDirectiveAfterModuleDirective = lastParsedDirective == TestDirectives.MODULE // Only FILE directive may follow MODULE directive. diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/TestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/TestCaseGroupProvider.kt index 89a0829e387..add0f1713df 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/TestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/TestCaseGroupProvider.kt @@ -9,5 +9,12 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseGroup import java.io.File internal interface TestCaseGroupProvider { + fun setPreprocessors(testDataDir: File, preprocessors: List<(String) -> String>) fun getTestCaseGroup(testDataDir: File): 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)