[Test] Migrate AbstractFirBlackBoxCodegenTest to new infrastructure

This commit is contained in:
Dmitriy Novozhilov
2020-12-30 12:15:52 +03:00
committed by TeamCityServer
parent af5a635f85
commit e3066a166e
11 changed files with 6976 additions and 2415 deletions
@@ -20,6 +20,7 @@ dependencies {
testApi(projectTests(":compiler:tests-common-new"))
testApi(project(":compiler:cli"))
testApi(project(":compiler:fir:checkers"))
testApi(project(":compiler:fir:fir-serialization"))
testApi(project(":compiler:fir:entrypoint"))
testApi(project(":compiler:frontend"))
@@ -30,6 +31,8 @@ dependencies {
testCompileOnly(project(":kotlin-reflect-api"))
testRuntimeOnly(project(":kotlin-reflect"))
testRuntimeOnly(project(":core:descriptors.runtime"))
testRuntimeOnly(androidDxJar())
testRuntimeOnly(project(":compiler:fir:fir2ir:jvm-backend"))
testImplementation(intellijCoreDep()) { includeJars("intellij-core") }
testImplementation(intellijDep()) {
@@ -7,8 +7,13 @@ package org.jetbrains.kotlin.test.backend
import org.jetbrains.kotlin.test.TargetBackend
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
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.moduleStructure
import org.jetbrains.kotlin.test.util.joinToArrayString
@@ -19,25 +24,42 @@ class BlackBoxCodegenSuppressor(testServices: TestServices) : AfterAnalysisCheck
override fun suppressIfNeeded(failedAssertions: List<AssertionError>): List<AssertionError> {
val moduleStructure = testServices.moduleStructure
val ignoredBackends = moduleStructure.modules.flatMap { it.directives[CodegenTestDirectives.IGNORE_BACKEND] }
if (ignoredBackends.isEmpty()) return failedAssertions
val targetBackends = moduleStructure.modules.map { it.targetBackend }
val matchedBackend = ignoredBackends.intersect(targetBackends)
if (ignoredBackends.contains(TargetBackend.ANY)) {
return processAssertions(failedAssertions)
val targetBackends = moduleStructure.modules.mapNotNull { it.targetBackend }
return when (moduleStructure.modules.map { it.frontendKind }.first()) {
FrontendKinds.ClassicFrontend -> processIgnoreBackend(moduleStructure, IGNORE_BACKEND, targetBackends, failedAssertions)
FrontendKinds.FIR -> processIgnoreBackend(moduleStructure, IGNORE_BACKEND_FIR, targetBackends, failedAssertions)
else -> failedAssertions
}
if (matchedBackend.isNotEmpty()) {
return processAssertions(failedAssertions, "for ${matchedBackend.joinToArrayString()}")
}
return failedAssertions
}
private fun processAssertions(failedAssertions: List<AssertionError>, additionalMessage: String = ""): List<AssertionError> {
private fun processIgnoreBackend(
moduleStructure: TestModuleStructure,
directive: ValueDirective<TargetBackend>,
targetBackends: List<TargetBackend>,
failedAssertions: List<AssertionError>
): List<AssertionError> {
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<AssertionError>,
directive: ValueDirective<TargetBackend>,
additionalMessage: String = ""
): List<AssertionError> {
return if (failedAssertions.isNotEmpty()) emptyList()
else {
val message = buildString {
append("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive")
append("Looks like this test can be unmuted. Remove ${directive.name} directive")
if (additionalMessage.isNotEmpty()) {
append(" ")
append(additionalMessage)
@@ -0,0 +1,59 @@
/*
* 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.backend.handlers
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderer
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_FIR_DIAGNOSTICS
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirAnalysisHandler
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHandler(testServices) {
override val directivesContainers: List<DirectivesContainer>
get() = listOf(CodegenTestDirectives)
override fun processModule(module: TestModule, info: FirOutputArtifact) {
var hasError = false
val ignoreErrors = IGNORE_FIR_DIAGNOSTICS in module.directives
for ((firFile, diagnostics) in info.firAnalyzerFacade.runCheckers()) {
for (diagnostic in diagnostics) {
if (diagnostic.severity == Severity.ERROR) {
hasError = true
if (!ignoreErrors) {
val diagnosticText = FirDefaultErrorMessages.getRendererForDiagnostic(diagnostic).hackyRender(diagnostic)
val range = diagnostic.textRanges.first()
val locationText = firFile.source?.psi?.containingFile?.let { psiFile ->
PsiDiagnosticUtils.atLocation(psiFile, range)
} ?: "${firFile.name}:$range"
throw IllegalStateException("${diagnostic.factory.name}: $diagnosticText at $locationText")
}
}
}
}
if (!hasError && ignoreErrors) {
assertions.fail { "Test contains $IGNORE_FIR_DIAGNOSTICS directive but no errors was reported. Please remove directive" }
}
}
private fun FirDiagnosticRenderer<*>.hackyRender(diagnostic: FirDiagnostic<*>): String {
@Suppress("UNCHECKED_CAST")
val renderer = this as FirDiagnosticRenderer<FirDiagnostic<FirSourceElement>>
val castedDiagnostic = diagnostic as FirDiagnostic<FirSourceElement>
return renderer.render(castedDiagnostic)
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
}
@@ -13,6 +13,10 @@ object CodegenTestDirectives : SimpleDirectivesContainer() {
description = "Ignore failures of test on target backend"
)
val IGNORE_BACKEND_FIR by enumDirective<TargetBackend>(
description = "Ignore specific backend if test uses FIR"
)
val JAVAC_OPTIONS by stringDirective(
description = "Specify javac options to compile java files"
)
@@ -35,4 +39,8 @@ object CodegenTestDirectives : SimpleDirectivesContainer() {
val IGNORE_DEXING by directive(
description = "Ignore dex checkers"
)
val IGNORE_FIR_DIAGNOSTICS by directive(
description = "Run backend even FIR reported some diagnostics with ERROR severity"
)
}
@@ -9,12 +9,18 @@ import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.classic.ClassicJvmBackendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2ClassicBackendConverter
import org.jetbrains.kotlin.test.model.BackendFacade
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.model.*
open class AbstractBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase(TargetBackend.JVM) {
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<*, *>>
open class AbstractBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase<ClassicFrontendOutputArtifact>(
FrontendKinds.ClassicFrontend,
TargetBackend.JVM
) {
override val frontendFacade: Constructor<FrontendFacade<ClassicFrontendOutputArtifact>>
get() = ::ClassicFrontendFacade
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<ClassicFrontendOutputArtifact, *>>
get() = ::ClassicFrontend2ClassicBackendConverter
override val backendFacade: Constructor<BackendFacade<*, BinaryArtifacts.Jvm>>
@@ -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.runners.codegen
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.USE_PSI_CLASS_FILES_READING
import org.jetbrains.kotlin.test.frontend.fir.Fir2IrResultsConverter
import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.model.*
open class AbstractFirBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase<FirOutputArtifact>(
FrontendKinds.FIR,
TargetBackend.JVM_IR
) {
override val frontendFacade: Constructor<FrontendFacade<FirOutputArtifact>>
get() = ::FirFrontendFacade
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<FirOutputArtifact, *>>
get() = ::Fir2IrResultsConverter
override val backendFacade: Constructor<BackendFacade<*, BinaryArtifacts.Jvm>>
get() = ::JvmIrBackendFacade
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
defaultDirectives {
// See KT-44152
-USE_PSI_CLASS_FILES_READING
}
}
}
}
@@ -9,12 +9,18 @@ import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2IrConverter
import org.jetbrains.kotlin.test.model.BackendFacade
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.model.*
open class AbstractIrBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase(TargetBackend.JVM_IR) {
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<*, *>>
open class AbstractIrBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase<ClassicFrontendOutputArtifact>(
FrontendKinds.ClassicFrontend,
TargetBackend.JVM_IR
) {
override val frontendFacade: Constructor<FrontendFacade<ClassicFrontendOutputArtifact>>
get() = ::ClassicFrontendFacade
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<ClassicFrontendOutputArtifact, *>>
get() = ::ClassicFrontend2IrConverter
override val backendFacade: Constructor<BackendFacade<*, BinaryArtifacts.Jvm>>
@@ -12,9 +12,7 @@ import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
import org.jetbrains.kotlin.test.backend.handlers.*
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.RUN_DEX_CHECKER
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.REPORT_JVM_DIAGNOSTICS_ON_FRONTEND
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.USE_PSI_CLASS_FILES_READING
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
@@ -23,22 +21,23 @@ import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsS
import org.jetbrains.kotlin.test.services.sourceProviders.CodegenHelpersSourceFilesProvider
import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider
abstract class AbstractJvmBlackBoxCodegenTestBase(
abstract class AbstractJvmBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendOutput<R>>(
val targetFrontend: FrontendKind<R>,
targetBackend: TargetBackend
) : AbstractKotlinCompilerWithTargetBackendTest(targetBackend) {
abstract val frontendToBackendConverter: Constructor<Frontend2BackendConverter<*, *>>
abstract val frontendFacade: Constructor<FrontendFacade<R>>
abstract val frontendToBackendConverter: Constructor<Frontend2BackendConverter<R, *>>
abstract val backendFacade: Constructor<BackendFacade<*, BinaryArtifacts.Jvm>>
override fun TestConfigurationBuilder.configuration() {
globalDefaults {
frontend = FrontendKinds.ClassicFrontend
frontend = targetFrontend
targetPlatform = JvmPlatforms.defaultJvmPlatform
dependencyKind = DependencyKind.Binary
}
defaultDirectives {
+USE_PSI_CLASS_FILES_READING
+REPORT_JVM_DIAGNOSTICS_ON_FRONTEND
+RUN_DEX_CHECKER
}
@@ -53,11 +52,15 @@ abstract class AbstractJvmBlackBoxCodegenTestBase(
::CodegenHelpersSourceFilesProvider,
)
useFrontendFacades(::ClassicFrontendFacade)
useFrontendFacades(frontendFacade)
useFrontend2BackendConverters(frontendToBackendConverter)
useBackendFacades(backendFacade)
useFrontendHandlers(::NoCompilationErrorsHandler)
useFrontendHandlers(
::NoCompilationErrorsHandler,
::NoFirCompilationErrorsHandler,
)
useArtifactsHandlers(
::JvmBoxRunner,
::NoJvmSpecificCompilationErrorsHandler,
@@ -506,10 +506,6 @@ fun generateJUnit3CompilerTests(args: Array<String>) {
testRunnerMethodName = "runTestWithCustomIgnoreDirective",
additionalRunnerArguments = listOf("\"// IGNORE_BACKEND_FIR: \"")
) {
testClass<AbstractFirBlackBoxCodegenTest> {
model("codegen/box", targetBackend = TargetBackend.JVM_IR, excludeDirs = listOf("oldLanguageVersions"))
}
testClass<AbstractFirBlackBoxInlineCodegenTest> {
model("codegen/boxInline", targetBackend = TargetBackend.JVM_IR, excludeDirs = listOf("oldLanguageVersions"))
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.runners.*
import org.jetbrains.kotlin.test.runners.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.test.runners.codegen.AbstractFirBlackBoxCodegenTest
import org.jetbrains.kotlin.test.runners.codegen.AbstractIrBlackBoxCodegenTest
fun generateJUnit5CompilerTests(args: Array<String>) {
@@ -72,6 +73,10 @@ fun generateJUnit5CompilerTests(args: Array<String>) {
model("diagnostics/tests", excludedPattern = excludedFirTestdataPattern)
model("diagnostics/testsWithStdLib", excludedPattern = excludedFirTestdataPattern)
}
testClass<AbstractFirBlackBoxCodegenTest> {
model("codegen/box", excludeDirs = listOf("oldLanguageVersions"))
}
}
testGroup("compiler/fir/analysis-tests/tests-gen", "compiler/fir/analysis-tests/testData") {