From c2e20686826930bec0a2bbfae46a4071e74ce9cd Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 14 Jul 2021 16:32:40 +0300 Subject: [PATCH] [Test] Add ability to mark group of tests with specific tags Currently tags can be applied to all tests in specific testdata directory by placing `_tags.txt` file in it, where all tags should be listed on separate lines. Test generator adds those tags to corresponding generated test classes with `@Tag` annotation Please note that is applicable only to JUnit 5 tests --- .../test/generators/NewTestGeneratorImpl.kt | 24 +++++++++++++++++ .../generators/impl/TestGeneratorImpl.kt | 3 +++ .../kotlin/generators/TestGenerationDSL.kt | 7 +++-- .../model/DelegatingTestClassModel.kt | 3 +++ .../generators/model/RunTestMethodModel.kt | 3 +++ .../generators/model/SimpleTestClassModel.kt | 17 ++++++++++-- .../generators/model/SimpleTestMethodModel.kt | 3 ++- .../generators/model/SingleClassTestModel.kt | 8 ++++-- .../kotlin/generators/model/TestModel.kt | 1 + .../kotlin/generators/util/TagsExtractor.kt | 27 +++++++++++++++++++ 10 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 generators/test-generator/tests/org/jetbrains/kotlin/generators/util/TagsExtractor.kt diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/generators/NewTestGeneratorImpl.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/generators/NewTestGeneratorImpl.kt index d1d5fbc49a7..cfb378f077d 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/generators/NewTestGeneratorImpl.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/generators/NewTestGeneratorImpl.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.test.TestMetadata import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.utils.Printer import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import java.io.File import java.io.IOException @@ -64,6 +65,12 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { } } + private fun Printer.generateTags(testEntityModel: TestEntityModel) { + for (tag in testEntityModel.tags) { + println("@Tag(\"$tag\")") + } + } + private fun Printer.generateSuppressAllWarnings() { println("@SuppressWarnings(\"all\")") } @@ -134,6 +141,9 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { p.println("import ${TestMetadata::class.java.canonicalName};") p.println("import ${Nested::class.java.canonicalName};") p.println("import ${Test::class.java.canonicalName};") + if (testClassModels.any { it.containsTags() }) { + p.println("import ${Tag::class.java.canonicalName};") + } p.println() p.println("import java.io.File;") p.println("import java.util.regex.Pattern;") @@ -173,6 +183,9 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { override val imports: Set> get() = super.imports + + override val tags: List + get() = emptyList() } } @@ -182,6 +195,7 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { private fun generateTestClass(p: Printer, testClassModel: TestClassModel, isNested: Boolean) { p.generateNestedAnnotation(isNested) + p.generateTags(testClassModel) p.generateMetadata(testClassModel) p.generateTestDataPath(testClassModel) p.generateParameterAnnotations(testClassModel) @@ -229,6 +243,7 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { val generator = methodGenerators.getValue(methodModel.kind) p.generateTestAnnotation() + p.generateTags(methodModel) p.generateMetadata(methodModel) generator.hackyGenerateSignature(methodModel, p) p.printWithNoIndent(" {") @@ -252,4 +267,13 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) { generateSignature(method as T, p) } } + + private fun TestEntityModel.containsTags(): Boolean { + if (this.tags.isNotEmpty()) return true + if (this is TestClassModel) { + if (innerTestClasses.any { it.containsTags() }) return true + if (methods.any { it.containsTags() }) return true + } + return false + } } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/generators/impl/TestGeneratorImpl.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/generators/impl/TestGeneratorImpl.kt index a3cde41411a..27939dd969f 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/generators/impl/TestGeneratorImpl.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/generators/impl/TestGeneratorImpl.kt @@ -176,6 +176,9 @@ private class TestGeneratorImplInstance( override val imports: Set> get() = super.imports + + override val tags: List + get() = emptyList() } } 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 7c8cbb4ebc1..52c9815e273 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/TestGenerationDSL.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/TestGenerationDSL.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.generators import org.jetbrains.kotlin.generators.model.* 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.* @@ -116,13 +117,15 @@ class TestGroup( SingleClassTestModel( rootFile, compiledPattern, compiledExcludedPattern, filenameStartsLowerCase, testMethod, className, - realTargetBackend, skipIgnored, testRunnerMethodName, additionalRunnerArguments, annotations + realTargetBackend, skipIgnored, testRunnerMethodName, additionalRunnerArguments, annotations, + extractTagsFromDirectory(rootFile) ) } else { SimpleTestClassModel( rootFile, recursive, excludeParentDirs, compiledPattern, compiledExcludedPattern, filenameStartsLowerCase, testMethod, className, - realTargetBackend, excludeDirs, skipIgnored, testRunnerMethodName, additionalRunnerArguments, deep, annotations + realTargetBackend, excludeDirs, skipIgnored, testRunnerMethodName, additionalRunnerArguments, deep, annotations, + extractTagsFromDirectory(rootFile) ) } ) diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/DelegatingTestClassModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/DelegatingTestClassModel.kt index f3a7f9318da..cc2166a3e17 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/DelegatingTestClassModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/DelegatingTestClassModel.kt @@ -25,4 +25,7 @@ open class DelegatingTestClassModel(private val delegate: TestClassModel) : Test override val annotations: Collection get() = delegate.annotations + + override val tags: List + get() = delegate.tags } diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/RunTestMethodModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/RunTestMethodModel.kt index 6329901aa2a..49da9295b40 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/RunTestMethodModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/RunTestMethodModel.kt @@ -21,6 +21,9 @@ class RunTestMethodModel( override val name = METHOD_NAME override val dataString: String? = null + override val tags: List + get() = emptyList() + override fun imports(): Collection> { return super.imports() + if (isWithTargetBackend()) setOf(TargetBackend::class.java) else emptySet() } diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestClassModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestClassModel.kt index 13b174567aa..2699a1d5337 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestClassModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestClassModel.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.generators.model import com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.generators.util.TestGeneratorUtil.fileNameToJavaIdentifier +import org.jetbrains.kotlin.generators.util.extractTagsFromDirectory +import org.jetbrains.kotlin.generators.util.extractTagsFromTestFile import org.jetbrains.kotlin.test.TargetBackend import org.jetbrains.kotlin.test.util.KtTestUtil import java.io.File @@ -28,6 +30,7 @@ class SimpleTestClassModel( private val additionalRunnerArguments: List, private val deep: Int?, override val annotations: Collection, + override val tags: List ) : TestClassModel() { override val name: String get() = testClassName @@ -60,6 +63,7 @@ class SimpleTestClassModel( additionalRunnerArguments, if (deep != null) deep - 1 else null, annotations, + extractTagsFromDirectory(file) ) ) } @@ -85,7 +89,13 @@ class SimpleTestClassModel( if (!rootFile.isDirectory) { return@lazy listOf( SimpleTestMethodModel( - rootFile, rootFile, filenamePattern, checkFilenameStartsLowerCase, targetBackend, skipIgnored + rootFile, + rootFile, + filenamePattern, + checkFilenameStartsLowerCase, + targetBackend, + skipIgnored, + extractTagsFromTestFile(rootFile) ) ) } @@ -103,7 +113,7 @@ class SimpleTestClassModel( result.add( SimpleTestMethodModel( rootFile, file, filenamePattern, - checkFilenameStartsLowerCase, targetBackend, skipIgnored + checkFilenameStartsLowerCase, targetBackend, skipIgnored, extractTagsFromTestFile(file) ) ) } @@ -143,6 +153,9 @@ class SimpleTestClassModel( override fun shouldBeGenerated(): Boolean { return true } + + override val tags: List + get() = emptyList() } companion object { diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt index 3cf01bc96ad..66e317cf41e 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt @@ -18,7 +18,8 @@ open class SimpleTestMethodModel( private val filenamePattern: Pattern, checkFilenameStartsLowerCase: Boolean?, protected val targetBackend: TargetBackend, - private val skipIgnored: Boolean + private val skipIgnored: Boolean, + override val tags: List ) : MethodModel { object Kind : MethodModel.Kind() diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SingleClassTestModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SingleClassTestModel.kt index 541c87771b6..3b3d2b95542 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SingleClassTestModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SingleClassTestModel.kt @@ -22,7 +22,8 @@ class SingleClassTestModel( private val skipIgnored: Boolean, private val testRunnerMethodName: String, private val additionalRunnerArguments: List, - override val annotations: List + override val annotations: List, + override val tags: List ) : TestClassModel() { override val name: String get() = testClassName @@ -46,7 +47,7 @@ class SingleClassTestModel( private fun getTestMethodsFromFile(file: File): Collection { return listOf( SimpleTestMethodModel( - rootFile, file, filenamePattern, checkFilenameStartsLowerCase, targetBackend, skipIgnored + rootFile, file, filenamePattern, checkFilenameStartsLowerCase, targetBackend, skipIgnored, tags = emptyList() ) ) } @@ -73,5 +74,8 @@ class SingleClassTestModel( override fun shouldBeGenerated(): Boolean { return true } + + override val tags: List + get() = emptyList() } } diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TestModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TestModel.kt index ad20ff708bc..4c11d6cc50f 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TestModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/TestModel.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.generators.model interface TestEntityModel { val name: String val dataString: String? + val tags: List } interface ClassModel : TestEntityModel { diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/util/TagsExtractor.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/util/TagsExtractor.kt new file mode 100644 index 00000000000..879df9a5d05 --- /dev/null +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/util/TagsExtractor.kt @@ -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.generators.util + +import java.io.File + +private const val TAGS_FILE_NAME = "_tags.txt" +private val PROHIBITED_SYMBOLS = listOf(' ', ',', '(', ')', '&', '|', '!') + +fun extractTagsFromDirectory(dir: File): List { + require(dir.isDirectory) + val tagsFile = dir.resolve(TAGS_FILE_NAME) + if (!tagsFile.exists()) return emptyList() + return tagsFile.readLines().filter { it.isNotBlank() }.onEach(::validateTag) +} + +// TODO: support tags in testdata files +fun extractTagsFromTestFile(@Suppress("UNUSED_PARAMETER") file: File): List = emptyList() + +private fun validateTag(tag: String) { + require(PROHIBITED_SYMBOLS.none { it in tag }) { + "Tag \"tag\" contains one of prohibited symbols: $PROHIBITED_SYMBOLS" + } +}