Compare module metadata in JVM ABI consistency tests

This commit is contained in:
vladislav.grechko
2024-02-06 12:13:49 +01:00
committed by Space Team
parent ba217ad688
commit b74501ee93
9 changed files with 200 additions and 18 deletions
@@ -25,6 +25,14 @@ fun ClassFileFactory.getClassFiles(): Iterable<OutputFile> {
return asList().filterClassFiles()
}
fun ClassFileFactory.getKotlinModuleFile(): OutputFile? = asList().filter { it.relativePath.endsWith(".kotlin_module") }.run {
when (size) {
0 -> null
1 -> single()
else -> error("Module has non-unique .kotlin_metadata file")
}
}
fun List<OutputFile>.filterClassFiles(): List<OutputFile> {
return filter { it.relativePath.endsWith(".class") }
}
@@ -9,3 +9,9 @@ MODULE main
<set-?>: kotlin/Int
K2
value: kotlin/Int
MODULE METADATA
Property: module.metadata.optionalAnnotations
K1
[Anno]
K2
[]
@@ -10,8 +10,10 @@ import org.jetbrains.kotlin.abicmp.defects.Location
import org.jetbrains.kotlin.abicmp.reports.*
import org.jetbrains.kotlin.abicmp.tag
import org.jetbrains.kotlin.abicmp.tasks.ClassTask
import org.jetbrains.kotlin.abicmp.tasks.ModuleMetadataTask
import org.jetbrains.kotlin.abicmp.tasks.checkerConfiguration
import org.jetbrains.kotlin.codegen.getClassFiles
import org.jetbrains.kotlin.codegen.getKotlinModuleFile
import org.jetbrains.kotlin.test.backend.ir.AbiCheckerSuppressor
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.model.*
@@ -35,6 +37,7 @@ class JvmAbiConsistencyHandler(testServices: TestServices) : AnalysisHandler<Bin
val missingInK1: Set<String>,
val missingInK2: Set<String>,
val nonEmptyClassReports: MutableList<ClassReport>,
val moduleMetadataReport: ModuleMetadataReport,
)
private class TestReport {
@@ -63,9 +66,14 @@ class JvmAbiConsistencyHandler(testServices: TestServices) : AnalysisHandler<Bin
node("MODULE $module") {
reportMissing("K1", report.missingInK1)
reportMissing("K2", report.missingInK2)
report.nonEmptyClassReports.forEach { classReport ->
with(classReport) { appendClassReport() }
}
if (!report.moduleMetadataReport.isEmpty()) {
with(report.moduleMetadataReport) { appendModuleMetadataReport() }
}
}
}
}
@@ -164,27 +172,45 @@ class JvmAbiConsistencyHandler(testServices: TestServices) : AnalysisHandler<Bin
if (AbiCheckerSuppressor.ignoredByBackendOrInliner(testServices)) return
val classesFromK1 = info.fromK1.classFileFactory.getClassFiles().associate { it.relativePath to it.asByteArray() }
val classesFromK2 = info.fromK2.classFileFactory.getClassFiles().associate { it.relativePath to it.asByteArray() }
val missingInK2 = Sets.difference(classesFromK1.keys, classesFromK2.keys)
val missingInK1 = Sets.difference(classesFromK2.keys, classesFromK1.keys)
val missingInK2 = Sets.difference(classesFromK1.keys, classesFromK2.keys).toMutableSet()
val missingInK1 = Sets.difference(classesFromK2.keys, classesFromK1.keys).toMutableSet()
val commonClasses = Sets.intersection(classesFromK1.keys, classesFromK2.keys)
val configuration = checkerConfiguration {
// Indication of constants is different in K2 as expected
// We simply turn the checker off to avoid producing an enormous number of difference reports
disable("class.metadata.property.hasConstant")
}
val nonEmptyClassReports = mutableListOf<ClassReport>()
commonClasses.forEach { classInternalName ->
val k1ClassNode = parseClassNode(classesFromK1[classInternalName]!!)
val k2ClassNode = parseClassNode(classesFromK2[classInternalName]!!)
val classReport = ClassReport(Location.Class("", classInternalName), classInternalName, "K1", "K2", DefectReport())
ClassTask(checkerConfiguration {
// Indication of constants is different in K2 as expected
// We simply turn the checker off to avoid producing an enormous number of difference reports
disable("class.metadata.property.hasConstant")
}, k1ClassNode, k2ClassNode, classReport).run()
ClassTask(configuration, k1ClassNode, k2ClassNode, classReport).run()
if (classReport.isNotEmpty()) {
nonEmptyClassReports.add(classReport)
}
}
if (nonEmptyClassReports.isNotEmpty() || missingInK1.isNotEmpty() || missingInK2.isNotEmpty()) {
testReport.addModuleReport(module.name, ModuleReport(missingInK1, missingInK2, nonEmptyClassReports))
val k1ModuleFile = info.fromK1.classFileFactory.getKotlinModuleFile()
val k2ModuleFile = info.fromK2.classFileFactory.getKotlinModuleFile()
if (k1ModuleFile == null && k2ModuleFile != null) {
missingInK1.add(k2ModuleFile.relativePath)
}
if (k1ModuleFile != null && k2ModuleFile == null) {
missingInK2.add(k1ModuleFile.relativePath)
}
val moduleMetadataReport = ModuleMetadataReport("K1", "K2")
if (k1ModuleFile != null && k2ModuleFile != null) {
ModuleMetadataTask(configuration, k1ModuleFile.asByteArray(), k2ModuleFile.asByteArray(), moduleMetadataReport).run()
}
if (nonEmptyClassReports.isNotEmpty() || missingInK1.isNotEmpty() || missingInK2.isNotEmpty() || !moduleMetadataReport.isEmpty()) {
testReport.addModuleReport(module.name, ModuleReport(missingInK1, missingInK2, nonEmptyClassReports, moduleMetadataReport))
}
}