diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt index f6d5d16a97a..8a11389b6c5 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -34,17 +34,6 @@ class CoverageReporter( fun generateRichTextReport(): Pair { logCoverageReport() - // Rough - /* If HTML -> HTML report -> send reportText -> Done - * If MD -> generate report() -> send reportText ("file.kt, 23%, 2/4 lines, :x:") - * oh wait no... the last one is decided also based on exemption - * so after coverageCheckThreshold -> determine coverage status -> - * set coverage status to PASS or FAIL - * reportText += " > :tick: ; < :wrong:" - * - * In execute after awaitAll -> check MD -> generateMD report - * */ - return when (reportFormat) { ReportFormat.MARKDOWN -> generateMarkdownReport() ReportFormat.HTML -> generateHtmlReport() @@ -52,70 +41,10 @@ class CoverageReporter( } private fun generateMarkdownReport(): Pair { - // TODO: (remove) - /*Thinking of alternating or having 2 versions - * one for just printing to the console - * two an actual md template with dropdowns as discussed in meeting - * - * Adding the meeting template for reference here - * Total coverage: - * Files covered: (# changed / # run with coverage) - * Coverage percentage: ##% covered / ##% expected - * LOC: # covered / # instrumented - * - * (indent left) Specific coverage: - * app/src/.../app - * home - * HomeActivity.kt - 87% (110/115) - * ... - * ... - * - * ### Coverage Report - *
- * MathModel.kt - 100% - * - *
- * - * Sample template for reference: - * |Covered File|Percentage|Line Coverage|Status| - |-------------|:----------:|:---------------:|:------:| - |[HomeActivity.kt](https://www.github.com)|53.00%|4/7 lines|:x:| - - - # Coverage Report - - ## Failed Coverage - - | File Path | Coverage Percentage | Line Coverage | - |-------------------------------|----------------------|-------------------| - | src/main/file1.kt | 45.00% | 90/200 lines | - | src/main/file2.kt | 50.50% | 101/200 lines | - | src/main/really_long_file_name.kt | 60.00% | 120/200 lines | - -
- Success Coverage - - | File Path | Coverage Percentage | Line Coverage |Status - |-------------------------------|:----------------------:|-------------------|:------:| - | src/main/file3.kt | 85.00% | 170/200 lines |:white_check_mark:| - | src/main/file4.kt | 90.50% | 181/200 lines |:white_check_mark:| - | src/main/file5.kt | 95.00% | 190/200 lines |:x:| - -
- - */ - val markdownContent = "|$filePath" + + val markdownContent = "|${getFilenameAsLink(filePath)}" + "|$formattedCoveragePercentage%" + "|$totalLinesHit / $totalLinesFound" - println("\n$markdownContent") - return Pair(computedCoverageRatio, markdownContent) } @@ -278,11 +207,9 @@ class CoverageReporter( } private fun computeCoverageRatio(): Float { - return if (coverageReport.linesFound != 0) { - coverageReport.linesHit.toFloat() / coverageReport.linesFound.toFloat() - } else { - 0f - } + return coverageReport.linesFound.takeIf { it != 0 }?.let { + coverageReport.linesHit.toFloat() / it.toFloat() + } ?: 0f } private fun logCoverageReport() { @@ -303,6 +230,12 @@ class CoverageReporter( } } +private fun getFilenameAsLink(filePath: String): String { + val filename = filePath.substringAfterLast("/").trim() + val filenameAsLink = "[$filename](https://github.com/oppia/oppia-android/tree/develop/$filePath)" + return filenameAsLink +} + /** Represents the different types of formats available to generate code coverage reports. */ enum class ReportFormat { /** Indicates that the report should be formatted in .md format. */ diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt index 17a44e2aaf1..cb5e284651a 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -3,7 +3,6 @@ package org.oppia.android.scripts.coverage import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.async -import kotlinx.coroutines.delay import org.oppia.android.scripts.common.BazelClient import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher @@ -14,7 +13,6 @@ import java.io.File import java.nio.file.Files import java.nio.file.Paths import java.security.MessageDigest -import java.time.LocalDateTime /** * Class responsible for running coverage analysis asynchronously. @@ -40,12 +38,9 @@ class CoverageRunner( bazelTestTarget: String ): Deferred { return CoroutineScope(scriptBgDispatcher).async { -// println("$bazelTestTarget start: ${LocalDateTime.now()} on thread: ${Thread.currentThread().name}") val coverageResult = retrieveCoverageResult(bazelTestTarget) ?: return@async generateFailedCoverageReport() -// println("$bazelTestTarget end: ${LocalDateTime.now()} on thread: ${Thread.currentThread().name}") - coverageDataFileLines(coverageResult, bazelTestTarget) } } diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt index b35872f55d3..7fd2eb1ae1d 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -38,7 +38,7 @@ import java.util.concurrent.TimeUnit fun main(vararg args: String) { val repoRoot = args[0] val filePath = args[1] - println("FilePath = $filePath") + println("File Path: $filePath") //TODO: once the file list is received (git client), it need to be filtered to just have // .kt files and also not Test.kt files @@ -48,8 +48,6 @@ fun main(vararg args: String) { "utility/src/main/java/org/oppia/android/util/math/NumericExpressionEvaluator.kt", "utility/src/main/java/org/oppia/android/util/math/MathTokenizer.kt", "utility/src/main/java/org/oppia/android/util/math/RealExtensions.kt", -// "utility/src/main/java/org/oppia/android/util/logging/ConsoleLogger.kt", -// "domain/src/main/java/org/oppia/android/domain/auth/FirebaseAuthWrapperImpl.kt" ) val format = args.find { it.startsWith("format=", ignoreCase = true) } @@ -57,7 +55,7 @@ fun main(vararg args: String) { ?.uppercase() ?: "MARKDOWN" val reportFormat = when (format) { - // TODO: (default to HTML) as it would be much simpler for local development + // TODO: (default to HTML) as that would be much simpler for local development "HTML" -> ReportFormat.HTML "MARKDOWN" -> ReportFormat.MARKDOWN else -> throw IllegalArgumentException("Unsupported report format: $format") @@ -115,7 +113,7 @@ class RunCoverage( .associateBy { it.exemptedFilePath } } - private val MIN_THRESHOLD = 10 // Example threshold, yet to be decided on a value + private val MIN_THRESHOLD = 10 // TODO: (to be decided) min threshold, yet to be decided on a value private var coverageCheckState = CoverageCheck.PASS /** @@ -135,7 +133,6 @@ class RunCoverage( if (reportFormat == ReportFormat.MARKDOWN) generateFinalMdReport(coverageResults) -// println("Coverage Results: $coverageResults") println("\nCOVERAGE ANALYSIS COMPLETED.") } @@ -162,8 +159,8 @@ class RunCoverage( val coverageReports = deferredCoverageReports.awaitAll() - // Check if the coverage reports are successfully generated else return failure message. // TODO: (yet to decide) if this too needs to be set as coverage state -> FAIL. + // Check if the coverage reports are successfully generated else return failure message. coverageReports.firstOrNull()?.let { if (!it.isGenerated) { return "Failed to generate coverage report for the file: $filePath.".also { @@ -176,16 +173,15 @@ class RunCoverage( val reporter = CoverageReporter(repoRoot, aggregatedCoverageReport, reportFormat) var (computedCoverageRatio, reportText) = reporter.generateRichTextReport() - val coverageCheckThreshold = exemption?.overrideMinCoveragePercentRequired ?: MIN_THRESHOLD + val coverageCheckThreshold = exemption?.overrideMinCoveragePercentRequired + ?: MIN_THRESHOLD -// println("**************************Coverage threshold : $coverageCheckThreshold") if (computedCoverageRatio*100 < coverageCheckThreshold) { coverageCheckState = CoverageCheck.FAIL reportText += "|:x:|" } else { reportText += "|:white_check_mark:|" } -// println("***************Coverage check state: $coverageCheckState") File(reportOutputPath).apply { parentFile?.mkdirs() @@ -200,65 +196,49 @@ class RunCoverage( } } - private enum class CoverageCheck { - PASS, - FAIL - } -} - -private fun generateFinalMdReport(coverageResults: List) { - /*val coverageTableHeader = "| Covered File | Percentage | Line Coverage | Status |\n" + - "|--------------|------------|---------------|--------|\n" - - println("Coverage table header: $coverageTableHeader") - - *//*val coverageFailures = coverageResults.map { result -> - result.split("|").fil{it} - }*//* - println(coverageResults[0].split("|")[4]) - println("Coverage Failures: $coverageResults")*/ - - val coverageTableHeader = "| Covered File | Percentage | Line Coverage | Status |\n" + - "|--------------|------------|---------------|--------|\n" + private fun generateFinalMdReport(coverageResults: List) { + val coverageTableHeader = "| Covered File | Percentage | Line Coverage | Status |\n" + + "|--------------|------------|---------------|--------|\n" - val coverageFailures = coverageResults.filter { result -> - result.contains("|") && result.split("|")[4].trim() == ":x:" - } - - val coverageSuccesses = coverageResults.filter { result -> - result.contains("|") && result.split("|")[4].trim() == ":white_check_mark:" - } + val coverageFailures = coverageResults.filter { result -> + result.contains("|") && result.split("|")[4].trim() == ":x:" + } - val exemptedCases = coverageResults.filterNot { it.contains("|") } + val coverageSuccesses = coverageResults.filter { result -> + result.contains("|") && result.split("|")[4].trim() == ":white_check_mark:" + } - val coverageFailuresRows = coverageFailures.joinToString(separator = "\n") - val coverageSuccessesRows = coverageSuccesses.joinToString(separator = "\n") + val anamolyCases = coverageResults.filterNot { it.contains("|") } - val failureMarkdownTable = "## Coverage Report\n\n" + - "Total covered files: ${coverageResults.size}\n" + - "Coverage Status: FAIL\n" + - "Min Coverage Required: 10%\n\n" + // make use of MIN_THRESHOLD - coverageTableHeader + - coverageFailuresRows + val coverageFailuresRows = coverageFailures.joinToString(separator = "\n") + val coverageSuccessesRows = coverageSuccesses.joinToString(separator = "\n") - val successMarkdownTable = "
\n" + - "Succeeded Coverages\n\n" + - coverageTableHeader + - coverageSuccessesRows + - "\n
" + val failureMarkdownTable = "## Coverage Report\n\n" + + "- Total covered files: ${coverageResults.size}\n" + + "- Coverage Status: **$coverageCheckState**\n" + + "- Min Coverage Required: $MIN_THRESHOLD%\n\n" + + coverageTableHeader + + coverageFailuresRows - val exemptedCasesList = exemptedCases.joinToString(separator = "\n") { "- $it" } + val successMarkdownTable = "
\n" + + "Succeeded Coverages
\n\n" + + coverageTableHeader + + coverageSuccessesRows + + "\n
" - val finalReportText = failureMarkdownTable + "\n\n" + successMarkdownTable + "\n\n" + "### Exempted Cases\n" + exemptedCasesList -/* + val anamolyCasesList = anamolyCases.joinToString(separator = "\n") { "- $it" } + val finalReportText = failureMarkdownTable + + "\n\n" + successMarkdownTable + + "\n\n" + "### Anamoly Cases\n" + + anamolyCasesList - println(""" - ## Coverage Report - $coverageResults - """.trimIndent()) -*/ + println(finalReportText) + } - println(finalReportText) + private enum class CoverageCheck { + PASS, + FAIL + } } private fun calculateAggregateCoverageReport(