[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
This commit is contained in:
Dmitriy Novozhilov
2021-07-14 16:32:40 +03:00
committed by teamcityserver
parent b9c549803d
commit c2e2068682
10 changed files with 89 additions and 7 deletions

View File

@@ -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<Class<*>>
get() = super.imports
override val tags: List<String>
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
}
}

View File

@@ -176,6 +176,9 @@ private class TestGeneratorImplInstance(
override val imports: Set<Class<*>>
get() = super.imports
override val tags: List<String>
get() = emptyList()
}
}

View File

@@ -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)
)
}
)

View File

@@ -25,4 +25,7 @@ open class DelegatingTestClassModel(private val delegate: TestClassModel) : Test
override val annotations: Collection<AnnotationModel>
get() = delegate.annotations
override val tags: List<String>
get() = delegate.tags
}

View File

@@ -21,6 +21,9 @@ class RunTestMethodModel(
override val name = METHOD_NAME
override val dataString: String? = null
override val tags: List<String>
get() = emptyList()
override fun imports(): Collection<Class<*>> {
return super.imports() + if (isWithTargetBackend()) setOf(TargetBackend::class.java) else emptySet()
}

View File

@@ -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<String>,
private val deep: Int?,
override val annotations: Collection<AnnotationModel>,
override val tags: List<String>
) : 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<String>
get() = emptyList()
}
companion object {

View File

@@ -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<String>
) : MethodModel {
object Kind : MethodModel.Kind()

View File

@@ -22,7 +22,8 @@ class SingleClassTestModel(
private val skipIgnored: Boolean,
private val testRunnerMethodName: String,
private val additionalRunnerArguments: List<String>,
override val annotations: List<AnnotationModel>
override val annotations: List<AnnotationModel>,
override val tags: List<String>
) : TestClassModel() {
override val name: String
get() = testClassName
@@ -46,7 +47,7 @@ class SingleClassTestModel(
private fun getTestMethodsFromFile(file: File): Collection<MethodModel> {
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<String>
get() = emptyList()
}
}

View File

@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.generators.model
interface TestEntityModel {
val name: String
val dataString: String?
val tags: List<String>
}
interface ClassModel : TestEntityModel {

View File

@@ -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<String> {
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<String> = emptyList()
private fun validateTag(tag: String) {
require(PROHIBITED_SYMBOLS.none { it in tag }) {
"Tag \"tag\" contains one of prohibited symbols: $PROHIBITED_SYMBOLS"
}
}