[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,
|
dryRun: Boolean = false,
|
||||||
init: TestGroupSuite.() -> Unit
|
init: TestGroupSuite.() -> Unit
|
||||||
) {
|
) {
|
||||||
val suite = testGroupSuite(init)
|
val suite = TestGroupSuite(ReflectionBasedTargetBackendComputer).apply(init)
|
||||||
for (testGroup in suite.testGroups) {
|
for (testGroup in suite.testGroups) {
|
||||||
for (testClass in testGroup.testClasses) {
|
for (testClass in testGroup.testClasses) {
|
||||||
val (changed, testSourceFilePath) = NewTestGeneratorImpl.generateAndSave(testClass, dryRun)
|
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(platform("org.junit:junit-bom:5.7.0"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
testImplementation(projectTests(":compiler:tests-common"))
|
testImplementation(projectTests(":compiler:tests-common"))
|
||||||
|
testImplementation(projectTests(":compiler:test-infrastructure"))
|
||||||
testImplementation(projectTests(":compiler:tests-common-new"))
|
testImplementation(projectTests(":compiler:tests-common-new"))
|
||||||
testImplementation(projectTests(":compiler:tests-common"))
|
|
||||||
testImplementation(projectTests(":compiler"))
|
testImplementation(projectTests(":compiler"))
|
||||||
testImplementation(projectTests(":compiler:fir:raw-fir:psi2fir"))
|
testImplementation(projectTests(":compiler:fir:raw-fir:psi2fir"))
|
||||||
testImplementation(projectTests(":compiler:fir:raw-fir:light-tree2fir"))
|
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.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
fun testGroupSuite(
|
fun testGroupSuite(
|
||||||
init: TestGroupSuite.() -> Unit
|
init: TestGroupSuite.() -> Unit
|
||||||
): TestGroupSuite {
|
): TestGroupSuite {
|
||||||
return TestGroupSuite().apply(init)
|
return TestGroupSuite(DefaultTargetBackendComputer).apply(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestGroupSuite {
|
class TestGroupSuite(val targetBackendComputer: TargetBackendComputer) {
|
||||||
private val _testGroups = mutableListOf<TestGroup>()
|
private val _testGroups = mutableListOf<TestGroup>()
|
||||||
val testGroups: List<TestGroup>
|
val testGroups: List<TestGroup>
|
||||||
get() = _testGroups
|
get() = _testGroups
|
||||||
@@ -35,6 +36,7 @@ class TestGroupSuite {
|
|||||||
testDataRoot,
|
testDataRoot,
|
||||||
testRunnerMethodName,
|
testRunnerMethodName,
|
||||||
additionalRunnerArguments,
|
additionalRunnerArguments,
|
||||||
|
targetBackendComputer = targetBackendComputer
|
||||||
).apply(init)
|
).apply(init)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,6 +47,7 @@ class TestGroup(
|
|||||||
val testRunnerMethodName: String,
|
val testRunnerMethodName: String,
|
||||||
val additionalRunnerArguments: List<String> = emptyList(),
|
val additionalRunnerArguments: List<String> = emptyList(),
|
||||||
val annotations: List<AnnotationModel> = emptyList(),
|
val annotations: List<AnnotationModel> = emptyList(),
|
||||||
|
val targetBackendComputer: TargetBackendComputer
|
||||||
) {
|
) {
|
||||||
private val _testClasses: MutableList<TestClass> = mutableListOf()
|
private val _testClasses: MutableList<TestClass> = mutableListOf()
|
||||||
val testClasses: List<TestClass>
|
val testClasses: List<TestClass>
|
||||||
@@ -56,24 +59,28 @@ class TestGroup(
|
|||||||
annotations: List<AnnotationModel> = emptyList(),
|
annotations: List<AnnotationModel> = emptyList(),
|
||||||
noinline init: TestClass.() -> Unit
|
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(
|
fun testClass(
|
||||||
|
testKClass: KClass<*>,
|
||||||
baseTestClassName: String,
|
baseTestClassName: String,
|
||||||
suiteTestClassName: String = getDefaultSuiteTestClassName(baseTestClassName.substringAfterLast('.')),
|
suiteTestClassName: String = getDefaultSuiteTestClassName(baseTestClassName.substringAfterLast('.')),
|
||||||
useJunit4: Boolean,
|
useJunit4: Boolean,
|
||||||
annotations: List<AnnotationModel> = emptyList(),
|
annotations: List<AnnotationModel> = emptyList(),
|
||||||
init: TestClass.() -> Unit
|
init: TestClass.() -> Unit
|
||||||
) {
|
) {
|
||||||
_testClasses += TestClass(baseTestClassName, suiteTestClassName, useJunit4, annotations).apply(init)
|
_testClasses += TestClass(testKClass, baseTestClassName, suiteTestClassName, useJunit4, annotations, targetBackendComputer).apply(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class TestClass(
|
inner class TestClass(
|
||||||
|
val testKClass: KClass<*>,
|
||||||
val baseTestClassName: String,
|
val baseTestClassName: String,
|
||||||
val suiteTestClassName: String,
|
val suiteTestClassName: String,
|
||||||
val useJunit4: Boolean,
|
val useJunit4: Boolean,
|
||||||
val annotations: List<AnnotationModel>
|
val annotations: List<AnnotationModel>,
|
||||||
|
val targetBackendComputer: TargetBackendComputer
|
||||||
) {
|
) {
|
||||||
val baseDir: String
|
val baseDir: String
|
||||||
get() = this@TestGroup.testsRoot
|
get() = this@TestGroup.testsRoot
|
||||||
@@ -92,7 +99,7 @@ class TestGroup(
|
|||||||
testClassName: String? = null, // specific name for generated test class
|
testClassName: String? = null, // specific name for generated test class
|
||||||
// which backend will be used in test. Specifying value may affect some test with
|
// 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
|
// directives TARGET_BACKEND/DONT_TARGET_EXACT_BACKEND won't be generated
|
||||||
targetBackend: TargetBackend = TargetBackend.ANY,
|
targetBackend: TargetBackend? = null,
|
||||||
excludeDirs: List<String> = listOf(),
|
excludeDirs: List<String> = listOf(),
|
||||||
filenameStartsLowerCase: Boolean? = null, // assert that file is properly named
|
filenameStartsLowerCase: Boolean? = null, // assert that file is properly named
|
||||||
skipIgnored: Boolean = false, // pretty meaningless flag, affects only few test names in one test runner
|
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 compiledPattern = Pattern.compile(pattern)
|
||||||
val compiledExcludedPattern = excludedPattern?.let { Pattern.compile(it) }
|
val compiledExcludedPattern = excludedPattern?.let { Pattern.compile(it) }
|
||||||
val className = testClassName ?: TestGeneratorUtil.fileNameToJavaIdentifier(rootFile)
|
val className = testClassName ?: TestGeneratorUtil.fileNameToJavaIdentifier(rootFile)
|
||||||
|
val realTargetBackend = targetBackendComputer.compute(targetBackend, testKClass)
|
||||||
testModels.add(
|
testModels.add(
|
||||||
if (singleClass) {
|
if (singleClass) {
|
||||||
if (excludeDirs.isNotEmpty()) error("excludeDirs is unsupported for SingleClassTestModel yet")
|
if (excludeDirs.isNotEmpty()) error("excludeDirs is unsupported for SingleClassTestModel yet")
|
||||||
|
|
||||||
SingleClassTestModel(
|
SingleClassTestModel(
|
||||||
rootFile, compiledPattern, compiledExcludedPattern, filenameStartsLowerCase, testMethod, className,
|
rootFile, compiledPattern, compiledExcludedPattern, filenameStartsLowerCase, testMethod, className,
|
||||||
targetBackend, skipIgnored, testRunnerMethodName, additionalRunnerArguments, annotations
|
realTargetBackend, skipIgnored, testRunnerMethodName, additionalRunnerArguments, annotations
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
SimpleTestClassModel(
|
SimpleTestClassModel(
|
||||||
rootFile, recursive, excludeParentDirs,
|
rootFile, recursive, excludeParentDirs,
|
||||||
compiledPattern, compiledExcludedPattern, filenameStartsLowerCase, testMethod, className,
|
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(
|
val depenencyProjects = arrayOf(
|
||||||
":generators",
|
":generators",
|
||||||
":compiler",
|
":compiler",
|
||||||
|
":compiler:test-infrastructure",
|
||||||
":compiler:tests-common-new",
|
":compiler:tests-common-new",
|
||||||
":compiler:tests-for-compiler-generator",
|
":compiler:tests-for-compiler-generator",
|
||||||
":js:js.tests",
|
":js:js.tests",
|
||||||
|
|||||||
Reference in New Issue
Block a user