[Test] Migrate AbstractFir2IrTextTest to new infrastructure

This commit is contained in:
Dmitriy Novozhilov
2021-01-20 13:00:22 +03:00
committed by TeamCityServer
parent aba029237d
commit bdcb8aecab
10 changed files with 677 additions and 264 deletions

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2010-2019 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.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade
import org.jetbrains.kotlin.ir.AbstractIrTextTestCase
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import java.io.File
abstract class AbstractFir2IrTextTest : AbstractIrTextTestCase() {
private fun prepareProjectExtensions(project: Project) {
PsiElementFinder.EP.getPoint(project).unregisterExtension(JavaElementFinder::class.java)
}
override fun doTest(wholeFile: File, testFiles: List<TestFile>) {
buildFragmentAndTestIt(wholeFile, testFiles)
}
override fun doTest(filePath: String) {
val oldFrontendTextPath = filePath.replace(".kt", ".txt")
val firTextPath = filePath.replace(".kt", ".fir.txt")
val oldFrontendTextFile = File(oldFrontendTextPath)
val firTextFile = File(firTextPath)
if (oldFrontendTextFile.exists() && firTextFile.exists()) {
compareAndMergeFirFileAndOldFrontendFile(oldFrontendTextFile, firTextFile, compareWithTrimming = true)
}
super.doTest(filePath)
}
override fun getExpectedTextFileName(testFile: TestFile, name: String): String {
// NB: replace with if (true) to make test against old FE results
if ("// FIR_IDENTICAL" in testFile.content.split("\n")) {
return super.getExpectedTextFileName(testFile, name)
}
return name.replace(".txt", ".fir.txt").replace(".kt", ".fir.txt")
}
override fun generateIrModule(ignoreErrors: Boolean): IrModuleFragment {
val psiFiles = myFiles.psiFiles
val project = psiFiles.first().project
prepareProjectExtensions(project)
val scope = GlobalSearchScope.filesScope(project, psiFiles.map { it.virtualFile })
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
val session = createSession(myEnvironment, scope)
val firAnalyzerFacade = FirAnalyzerFacade(session, myEnvironment.configuration.languageVersionSettings, psiFiles)
return firAnalyzerFacade.convertToIr(JvmGeneratorExtensions(generateFacades = false)).irModuleFragment
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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.test.backend.handlers
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.FIR_IDENTICAL
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.moduleStructure
import org.jetbrains.kotlin.test.utils.FirIdenticalCheckerHelper
import org.jetbrains.kotlin.test.utils.withExtension
import java.io.File
class FirIrDumpIdenticalChecker(testServices: TestServices) : AfterAnalysisChecker(testServices) {
override val directives: List<DirectivesContainer>
get() = listOf(FirDiagnosticsDirectives)
private val simpleDumpChecker = object : FirIdenticalCheckerHelper(testServices) {
override fun getClassicFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension(IrTextDumpHandler.DUMP_EXTENSION).takeIf { it.exists() }
}
override fun getFirFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension("fir.${IrTextDumpHandler.DUMP_EXTENSION}").takeIf { it.exists() }
}
}
private val prettyDumpChecker = object : FirIdenticalCheckerHelper(testServices) {
override fun getClassicFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension(IrPrettyKotlinDumpHandler.DUMP_EXTENSION).takeIf { it.exists() }
}
override fun getFirFileToCompare(testDataFile: File): File? {
return testDataFile.withExtension("fir.${IrPrettyKotlinDumpHandler.DUMP_EXTENSION}").takeIf { it.exists() }
}
}
override fun check(failedAssertions: List<AssertionError>) {
if (failedAssertions.isNotEmpty()) return
val testDataFile = testServices.moduleStructure.originalTestDataFiles.first()
if (FIR_IDENTICAL in testServices.moduleStructure.allDirectives) {
simpleDumpChecker.deleteFirFile(testDataFile)
prettyDumpChecker.deleteFirFile(testDataFile)
return
}
if (
simpleDumpChecker.firAndClassicContentsAreEquals(testDataFile) &&
prettyDumpChecker.firAndClassicContentsAreEquals(testDataFile, trimLines = true)
) {
simpleDumpChecker.deleteFirFile(testDataFile)
prettyDumpChecker.deleteFirFile(testDataFile)
simpleDumpChecker.addDirectiveToClassicFileAndAssert(testDataFile)
}
}
}

View File

