[Tests] Native tests runTest applies source transformers

This commit is contained in:
Evgeniy.Zhelenskiy
2021-12-03 18:38:16 +03:00
parent 9b196c738f
commit c27b647ce8
12 changed files with 104 additions and 16 deletions
@@ -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<Pair<String, String>> =
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()
}
@@ -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
@@ -24,7 +24,13 @@ object TransformingTestMethodGenerator : MethodGenerator<TransformingTestMethodM
override fun generateBody(method: TransformingTestMethodModel, p: Printer) {
with(method) {
val filePath = KtTestUtil.getFilePath(source.file) + if (source.file.isDirectory) "/" else ""
p.println("${RunTestMethodModel.METHOD_NAME}(\"$filePath\", ${method.transformer});")
p.println("${RunTestMethodModel.METHOD_NAME}(\"$filePath\"${if (isNative) "" else ", $transformer"});")
if (isNative) {
p.println("/*")
p.println(" There is a registered source transformer for the testcase:")
transformer.lines().forEach { p.println(" $it") }
p.println("*/")
}
}
}
}
@@ -17,7 +17,7 @@ open class SimpleTestMethodModel(
val file: File,
private val filenamePattern: Pattern,
checkFilenameStartsLowerCase: Boolean?,
protected val targetBackend: TargetBackend,
internal val targetBackend: TargetBackend,
private val skipIgnored: Boolean,
override val tags: List<String>
) : MethodModel {
@@ -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.
}
@@ -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
@@ -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<Pair<File, List<(String) -> 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)
@@ -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)
@@ -24,6 +24,10 @@ internal class TestRunProvider(
private val compilationFactory = TestCompilationFactory(environment)
private val cachedCompilations = ThreadSafeCache<TestCompilationCacheKey, TestCompilation>()
fun setProcessors(testDataFile: File, sourceTransformers: List<(String) -> String>) {
testCaseGroupProvider.setPreprocessors(testDataFile, sourceTransformers)
}
fun getSingleTestRun(testDataFile: File): TestRun {
environment.assertNotDisposed()
@@ -38,6 +38,7 @@ import java.io.File
internal class ExtTestCaseGroupProvider(
private val environment: TestEnvironment
) : TestCaseGroupProvider, TestDisposable(parentDisposable = environment) {
private val sourceTransformers: MutableMap<String, List<(String) -> String>> = mutableMapOf()
private val structureFactory = ExtTestDataFileStructureFactory(parentDisposable = this)
private val sharedModules = ThreadSafeCache<String, TestModule.Shared?>()
@@ -55,7 +56,9 @@ internal class ExtTestCaseGroupProvider(
val testCases = mutableListOf<TestCase>()
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:
// <!NO_TAIL_CALLS_FOUND!>, <!NON_TAIL_RECURSIVE_CALL!>, <!>.
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
)
@@ -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, List<(String) -> String>> = mutableMapOf()
// Load test cases in groups on demand.
private val lazyTestCaseGroups = ThreadSafeFactory<File, TestCaseGroup?> { 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.
@@ -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)