[Test] Add single service for checking that codegen test is ingored

This approach is better than manual check for `IGNORE_BACKEND` directive
  because it also tracks `IGNORE_BACKEND_FIR` directive and reduces
  duplicating code
This commit is contained in:
Dmitriy Novozhilov
2021-08-05 12:10:09 +03:00
committed by teamcityserver
parent c8386ad1c7
commit 6f0bf766f2
4 changed files with 55 additions and 40 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.backend
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.WrappedException
import org.jetbrains.kotlin.test.bind
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND_FIR
@@ -14,11 +15,8 @@ import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.ValueDirective
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.defaultsProvider
import org.jetbrains.kotlin.test.services.moduleStructure
import org.jetbrains.kotlin.test.util.joinToArrayString
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
class BlackBoxCodegenSuppressor(
testServices: TestServices,
@@ -27,43 +25,22 @@ class BlackBoxCodegenSuppressor(
override val directiveContainers: List<DirectivesContainer>
get() = listOf(CodegenTestDirectives)
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::SuppressionChecker.bind(customIgnoreDirective)))
@OptIn(ExperimentalStdlibApi::class)
override fun suppressIfNeeded(failedAssertions: List<WrappedException>): List<WrappedException> {
if (failedAssertions.isEmpty()) return failedAssertions
val suppressionChecker = testServices.codegenSuppressionChecker
val moduleStructure = testServices.moduleStructure
val targetBackends = buildList {
testServices.defaultsProvider.defaultTargetBackend?.let {
add(it)
return@buildList
}
moduleStructure.modules.mapNotNullTo(this) { it.targetBackend }
}
val ignoreDirective = when (moduleStructure.modules.map { it.frontendKind }.first()) {
FrontendKinds.ClassicFrontend -> customIgnoreDirective ?: IGNORE_BACKEND
FrontendKinds.FIR -> IGNORE_BACKEND_FIR
else -> return failedAssertions
}
return processIgnoreBackend(moduleStructure, ignoreDirective, targetBackends, failedAssertions)
val ignoreDirective = suppressionChecker.extractIgnoreDirective(moduleStructure.modules.first()) ?: return failedAssertions
val suppressionResult = moduleStructure.modules.map { suppressionChecker.failuresInModuleAreIgnored(it, ignoreDirective) }
.firstOrNull { it.testMuted } ?: return failedAssertions
val additionalMessage = suppressionResult.matchedBackend?.let { "for $it" } ?: ""
return processAssertions(failedAssertions, ignoreDirective, additionalMessage)
}
private fun processIgnoreBackend(
moduleStructure: TestModuleStructure,
directive: ValueDirective<TargetBackend>,
targetBackends: List<TargetBackend>,
failedAssertions: List<WrappedException>
): List<WrappedException> {
val ignoredBackends = moduleStructure.allDirectives[directive]
if (ignoredBackends.isEmpty()) return failedAssertions
val matchedBackend = ignoredBackends.intersect(targetBackends)
if (ignoredBackends.contains(TargetBackend.ANY)) {
return processAssertions(failedAssertions, directive)
}
if (matchedBackend.isNotEmpty()) {
return processAssertions(failedAssertions, directive, "for ${matchedBackend.joinToArrayString()}")
}
return failedAssertions
}
private fun processAssertions(
failedAssertions: List<WrappedException>,
directive: ValueDirective<TargetBackend>,
@@ -81,4 +58,39 @@ class BlackBoxCodegenSuppressor(
listOf(AssertionError(message).wrap())
}
}
class SuppressionChecker(val testServices: TestServices, val customIgnoreDirective: ValueDirective<TargetBackend>?) : TestService {
fun extractIgnoreDirective(module: TestModule): ValueDirective<TargetBackend>? {
return when (module.frontendKind) {
FrontendKinds.ClassicFrontend -> customIgnoreDirective ?: IGNORE_BACKEND
FrontendKinds.FIR -> IGNORE_BACKEND_FIR
else -> null
}
}
fun failuresInModuleAreIgnored(module: TestModule): Boolean {
val ignoreDirective = extractIgnoreDirective(module) ?: return false
return failuresInModuleAreIgnored(module, ignoreDirective).testMuted
}
fun failuresInModuleAreIgnored(module: TestModule, ignoreDirective: ValueDirective<TargetBackend>): SuppressionResult {
val ignoredBackends = module.directives[ignoreDirective]
val targetBackend = testServices.defaultsProvider.defaultTargetBackend ?: module.targetBackend
return when {
ignoredBackends.isEmpty() -> SuppressionResult.NO_MUTE
targetBackend in ignoredBackends -> SuppressionResult(true, targetBackend)
TargetBackend.ANY in ignoredBackends -> SuppressionResult(true, null)
else -> SuppressionResult.NO_MUTE
}
}
data class SuppressionResult(val testMuted: Boolean, val matchedBackend: TargetBackend?) {
companion object {
val NO_MUTE = SuppressionResult(false, null)
}
}
}
}
val TestServices.codegenSuppressionChecker: BlackBoxCodegenSuppressor.SuppressionChecker by TestServices.testServiceAccessor()
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.backend.handlers
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.codegenSuppressionChecker
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.CHECK_BYTECODE_TEXT
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.TREAT_AS_ONE_FILE
@@ -31,7 +32,7 @@ class BytecodeTextHandler(testServices: TestServices, private val shouldEnableEx
if (shouldEnableExplicitly && CHECK_BYTECODE_TEXT !in module.directives) return
val targetBackend = module.targetBackend!!
val isIgnored = targetBackend in module.directives[CodegenTestDirectives.IGNORE_BACKEND]
val isIgnored = testServices.codegenSuppressionChecker.failuresInModuleAreIgnored(module)
val files = module.files.filter { it.isKtFile }
if (files.size > 1 && TREAT_AS_ONE_FILE !in module.directives) {
processMultiFileTest(files, info, targetBackend, !isIgnored)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.backend.handlers
import org.jetbrains.kotlin.codegen.D8Checker
import org.jetbrains.kotlin.codegen.getClassFiles
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
import org.jetbrains.kotlin.test.backend.codegenSuppressionChecker
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_DEXING
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.RUN_DEX_CHECKER
@@ -28,7 +29,7 @@ class DxCheckerHandler(testServices: TestServices) : JvmBinaryArtifactHandler(te
D8Checker.check(info.classFileFactory)
} catch (e: Throwable) {
if (!GeneratorsFileUtil.isTeamCityBuild &&
module.targetBackend !in module.directives[CodegenTestDirectives.IGNORE_BACKEND]
!testServices.codegenSuppressionChecker.failuresInModuleAreIgnored(module)
) {
try {
val javaDir = compiledClassesManager.getCompiledJavaDirForModule(module)
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil.getFileClassInfoNoResolve
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.backend.codegenSuppressionChecker
import org.jetbrains.kotlin.test.clientserver.TestProxy
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.ATTACH_DEBUGGER
@@ -53,7 +54,7 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe
override fun processModule(module: TestModule, info: BinaryArtifacts.Jvm) {
val ktFiles = info.classFileFactory.inputFiles.ifEmpty { return }
val reportProblems = module.targetBackend !in module.directives[CodegenTestDirectives.IGNORE_BACKEND]
val reportProblems = !testServices.codegenSuppressionChecker.failuresInModuleAreIgnored(module)
val classLoader = createAndVerifyClassLoader(module, info.classFileFactory, reportProblems)
try {
for (ktFile in ktFiles) {