Skip to content

Commit

Permalink
Introduced coverage.proto and parsed the coverage data and store them…
Browse files Browse the repository at this point in the history
… to the proto
  • Loading branch information
Rd4dev committed Jun 21, 2024
1 parent 87d34ad commit 0735c64
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ kt_jvm_library(
visibility = ["//scripts:oppia_script_binary_visibility"],
deps = [
"//scripts/src/java/org/oppia/android/scripts/common:bazel_client",
"//scripts/src/java/org/oppia/android/scripts/proto:coverage_java_proto",
],
)
135 changes: 135 additions & 0 deletions scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package org.oppia.android.scripts.coverage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import org.oppia.android.scripts.proto.CoverageReport
import org.oppia.android.scripts.proto.CoveredFile
import org.oppia.android.scripts.proto.CoveredLine
import org.oppia.android.scripts.proto.BranchCoverage
import org.oppia.android.scripts.proto.FunctionCoverage
import org.oppia.android.scripts.common.BazelClient
import org.oppia.android.scripts.common.CommandExecutor
import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher
Expand Down Expand Up @@ -33,6 +38,12 @@ class CoverageRunner(
): Deferred<List<String>?> {
return CoroutineScope(scriptBgDispatcher).async {
val coverageDataFilePath = retrieveCoverageResult(bazelTestTarget)

val coverageReport = coverageDataFilePath?.let {
parseCoverageData(it, bazelTestTarget)
}
println("Coverage Report: $coverageReport")

coverageDataFilePath
}
}
Expand All @@ -48,4 +59,128 @@ class CoverageRunner(
): List<String>? {
return bazelClient.runCoverageForTestTarget(bazelTestTarget)
}

private fun parseCoverageData(coverageData: List<String>, bazelTestTarget: String): CoverageReport {
var filePath = ""
var linesFound = 0
var linesHit = 0
val coveredLines = mutableListOf<CoveredLine>()
val branchCoverage = mutableListOf<BranchCoverage>()
val functionCoverage = mutableListOf<FunctionCoverage>()

var functionsFound = 0
var functionsHit = 0
var branchesFound = 0
var branchesHit = 0

coverageData.forEach { line ->
when {
// SF:<absolute path to the source file>
line.startsWith("SF:") -> {
filePath = line.substringAfter("SF:")
}
// DA:<line number>,<execution count>
line.startsWith("DA:") -> {
val parts = line.substringAfter("DA:").split(",")
val lineNumber = parts[0].toInt()
val hitCount = parts[1].toInt()
val coverage = if (hitCount > 0) CoveredLine.Coverage.FULL else CoveredLine.Coverage.NONE
coveredLines.add(
CoveredLine.newBuilder()
.setLineNumber(lineNumber)
.setCoverage(coverage)
.build()
)
}
// BRDA:<line number>,<block number>,<branch number>,<taken>
line.startsWith("BRDA:") -> {
val parts = line.substringAfter("BRDA:").split(",")
val lineNumber = parts[0].toInt()
val blockNumber = parts[1].toInt()
val branchNumber = parts[2].toInt()
val hitCount = parts[3].toInt()
val coverage = if (hitCount > 0) BranchCoverage.Coverage.FULL else BranchCoverage.Coverage.NONE
branchCoverage.add(
BranchCoverage.newBuilder()
.setLineNumber(lineNumber)
.setBlockNumber(blockNumber)
.setBranchNumber(branchNumber)
.setCoverage(coverage)
.build()
)
}
// FN:<line number of function start>,<function name>
line.startsWith("FN:") -> {
val parts = line.substringAfter("FN:").split(",")
val currentFunctionLineNumber = parts[0].toInt()
val functionName = parts[1]
functionCoverage.add(
FunctionCoverage.newBuilder()
.setLineNumber(currentFunctionLineNumber)
.setFunctionName(functionName)
.setExecutionCount(0)
.setCoverage(FunctionCoverage.Coverage.NONE)
.build()
)
}
// FNDA:<execution count>,<function name>
line.startsWith("FNDA:") -> {
val parts = line.substringAfter("FNDA:").split(",")
val executionCount = parts[0].toInt()
val functionName = parts[1]
val index = functionCoverage.indexOfFirst { it.functionName == functionName }
if (index != -1) {
val updatedFunctionCoverage = functionCoverage[index].toBuilder()
.setExecutionCount(executionCount)
.setCoverage(if (executionCount > 0) FunctionCoverage.Coverage.FULL else FunctionCoverage.Coverage.NONE)
.build()
functionCoverage[index] = updatedFunctionCoverage
}
}
// FNF:<number of functions found>
line.startsWith("FNF:") -> {
functionsFound = line.substringAfter("FNF:").toInt()
}
// FNH:<number of function hit>
line.startsWith("FNH:") -> {
functionsHit = line.substringAfter("FNH:").toInt()
}
// BRF:<number of branches found>
line.startsWith("BRF:") -> {
branchesFound = line.substringAfter("BRF:").toInt()
}
// BRH:<number of branches hit>
line.startsWith("BRH:") -> {
branchesHit = line.substringAfter("BRH:").toInt()
}
// LF:<number of instrumented lines>
line.startsWith("LF:") -> {
linesFound = line.substringAfter("LF:").toInt()
}
// LH:<number of lines with a non-zero execution count>
line.startsWith("LH:") -> {
linesHit = line.substringAfter("LH:").toInt()
}
}
}

val coveredFile = CoveredFile.newBuilder()
.setFilePath(filePath)
.addAllCoveredLine(coveredLines)
.addAllBranchCoverage(branchCoverage)
.addAllFunctionCoverage(functionCoverage)
.setFunctionsFound(functionsFound)
.setFunctionsHit(functionsHit)
.setBranchesFound(branchesFound)
.setBranchesHit(branchesHit)
.setLinesFound(linesFound)
.setLinesHit(linesHit)
.build()

return CoverageReport.newBuilder()
.setBazelTestTarget(bazelTestTarget)
.addCoveredFile(coveredFile)
.build()
}

}
11 changes: 11 additions & 0 deletions scripts/src/java/org/oppia/android/scripts/proto/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ java_proto_library(
deps = [":affected_tests_proto"],
)