@@ -11,9 +11,12 @@ import org.jetbrains.kotlin.ir.util.dumpKotlinLike
import org.jetbrains.kotlin.test.backend.handlers.IrTextDumpHandler.Companion.computeDumpExtension
import org.jetbrains.kotlin.test.backend.handlers.IrTextDumpHandler.Companion.groupWithTestFiles
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_KT_IR
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.EXTERNAL_FILE
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.SKIP_KT_DUMP
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.moduleStructure
@@ -21,8 +24,15 @@ import org.jetbrains.kotlin.test.utils.MultiModuleInfoDumperImpl
import org.jetbrains.kotlin.test.utils.withExtension
class IrPrettyKotlinDumpHandler(testServices: TestServices) : AbstractIrHandler(testServices) {
companion object {
const val DUMP_EXTENSION = "kt.txt"
}
private val dumper = MultiModuleInfoDumperImpl("// MODULE: %s")
override val directivesContainers: List<DirectivesContainer>
get() = listOf(CodegenTestDirectives, FirDiagnosticsDirectives)
override fun processModule(module: TestModule, info: IrBackendInput) {
if (DUMP_KT_IR !in module.directives || SKIP_KT_DUMP in module.directives) return
@@ -47,7 +57,7 @@ class IrPrettyKotlinDumpHandler(testServices: TestServices) : AbstractIrHandler(
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
if (dumper.isEmpty()) return
val moduleStructure = testServices.moduleStructure
val extension = computeDumpExtension(moduleStructure.modules.first(), "kt.txt")
val extension = computeDumpExtension(moduleStructure.modules.first(), DUMP_EXTENSION)
val expectedFile = moduleStructure.originalTestDataFiles.first().withExtension(extension)
assertions.assertEqualsToFile(expectedFile, dumper.generateResultingDump())
}

View File

@@ -36,6 +36,8 @@ import java.io.File
class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServices) {
companion object {
const val DUMP_EXTENSION = "txt"
fun computeDumpExtension(module: TestModule, defaultExtension: String): String {
return if (module.frontendKind == FrontendKinds.ClassicFrontend || FIR_IDENTICAL in module.directives)
defaultExtension else "fir.$defaultExtension"
@@ -74,6 +76,9 @@ class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServ
}
private fun compareDumpsOfExternalClasses(module: TestModule, info: IrBackendInput) {
// FIR doesn't support searching descriptors
if (module.frontendKind == FrontendKinds.FIR) return
val externalClassFqns = module.directives[DUMP_EXTERNAL_CLASS]
if (externalClassFqns.isEmpty()) return
@@ -121,5 +126,5 @@ class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServ
}
private val TestModule.dumpExtension: String
get() = computeDumpExtension(this, "txt")
get() = computeDumpExtension(this, DUMP_EXTENSION)
}

View File

@@ -5,49 +5,43 @@
package org.jetbrains.kotlin.test.frontend.fir.handlers
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.services.moduleStructure
import org.jetbrains.kotlin.test.utils.FirIdenticalCheckerHelper
import org.jetbrains.kotlin.test.utils.firTestDataFile
import org.jetbrains.kotlin.test.utils.isFirTestData
import org.jetbrains.kotlin.test.utils.originalTestDataFile
import java.io.File
class FirIdenticalChecker(testServices: TestServices) : AfterAnalysisChecker(testServices) {
private val helper = object : FirIdenticalCheckerHelper(testServices) {
override fun getClassicFileToCompare(testDataFile: File): File {
return if (testDataFile.isFirTestData) testDataFile.originalTestDataFile else testDataFile
}
override fun getFirFileToCompare(testDataFile: File): File {
return if (testDataFile.isFirTestData) testDataFile else testDataFile.firTestDataFile
}
}
override fun check(failedAssertions: List<AssertionError>) {
if (failedAssertions.isNotEmpty()) return
val file = testServices.moduleStructure.originalTestDataFiles.first()
if (file.isFirTestData) {
addDirectiveToClassicFile(file)
val testDataFile = testServices.moduleStructure.originalTestDataFiles.first()
if (testDataFile.isFirTestData) {
val firFile = helper.getFirFileToCompare(testDataFile)
val classicFile = helper.getClassicFileToCompare(testDataFile)
if (helper.contentsAreEquals(classicFile, firFile)) {
helper.deleteFirFile(testDataFile)
helper.addDirectiveToClassicFileAndAssert(testDataFile)
}
} else {
removeFirFileIfExist(file)
removeFirFileIfExist(testDataFile)
}
}
private fun addDirectiveToClassicFile(firFile: File) {
val classicFile = firFile.originalTestDataFile
val classicFileContent = classicFile.readText()
val firFileContent = firFile.readText()
if (classicFileContent == firFileContent) {
classicFile.writer().use {
it.appendLine("// ${FirDiagnosticsDirectives.FIR_IDENTICAL.name}")
it.append(classicFileContent)
}
firFile.delete()
testServices.assertions.fail {
"""
Dumps via FIR & via old FE are the same.
Deleted .fir.txt dump, added // FIR_IDENTICAL to test source
Please re-run the test now
""".trimIndent()
}
}
}
private fun removeFirFileIfExist(classicFile: File) {
val firFile = classicFile.firTestDataFile
private fun removeFirFileIfExist(testDataFile: File) {
val firFile = helper.getFirFileToCompare(testDataFile)
firFile.delete()
}
}

View File

@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.test.runners.ir
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.handlers.IrPrettyKotlinDumpHandler
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
import org.jetbrains.kotlin.test.backend.handlers.*
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_IR
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_KT_IR
@@ -70,3 +70,12 @@ abstract class AbstractIrTextTestBase(
}
open class AbstractIrTextTest : AbstractIrTextTestBase(FrontendKinds.ClassicFrontend)
open class AbstractFir2IrTextTest : AbstractIrTextTestBase(FrontendKinds.FIR) {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
useAfterAnalysisCheckers(::FirIrDumpIdenticalChecker)
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.test.utils
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import java.io.File
abstract class FirIdenticalCheckerHelper(private val testServices: TestServices) {
abstract fun getClassicFileToCompare(testDataFile: File): File?
abstract fun getFirFileToCompare(testDataFile: File): File?
fun firAndClassicContentsAreEquals(testDataFile: File, trimLines: Boolean = false): Boolean {
val classicFile = getClassicFileToCompare(testDataFile) ?: return true
val firFile = getFirFileToCompare(testDataFile) ?: return true
return contentsAreEquals(classicFile, firFile, trimLines)
}
fun contentsAreEquals(classicFile: File, firFile: File, trimLines: Boolean = false): Boolean {
val classicFileContent = classicFile.readContent(trimLines)
val firFileContent = firFile.readContent(trimLines)
return classicFileContent == firFileContent
}
private fun File.readContent(trimLines: Boolean): String {
return if (trimLines) {
this.readLines().map { it.trimEnd() }.joinToString("\n").trimEnd()
} else {
this.readText()
}
}
fun addDirectiveToClassicFileAndAssert(testDataFile: File) {
val classicFileContent = testDataFile.readText()
testDataFile.writer().use {
it.appendLine("// ${FirDiagnosticsDirectives.FIR_IDENTICAL.name}")
it.append(classicFileContent)
}
testServices.assertions.fail {
"""
Dumps via FIR & via old FE are the same.
Deleted .fir.txt dump, added // FIR_IDENTICAL to test source
Please re-run the test now
""".trimIndent()
}
}
fun deleteFirFile(testDataFile: File) {
getFirFileToCompare(testDataFile)?.takeIf { it.exists() }?.delete()
}
}

View File

@@ -597,16 +597,6 @@ fun generateJUnit3CompilerTests(args: Array<String>) {
}
}
testGroup(
"compiler/fir/fir2ir/tests-gen", "compiler/testData",
testRunnerMethodName = "runTestWithCustomIgnoreDirective",
additionalRunnerArguments = listOf("\"// IGNORE_BACKEND_FIR: \"")
) {
testClass<AbstractFir2IrTextTest> {
model("ir/irText")
}
}
testGroup("compiler/visualizer/tests-gen", "compiler/fir/raw-fir/psi2fir/testData") {
testClass<AbstractPsiVisualizer>("PsiVisualizerForRawFirDataGenerated") {
model("rawBuilder", testMethod = "doFirBuilderDataTest")

View File

@@ -12,6 +12,7 @@ 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
import org.jetbrains.kotlin.test.runners.ir.AbstractFir2IrTextTest
import org.jetbrains.kotlin.test.runners.ir.AbstractIrTextTest
import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode
@@ -99,6 +100,11 @@ fun generateJUnit5CompilerTests(args: Array<String>) {
model("resolve", pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME)
}
}
}
testGroup(testsRoot = "compiler/fir/analysis-tests/tests-gen", testDataRoot = "compiler/testData") {
testClass<AbstractFir2IrTextTest> {
model("ir/irText")
}
}
}
}