[kotlin] update k1/k2 parity report

GitOrigin-RevId: 4cdfdd10470dedd311a025bfc30e6c0734492532
This commit is contained in:
Vladimir Dolzhenko
2024-05-10 22:02:39 +02:00
committed by intellij-monorepo-bot
parent 64026b8f21
commit 5a733e68df
2 changed files with 204 additions and 5293 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -13,12 +13,13 @@ import org.jetbrains.kotlin.testGenerator.model.TWorkspace
import java.io.File
import java.util.Date
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.roundToInt
fun main() {
fun main(vararg args: String) {
val k2Workspace = assembleK2Workspace()
val k1Workspace = assembleK1Workspace()
ParityReportGenerator.generateReport(k1Workspace = k1Workspace, k2Workspace = k2Workspace)
ParityReportGenerator.generateReport(k1Workspace = k1Workspace, k2Workspace = k2Workspace, detailed = args.any { it == "detailed" })
}
object ParityReportGenerator {
@@ -26,6 +27,7 @@ object ParityReportGenerator {
data class Variation(
val name: String,
val ignoreDirectives: Set<String>,
val totalByCategory: MutableMap<GroupCategory, AtomicInteger> = mutableMapOf<GroupCategory, AtomicInteger>(),
val successByCategory: MutableMap<GroupCategory, AtomicInteger> = mutableMapOf<GroupCategory, AtomicInteger>(),
val successTestClasses: MutableMap<String, AtomicInteger> = mutableMapOf<String, AtomicInteger>()
) {
@@ -38,9 +40,13 @@ object ParityReportGenerator {
private const val SUCCESS_RATE_THRESHOLD = 85
val k1Variation = Variation("K1", setOf("// IGNORE_K1", "/* IGNORE_K1", "\"enabledInK1\": \"false\""))
val k2Variation = Variation("K2", setOf("// IGNORE_K2", "/* IGNORE_K2", "\"enabledInK2\": \"false\""))
val k2Variation = Variation("K2", setOf("// IGNORE_K2", "/* IGNORE_K2", "\"enabledInK2\": \"false\"", "// IGNORE_FOR_K2_CODE", "// IGNORE_K2_SMART_STEP_INTO"))
fun generateReport(k1Workspace: TWorkspace, k2Workspace: TWorkspace) {
fun generateReport(
k1Workspace: TWorkspace,
k2Workspace: TWorkspace,
detailed: Boolean,
) {
val md = buildString {
appendLine("# K2/K1 feature parity report").appendLine().appendLine()
appendLine("Generated on ${Date()}").appendLine()
@@ -52,10 +58,12 @@ object ParityReportGenerator {
val k1InvertedFileCases = toInvertedFileCases(k1Cases)
val k2InvertedFileCases = toInvertedFileCases(k2Cases)
reportK1OnlyFilesDetails(k1InvertedFileCases, k2InvertedFileCases, extraBuilder)
reportK1OnlyFilesDetails(k1InvertedFileCases, k2InvertedFileCases, detailed, extraBuilder)
reportSharedFilesDetails(k1InvertedFileCases, k2InvertedFileCases, this)
append(extraBuilder)
if (detailed) {
append(extraBuilder)
}
}
File(KotlinRoot.DIR, "k2-k1-parity-report.md").writeText(md.replace("\n", System.lineSeparator()))
}
@@ -173,6 +181,7 @@ object ParityReportGenerator {
val counter = it.successByCategory.computeIfAbsent(category) { AtomicInteger() }
counter.incrementAndGet()
}
variation.totalByCategory.computeIfAbsent(category) { AtomicInteger() }.incrementAndGet()
}
}
@@ -222,18 +231,8 @@ object ParityReportGenerator {
}
with(stringBuilder) {
appendLine("## Categories")
appendLine()
appendLine("| Status | Category | Success rate, % | K2 files | K1 files |")
appendLine("| -- | -- | -- | -- | -- |")
GroupCategory.entries.forEach {
val k2 = k2Variation.successByCategory[it]?.get() ?: 0
val k1 = k1Variation.successByCategory[it]?.get() ?: 0
if (k2 == 0 && k1 == 0) return@forEach
val statusLine = StatusLine(it.name, k2, k1, testClassesPerCategory[it]?.get() ?: 0)
appendLine(statusLine.renderToMd())
}
appendLine()
k2Categories(testClassesPerCategory)
categoriesParity(testClassesPerCategory)
appendLine("## Shared cases")
appendLine("shared ${sharedFiles.size} files out of ${k2Variation.successTestClasses.size} cases").appendLine()
@@ -253,11 +252,11 @@ object ParityReportGenerator {
val lastPart = substringAfter.substringBefore("$")
"$firstPart$$lastPart"
}.map {
StatusLine(it.key, it.value.sumOf { it.k2 }, it.value.sumOf { it.k1 }, it.value.sumOf { it.files })
StatusLine(it.key, it.value.sumOf { it.first }, it.value.sumOf { it.second }, it.value.sumOf { it.files })
}.groupBy {
it.name.substringBefore("$")
}.map {
StatusLine(it.key, it.value.map { it.k2 }.min(), it.value.map { it.k1 }.min(), it.value.sumOf { it.files }) to it.value
StatusLine(it.key, it.value.map { it.first }.min(), it.value.map { it.second }.min(), it.value.sumOf { it.files }) to it.value
}
.sortedWith(compareBy({ it.first.rate }, { it.first.name }))
.forEach {
@@ -265,13 +264,13 @@ object ParityReportGenerator {
val second = it.second
// no reasons to report all sub-elements if total it is 100%
if (first.rate == 100) {
val line = StatusLine("[${first.name}]", second.sumOf { it.k2 }, second.sumOf { it.k1 }, second.sumOf { it.files })
val line = StatusLine("[${first.name}]", second.sumOf { it.first }, second.sumOf { it.second }, second.sumOf { it.files })
appendLine(line.renderToMd())
} else {
// summary
if (first.name != second.first().name && second.size > 1) {
val line =
StatusLine("[${first.name}]", second.sumOf { it.k2 }, second.sumOf { it.k1 }, second.sumOf { it.files })
StatusLine("[${first.name}]", second.sumOf { it.first }, second.sumOf { it.second }, second.sumOf { it.files })
appendLine(line.renderToMd())
}
// detailed
@@ -289,24 +288,71 @@ object ParityReportGenerator {
appendLine(extensions.joinToString()).appendLine()
appendLine("---")
appendLine("## Total ")
appendLine(" * K1: $successK1 rate: ${Math.round(100.0 * successK1 / sharedFiles.size)} % of $totalPerCase files")
appendLine(" * K2: $successK2 rate: ${Math.round(100.0 * successK2 / sharedFiles.size)} % of $totalPerCase files")
appendLine(" * K1: $successK1 rate: ${(100.0 * successK1 / sharedFiles.size).roundToInt()} % of $totalPerCase files")
appendLine(" * K2: $successK2 rate: ${(100.0 * successK2 / sharedFiles.size).roundToInt()} % of $totalPerCase files")
appendLine("---").appendLine()
}
}
private fun StringBuilder.k2Categories(testClassesPerCategory: MutableMap<GroupCategory, AtomicInteger>) {
appendLine("## K2 Success rate per category")
appendLine()
appendLine(
"""
Success rate is ratio of
number of files successfully passed in a category
to total number of files in this category.
""".trimIndent()
)
appendLine()
appendLine("| Status | Category | Success rate, % | Success files | Total files |")
appendLine("| -- | -- | -- | -- | -- |")
GroupCategory.entries.forEach {
val k2 = k2Variation.successByCategory[it]?.get() ?: 0
val total = k2Variation.totalByCategory[it]?.get() ?: 0
if (k2 == 0 && total == 0) return@forEach
val statusLine = StatusLine(it.name, k2, total, testClassesPerCategory[it]?.get() ?: 0)
appendLine(statusLine.renderToMd())
}
appendLine()
}
private fun StringBuilder.categoriesParity(testClassesPerCategory: MutableMap<GroupCategory, AtomicInteger>) {
appendLine("## K2/K1 parity per category ")
appendLine()
appendLine(
"""
Success rate is ratio of
number of files successfully passed in K2 in a category
to number of files successfully passed in K1 in the same category.
""".trimIndent()
)
appendLine()
appendLine("| Status | Category | Success rate, % | K2 files | K1 files |")
appendLine("| -- | -- | -- | -- | -- |")
GroupCategory.entries.forEach {
val k2 = k2Variation.successByCategory[it]?.get() ?: 0
val k1 = k1Variation.successByCategory[it]?.get() ?: 0
if (k2 == 0 && k1 == 0) return@forEach
val statusLine = StatusLine(it.name, k2, k1, testClassesPerCategory[it]?.get() ?: 0)
appendLine(statusLine.renderToMd())
}
appendLine()
}
private data class StatusLine(
val name: String,
val k2: Int,
val k1: Int,
val first: Int,
val second: Int,
val files: Int
) {
val rate: Int = if (k1 > 0) Math.round(100.0 * k2 / k1).toInt() else 100
val rate: Int = if (second > 0) (100.0 * first / second).roundToInt() else 100
val passed = rate >= SUCCESS_RATE_THRESHOLD
fun renderToMd(): String {
val shortName = if (!name[0].isLetter()) (name[0] + name.substringAfterLast('.')) else name.substringAfterLast('.')
return PIPE + listOf(if (passed) ":white_check_mark:" else ":x:", shortName, rate, k2, k1, files).joinToString(
return PIPE + listOf(if (passed) ":white_check_mark:" else ":x:", shortName, rate, first, second, files).joinToString(
PIPE
) + PIPE
}
@@ -330,6 +376,7 @@ object ParityReportGenerator {
private fun reportK1OnlyFilesDetails(
invertedK1FileCases: Map<String, Case>,
invertedK2FileCases: Map<String, Case>,
detailed: Boolean,
stringBuilder: StringBuilder
) {
val k1OnlyCases = mutableSetOf<Case>()
@@ -344,11 +391,13 @@ object ParityReportGenerator {
}
}
with(stringBuilder) {
appendLine("## K1 only cases").appendLine()
appendLine("${k1OnlyCases.size} K1 only cases (${k1OnlyFiles.size} files):").appendLine()
k1OnlyCases.flatMap { it.files }.map { " * " + it.generatedClassName }.toSortedSet().forEach { appendLine(it) }
appendLine("---")
if (detailed) {
with(stringBuilder) {
appendLine("## K1 only cases").appendLine()
appendLine("${k1OnlyCases.size} K1 only cases (${k1OnlyFiles.size} files):").appendLine()
k1OnlyCases.flatMap { it.files }.map { " * " + it.generatedClassName }.toSortedSet().forEach { appendLine(it) }
appendLine("---")
}
}
}
}