oppia_proto_library(
name = "coverage_proto",
srcs = ["coverage.proto"],
)

java_proto_library(
name = "coverage_java_proto",
visibility = ["//scripts:oppia_script_library_visibility"],
deps = [":coverage_proto"],
)

oppia_proto_library(
name = "filename_pattern_validation_checks_proto",
srcs = ["filename_pattern_validation_checks.proto"],
Expand Down
62 changes: 62 additions & 0 deletions scripts/src/java/org/oppia/android/scripts/proto/coverage.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
syntax = "proto3";

package proto;

option java_package = "org.oppia.android.scripts.proto";
option java_multiple_files = true;

message CoverageReport {
string bazel_test_target = 1;
repeated CoveredFile covered_file = 2;
}

message CoveredFile {
string file_path = 1;
string file_sha1_hash = 2;
repeated CoveredLine covered_line = 3;
optional int32 lines_found = 4;
optional int32 lines_hit = 5;
repeated FunctionCoverage function_coverage = 6;
optional int32 functions_found = 7;
optional int32 functions_hit = 8;
repeated BranchCoverage branch_coverage = 9;
optional int32 branches_found = 10;
optional int32 branches_hit = 11;
}

message CoveredLine {
int32 line_number = 1;
CoveredLine.Coverage coverage = 2;

enum Coverage {
UNSPECIFIED = 0;
FULL = 1;
NONE = 2;
}
}

message BranchCoverage {
int32 line_number = 1;
optional int32 block_number = 2;
optional int32 branch_number = 3;
BranchCoverage.Coverage coverage = 4;

enum Coverage {
UNSPECIFIED = 0;
FULL = 1;
NONE = 2;
}
}

message FunctionCoverage {
int32 line_number = 1;
string function_name = 2;
optional int32 execution_count = 3;
FunctionCoverage.Coverage coverage = 4;

enum Coverage {
UNSPECIFIED = 0;
FULL = 1;
NONE = 2;
}
}

0 comments on commit 0735c64

Please sign in to comment.