[Test] Compute target backend in test generator automatically using reflection
This commit is contained in:
committed by
TeamCityServer
parent
9378d1ff31
commit
3c2079c926
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.test.runners
|
||||
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
|
||||
/**
|
||||
* If your test runner has specific target backend then you can add this interface
|
||||
* to your runner and after that you should not declare targetBackend
|
||||
* parameter in DSL in addition to defining it in test runner
|
||||
*
|
||||
* Please make sure that all abstract runners which are used in test generator
|
||||
* have `open` modality, not `abstract`. This is required because test generator
|
||||
* instantiates runner to get value of targetBackend and generate tests properly
|
||||
*/
|
||||
interface RunnerWithTargetBackendForTestGeneratorMarker {
|
||||
val targetBackend: TargetBackend
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ fun generateTestGroupSuiteWithJUnit5(
|
||||
dryRun: Boolean = false,
|
||||
init: TestGroupSuite.() -> Unit
|
||||
) {
|
||||
val suite = testGroupSuite(init)
|
||||
val suite = TestGroupSuite(ReflectionBasedTargetBackendComputer).apply(init)
|
||||
for (testGroup in suite.testGroups) {
|
||||
for (testClass in testGroup.testClasses) {
|
||||
val (changed, testSourceFilePath) = NewTestGeneratorImpl.generateAndSave(testClass, dryRun)
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.test.generators
|
||||
|
||||
import org.jetbrains.kotlin.generators.model.DefaultTargetBackendComputer
|
||||
import org.jetbrains.kotlin.generators.model.TargetBackendComputer
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import org.jetbrains.kotlin.test.runners.RunnerWithTargetBackendForTestGeneratorMarker
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.createInstance
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
|
||||
object ReflectionBasedTargetBackendComputer : TargetBackendComputer {
|
||||
private val runnerMarkerKClass = RunnerWithTargetBackendForTestGeneratorMarker::class
|
||||
private const val TARGET_BACKEND_PROPERTY_NAME = "targetBackend"
|
||||
|
||||
override fun compute(definedTargetBackend: TargetBackend?, testKClass: KClass<*>): TargetBackend {
|
||||
if (!testKClass.isSubclassOf(runnerMarkerKClass)) return DefaultTargetBackendComputer.compute(definedTargetBackend, testKClass)
|
||||
require(definedTargetBackend == null) {
|
||||
"""
|
||||
Test ${testKClass.simpleName} is inheritor of ${runnerMarkerKClass.simpleName} which means that
|
||||
target you should not specify targetBackend in test generation DSL, because it will be
|
||||
read from test runner class itself
|
||||
""".trimIndent()
|
||||
}
|
||||
require(testKClass.isOpen) {
|
||||
"""
|
||||
Test runner which inherits from ${runnerMarkerKClass.simpleName} and used as base class
|
||||
for real test should have `open` modality
|
||||
""".trimIndent()
|
||||
}
|
||||
val instance = testKClass.createInstance() as RunnerWithTargetBackendForTestGeneratorMarker
|
||||
val kProperty = runnerMarkerKClass.declaredMemberProperties.single { it.name == TARGET_BACKEND_PROPERTY_NAME }
|
||||
return kProperty.get(instance) as TargetBackend
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ dependencies {
|
||||
testImplementation(platform("org.junit:junit-bom:5.7.0"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
testImplementation(projectTests(":compiler:tests-common"))
|
||||
testImplementation(projectTests(":compiler:test-infrastructure"))
|
||||
testImplementation(projectTests(":compiler:tests-common-new"))
|
||||
testImplementation(projectTests(":compiler:tests-common"))
|
||||
testImplementation(projectTests(":compiler"))
|
||||
testImplementation(projectTests(":compiler:fir:raw-fir:psi2fir"))
|
||||
testImplementation(projectTests(":compiler:fir:raw-fir:light-tree2fir"))
|
||||
|
||||
+17
-8
@@ -11,14 +11,15 @@ import org.jetbrains.kotlin.test.TargetBackend
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
fun testGroupSuite(
|
||||
init: TestGroupSuite.() -> Unit
|
||||
): TestGroupSuite {
|
||||
return TestGroupSuite().apply(init)
|
||||
return TestGroupSuite(DefaultTargetBackendComputer).apply(init)
|
||||
}
|
||||
|
||||
class TestGroupSuite {
|
||||
class TestGroupSuite(val targetBackendComputer: TargetBackendComputer) {
|
||||
private val _testGroups = mutableListOf<TestGroup>()
|
||||
val testGroups: List<TestGroup>
|
||||
get() = _testGroups
|
||||
@@ -35,6 +36,7 @@ class TestGroupSuite {
|
||||
testDataRoot,
|
||||
testRunnerMethodName,
|
||||
additionalRunnerArguments,
|
||||
targetBackendComputer = targetBackendComputer
|
||||
).apply(init)
|
||||
}
|
||||
}
|
||||
@@ -45,6 +47,7 @@ class TestGroup(
|
||||
val testRunnerMethodName: String,
|
||||
val additionalRunnerArguments: List<String> = emptyList(),
|
||||
val annotations: List<AnnotationModel> = emptyList(),
|
||||
val targetBackendComputer: TargetBackendComputer
|
||||
) {
|
||||
private val _testClasses: MutableList<TestClass> = mutableListOf()
|
||||
val testClasses: List<TestClass>
|
||||
@@ -56,24 +59,28 @@ class TestGroup(
|
||||
annotations: List<AnnotationModel> = emptyList(),
|
||||
noinline init: TestClass.() -> Unit
|
||||
) {
|
||||
testClass(T::class.java.name, suiteTestClassName, useJunit4, annotations, init)
|
||||
val testKClass = T::class
|
||||
testClass(testKClass, testKClass.java.name, suiteTestClassName, useJunit4, annotations, init)
|
||||
}
|
||||
|
||||
fun testClass(
|
||||
testKClass: KClass<*>,
|
||||
baseTestClassName: String,
|
||||
suiteTestClassName: String = getDefaultSuiteTestClassName(baseTestClassName.substringAfterLast('.')),
|
||||
useJunit4: Boolean,
|
||||
annotations: List<AnnotationModel> = emptyList(),
|
||||
init: TestClass.() -> Unit
|
||||
) {
|
||||
_testClasses += TestClass(baseTestClassName, suiteTestClassName, useJunit4, annotations).apply(init)
|
||||
_testClasses += TestClass(testKClass, baseTestClassName, suiteTestClassName, useJunit4, annotations, targetBackendComputer).apply(init)
|
||||
}
|
||||
|
||||
inner class TestClass(
|
||||
val testKClass: KClass<*>,
|
||||
val baseTestClassName: String,
|
||||
val suiteTestClassName: String,
|
||||
val useJunit4: Boolean,
|
||||
val annotations: List<AnnotationModel>
|
||||
val annotations: List<AnnotationModel>,
|
||||
val targetBackendComputer: TargetBackendComputer
|
||||
) {
|
||||
val baseDir: String
|
||||
get() = this@TestGroup.testsRoot
|
||||
@@ -92,7 +99,7 @@ class TestGroup(
|
||||
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
|
||||
targetBackend: TargetBackend = TargetBackend.ANY,
|
||||
targetBackend: TargetBackend? = null,
|
||||
excludeDirs: List<String> = listOf(),
|
||||
filenameStartsLowerCase: Boolean? = null, // assert that file is properly named
|
||||
skipIgnored: Boolean = false, // pretty meaningless flag, affects only few test names in one test runner
|
||||
@@ -102,18 +109,20 @@ class TestGroup(
|
||||
val compiledPattern = Pattern.compile(pattern)
|
||||
val compiledExcludedPattern = excludedPattern?.let { Pattern.compile(it) }
|
||||
val className = testClassName ?: TestGeneratorUtil.fileNameToJavaIdentifier(rootFile)
|
||||
val realTargetBackend = targetBackendComputer.compute(targetBackend, testKClass)
|
||||
testModels.add(
|
||||
if (singleClass) {
|
||||
if (excludeDirs.isNotEmpty()) error("excludeDirs is unsupported for SingleClassTestModel yet")
|
||||
|
||||
SingleClassTestModel(
|
||||
rootFile, compiledPattern, compiledExcludedPattern, filenameStartsLowerCase, testMethod, className,
|
||||
targetBackend, skipIgnored, testRunnerMethodName, additionalRunnerArguments, annotations
|
||||
realTargetBackend, skipIgnored, testRunnerMethodName, additionalRunnerArguments, annotations
|
||||
)
|
||||
} else {
|
||||
SimpleTestClassModel(
|
||||
rootFile, recursive, excludeParentDirs,
|
||||
compiledPattern, compiledExcludedPattern, filenameStartsLowerCase, testMethod, className,
|
||||
targetBackend, excludeDirs, skipIgnored, testRunnerMethodName, additionalRunnerArguments, deep, annotations
|
||||
realTargetBackend, excludeDirs, skipIgnored, testRunnerMethodName, additionalRunnerArguments, deep, annotations
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.model
|
||||
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
fun interface TargetBackendComputer {
|
||||
fun compute(definedTargetBackend: TargetBackend?, testKClass: KClass<*>): TargetBackend
|
||||
}
|
||||
|
||||
object DefaultTargetBackendComputer : TargetBackendComputer {
|
||||
override fun compute(definedTargetBackend: TargetBackend?, testKClass: KClass<*>): TargetBackend {
|
||||
return definedTargetBackend ?: TargetBackend.ANY
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ plugins {
|
||||
val depenencyProjects = arrayOf(
|
||||
":generators",
|
||||
":compiler",
|
||||
":compiler:test-infrastructure",
|
||||
":compiler:tests-common-new",
|
||||
":compiler:tests-for-compiler-generator",
|
||||
":js:js.tests",
|
||||
|
||||
Reference in New Issue
Block a user