From 6ec35a75d2dfcd22439f0e722820332b1552ae02 Mon Sep 17 00:00:00 2001 From: Rd Date: Tue, 4 Jun 2024 14:11:09 +0530 Subject: [PATCH 001/105] Fix lint new line and kdoc checks --- .../org/oppia/android/scripts/coverage/BUILD.bazel | 14 ++++++++++++++ .../scripts/coverage/RunCoverageForTestTarget.kt | 10 ++++++++++ 2 files changed, 24 insertions(+) create mode 100644 scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel create mode 100644 scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel new file mode 100644 index 00000000000..88cebeac1d7 --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -0,0 +1,14 @@ +load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "run_coverage_for_test_target_lib", + testonly = True, + srcs = [ + "RunCoverageForTestTarget.kt", + ], + visibility = ["//scripts:oppia_script_binary_visibility"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", + "//scripts/src/java/org/oppia/android/scripts/common:git_client", + ], +) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt new file mode 100644 index 00000000000..99544e09c7d --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -0,0 +1,10 @@ +package org.oppia.android.scripts.coverage + +/** + * Entry point function for running coverage analysis for a single test target. + * + * @param args Command-line arguments. + */ +fun main(vararg args: String) { + println("Running coverage for test target: ${args[0]}") +} From 1ec224a6a960feb840f1e15ac0083d4423dd12cb Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 5 Jun 2024 13:34:54 +0530 Subject: [PATCH 002/105] Execute Bazel Command to run coverage on the test target --- .../android/scripts/common/BazelClient.kt | 13 ++++ .../android/scripts/coverage/BUILD.bazel | 14 ++++ .../scripts/coverage/CoverageRunner.kt | 71 +++++++++++++++++++ .../coverage/RunCoverageForTestTarget.kt | 41 ++++++++++- 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 9aede2fd16f..706adbba03c 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -130,6 +130,19 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return correctedTargets } + /** + * Runs code coverage for the specified Bazel test target. + * + * @param bazelTestTarget Bazel test target for which code coverage will be run. + * @return generated coverageResult output + */ + fun runCoverageForTestTarget(bazelTestTarget: String): List { + return executeBazelCommand( + "coverage", + bazelTestTarget + ) + } + /** * Returns the results of a query command with a potentially large list of [values] that will be * split up into multiple commands to avoid overflow the system's maximum argument limit. diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 88cebeac1d7..924011c5225 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -7,6 +7,20 @@ kt_jvm_library( "RunCoverageForTestTarget.kt", ], visibility = ["//scripts:oppia_script_binary_visibility"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", + "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", + "//scripts/src/java/org/oppia/android/scripts/common:git_client", + ], +) + +kt_jvm_library( + name = "coverage_runner", + testonly = True, + srcs = [ + "CoverageRunner.kt", + ], + visibility = ["//scripts:oppia_script_binary_visibility"], deps = [ "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", "//scripts/src/java/org/oppia/android/scripts/common:git_client", diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt new file mode 100644 index 00000000000..6ed50cb9c93 --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -0,0 +1,71 @@ +package org.oppia.android.scripts.coverage + +import org.oppia.android.scripts.common.BazelClient +import org.oppia.android.scripts.common.CommandExecutor +import org.oppia.android.scripts.common.CommandExecutorImpl +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.async +import kotlinx.coroutines.Deferred +import java.io.File + +class CoverageRunner { + fun runWithCoverageAsync( + repoRoot: File, + scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, + bazelTestTarget: String + ): Deferred { + return CoroutineScope(scriptBgDispatcher).async { + val coverageData = getCoverage(repoRoot, scriptBgDispatcher, bazelTestTarget) + val data = coverageData.await() + parseData(data) + } + } + + fun getCoverage( + repoRoot: File, + scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, + bazelTestTarget: String + ): Deferred> { + return CoroutineScope(scriptBgDispatcher).async { + val commandExecutor: CommandExecutor = CommandExecutorImpl(scriptBgDispatcher) + val bazelClient = BazelClient(repoRoot, commandExecutor) + val coverageData = bazelClient.runCoverageForTestTarget(bazelTestTarget) + coverageData + } + } + + fun parseData(data: List) { + // Implementation to parse the coverage data file path String + println("Parsed Data: $data") + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index 99544e09c7d..c8e18813b43 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -1,10 +1,49 @@ package org.oppia.android.scripts.coverage +import org.oppia.android.scripts.coverage.CoverageRunner +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import kotlinx.coroutines.runBlocking +import java.io.File + /** * Entry point function for running coverage analysis for a single test target. * * @param args Command-line arguments. */ fun main(vararg args: String) { - println("Running coverage for test target: ${args[0]}") + val repoRoot = File(args[0]).absoluteFile.normalize() + val targetPath = args[1] + + RunCoverageForTestTarget().runCoverage(repoRoot, targetPath) +} + +/** + * Class responsible for analyzing target files for coverage and generating reports. + */ +class RunCoverageForTestTarget() { + + /** + * Analyzes target file for coverage, generates chosen reports accordingly. + * + * @param targetFile Path to the file to analyze. + * @param outputFormats Output formats for the coverage reports. + * @throws IllegalStateException if computed coverage is below min required. + */ + fun runCoverage(repoRoot: File, targetPath: String) { + runWithCoverageAnalysis(repoRoot, targetPath) + } + + /** + * Runs coverage analysis on the specified target file asynchronously. + * + * @param targetFile Path to the target file to analyze coverage. + * @return A deferred result representing the coverage report. + */ + fun runWithCoverageAnalysis(repoRoot: File, targetPath: String) { + ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> + runBlocking { + CoverageRunner().runWithCoverageAsync(repoRoot, scriptBgDispatcher, targetPath).await() + } + } + } } From ee92168a6589a963145444ae40f3aeefc92f7436 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 5 Jun 2024 15:59:47 +0530 Subject: [PATCH 003/105] Parse the coverage execution result to acquire the generated coverage data file path --- .../scripts/coverage/CoverageRunner.kt | 75 ++++++++++--------- .../coverage/RunCoverageForTestTarget.kt | 6 +- 2 files changed, 43 insertions(+), 38 deletions(-) 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 6ed50cb9c93..ffd286b160c 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -9,19 +9,39 @@ import kotlinx.coroutines.async import kotlinx.coroutines.Deferred import java.io.File +/** + * Class responsible for running coverage analysis asynchronously. + */ class CoverageRunner { - fun runWithCoverageAsync( + + /** + * Runs coverage analysis asynchronously for the Bazel test target. + * + * @param repoRoot the absolute path to the working root directory + * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command + * @param bazelTestTarget Bazel test target to analyze coverage. + * @return a deferred value that contains the path of the coverage data file [will contain the proto for the coverage data]. + */ + suspend fun runWithCoverageAsync( repoRoot: File, scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, bazelTestTarget: String - ): Deferred { + ): Deferred { return CoroutineScope(scriptBgDispatcher).async { val coverageData = getCoverage(repoRoot, scriptBgDispatcher, bazelTestTarget) val data = coverageData.await() - parseData(data) + parseCoverageDataFile(data) } } + /** + * Runs coverage command for the Bazel test target. + * + * @param repoRoot the absolute path to the working root directory + * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command + * @param bazelTestTarget Bazel test target to analyze coverage. + * @return a deferred value that contains the result of the coverage execution. + */ fun getCoverage( repoRoot: File, scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, @@ -35,37 +55,22 @@ class CoverageRunner { } } - fun parseData(data: List) { - // Implementation to parse the coverage data file path String - println("Parsed Data: $data") + /** + * Parse the coverage command result to extract the path of the coverage data file. + * + * @param data the result from the execution of the coverage command + * @return the extracted path of the coverage data file. + */ + fun parseCoverageDataFile(data: List) : String? { + val regex = ".*coverage\\.dat$".toRegex() + for (line in data) { + val match = regex.find(line) + val extractedPath = match?.value?.substringAfterLast(",")?.trim() + if (extractedPath != null) { + println("Parsed Coverage Data File: $extractedPath") + return extractedPath + } + } + return null } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index c8e18813b43..f57d798c4d1 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -25,9 +25,8 @@ class RunCoverageForTestTarget() { /** * Analyzes target file for coverage, generates chosen reports accordingly. * + * @param repoRoot the absolute path to the working root directory * @param targetFile Path to the file to analyze. - * @param outputFormats Output formats for the coverage reports. - * @throws IllegalStateException if computed coverage is below min required. */ fun runCoverage(repoRoot: File, targetPath: String) { runWithCoverageAnalysis(repoRoot, targetPath) @@ -36,8 +35,9 @@ class RunCoverageForTestTarget() { /** * Runs coverage analysis on the specified target file asynchronously. * + * @param repoRoot the absolute path to the working root directory * @param targetFile Path to the target file to analyze coverage. - * @return A deferred result representing the coverage report. + * @return [A deferred result representing the coverage report]. */ fun runWithCoverageAnalysis(repoRoot: File, targetPath: String) { ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> From 075c77c5ef18a0f746ee2845f7f62ef52e21b784 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 7 Jun 2024 13:53:25 +0530 Subject: [PATCH 004/105] Implemented functionality to TestBazelWorkspace utility to add source file content and its related test content in the provided subpackage --- .../scripts/testing/TestBazelWorkspace.kt | 118 ++++++++++++++++++ .../android/scripts/common/BazelClientTest.kt | 44 +++++++ 2 files changed, 162 insertions(+) diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 7c57cf0d10c..0c7fb58ed20 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -50,6 +50,124 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { assertThat(bazelRcFile.exists()).isTrue() } + /** + * Adds a source file with the specified name and content to the specified subpackage, + * and updates the corresponding build configuration. + * + * @param filename the name of the source file (without the .kt extension) + * @param sourceContent the content of the source file + * @param subpackage the subpackage under which the source file should be added + * @return the target name of the added source file + */ + fun addSourceContentAndBuildFile( + filename: String, + sourceContent: String, + sourceSubpackage: String + ): String { + initEmptyWorkspace() // Ensure the workspace is at least initialized. + + // Create the source subpackage directory if it doesn't exist + if (!File(temporaryRootFolder.root, sourceSubpackage.replace(".", "/")).exists()) { + temporaryRootFolder.newFolder(*(sourceSubpackage.split(".")).toTypedArray()) + } + + // Create the source file + val sourceFile = temporaryRootFolder.newFile("${sourceSubpackage.replace(".", "/")}/$filename.kt") + sourceFile.writeText(sourceContent) + + // Create or update the BUILD file for the source file + val buildFileRelativePath = "${sourceSubpackage.replace(".", "/")}/BUILD.bazel" + val buildFile = File(temporaryRootFolder.root, buildFileRelativePath) + if (!buildFile.exists()) { + temporaryRootFolder.newFile(buildFileRelativePath) + } + + prepareBuildFileForLibraries(buildFile) + + val libTargetName = "${sourceSubpackage}:${filename}_lib" + buildFile.appendText( + """" + kt_jvm_library( + name = "${filename}_lib", + srcs=["$filename}.kt"], + ) + """.trimIndent() + "\n" + ) + return libTargetName + } + + /** + * Adds a test file with the specified name and content to the specified subpackage, + * and updates the corresponding build configuration. + * + * @param testName the name of the test file (without the .kt extension) + * @param testContent the content of the test file + * @param libTargetName the target name of the library the test depends on + * @param testSubpackage the subpackage for the test file + */ + fun addTestContentAndBuildFile( + testName: String, + testContent: String, + libTargetName: String, + testSubpackage: String + ) { + initEmptyWorkspace() // Ensure the workspace is at least initialized. + + // Create the test subpackage directory for the test file if it doesn't exist + if (!File(temporaryRootFolder.root, testSubpackage.replace(".", "/")).exists()) { + temporaryRootFolder.newFolder(*(testSubpackage.split(".")).toTypedArray()) + } + + // Create the test file + val testFile = temporaryRootFolder.newFile("${testSubpackage.replace(".", "/")}/$testName.kt") + testFile.writeText(testContent) + + // Create or update the BUILD file for the test file + val testBuildFileRelativePath = "${testSubpackage.replace(".", "/")}/BUILD.bazel" + val testBuildFile = File(temporaryRootFolder.root, testBuildFileRelativePath) + if (!testBuildFile.exists()) { + temporaryRootFolder.newFile(testBuildFileRelativePath) + } + prepareBuildFileForTests(testBuildFile) + + // Add the test file to the BUILD file with appropriate dependencies + testBuildFile.appendText( + """ + kt_jvm_test( + name = "$testName", + srcs = ["${testName}.kt"], + deps = [ + "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + "$libTargetName", + ], + ) + """.trimIndent() + "\n" + ) + } + + /** + * Adds a file with the specified name and content, along with its corresponding test file and + * test content, to the specified subpackage. Ensures the appropriate build configurations are created. + * + * @param filename the name of the source file (without the .kt extension) + * @param sourceContent the content of the source file + * @param testContent the content of the test file + * @param subpackage the subpackage for the source and test files + */ + fun addSourceFileAndItsTestFileWithContent( + filename: String, + sourceContent: String, + testContent: String, + subpackage: String, + ) { + val sourceSubpackage = "$subpackage/source" + val libTargetName = addSourceContentAndBuildFile(filename, sourceContent, sourceSubpackage) + + val testSubpackage = "$subpackage/test" + val testFileName = "${filename}Test" + addTestContentAndBuildFile(testFileName, testContent, libTargetName, testSubpackage) + } + /** * Generates and adds a new kt_jvm_test target with the target name [testName] and test file * [testFile]. This can be used to add multiple tests to the same build file, and will diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 3f451d354b8..3c764939468 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -379,6 +379,50 @@ class BazelClientTest { assertThat(thirdPartyDependenciesList).doesNotContain("@maven//:androidx_annotation_annotation") } + @Test + fun testRunCodeCoverageForATestTarget() { +// val bazelClient = BazelClient(tempFolder.root, commandExecutor) + testBazelWorkspace.initEmptyWorkspace() + testBazelWorkspace.createTest("FirstTest") + + + // Verify the test file is created + val testFile = File(tempFolder.root, "FirstTest.kt") + assertThat(testFile.exists()).isTrue() + assertThat(testFile.isFile).isTrue() + + val addsource = testBazelWorkspace.addSourceFileAndItsTestFileWithContent("test1", "Hi", "@Test", "cc") + println("Add Source result: $addsource") + + listFilesInDirectory(tempFolder.root) +// bazelClient.runCoverageForTestTarget("//utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest") + + // Verify the WORKSPACE file exists + val workspaceFile = File(tempFolder.root, "WORKSPACE") + assertThat(workspaceFile.exists()).isTrue() + assertThat(workspaceFile.isFile).isTrue() + + // Print the contents of the WORKSPACE file + println("\nContents of WORKSPACE file:") + println(workspaceFile.readText()) + + // Verify the BUILD.bazel file exists + val bazelFile = File(tempFolder.root, "BUILD.bazel") + assertThat(bazelFile.exists()).isTrue() + assertThat(bazelFile.isFile).isTrue() + + // Print the contents of the BUILD.bazel file + println("Contents of BUILD BAZEL file:") + println(bazelFile.readText()) + + } + + private fun listFilesInDirectory(directory: File) { + directory.walk().forEach { + println(it.relativeTo(directory)) + } + } + private fun fakeCommandExecutorWithResult(singleLine: String) { // Fake a Bazel command's results to return jumbled results. This has been observed to happen // sometimes in CI, but doesn't have a known cause. The utility is meant to de-jumble these in From d0519d684ec1d98c9793f54a8686618e01d1bd87 Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 9 Jun 2024 14:09:53 +0530 Subject: [PATCH 005/105] Sample Test data and Listing all contents --- .../android/scripts/common/BazelClient.kt | 37 ++++- .../scripts/common/CommandExecutorImpl.kt | 2 +- .../scripts/testing/TestBazelWorkspace.kt | 134 ++++++++++++++++- .../android/scripts/common/BazelClientTest.kt | 139 ++++++++++++++++-- 4 files changed, 295 insertions(+), 17 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 706adbba03c..cf198c10963 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -136,11 +136,44 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * @param bazelTestTarget Bazel test target for which code coverage will be run. * @return generated coverageResult output */ - fun runCoverageForTestTarget(bazelTestTarget: String): List { - return executeBazelCommand( +// fun runCoverageForTestTarget(bazelTestTarget: String): List { + fun runCoverageForTestTarget(bazelTestTarget: String): String? { + /*return executeBazelCommand( + "coverage", + bazelTestTarget + )*/ + val result = executeBazelCommand( "coverage", bazelTestTarget ) + + println("Coverage data from exe: $result") + val filedata = parseCoverageDataFile(result) + + println("Coverage data path from exe: $filedata") + val file = File(filedata) + + if (file.exists() && file.isFile) { + val contents = file.readText() + println(contents) + } else { + println("File does not exist or is not a valid file: $filedata") + } + + return filedata + } + + fun parseCoverageDataFile(data: List) : String? { + val regex = ".*coverage\\.dat$".toRegex() + for (line in data) { + val match = regex.find(line) + val extractedPath = match?.value?.substringAfterLast(",")?.trim() + if (extractedPath != null) { + println("Parsed Coverage Data File: $extractedPath") + return extractedPath + } + } + return null } /** diff --git a/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt b/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt index 01476cbf3cd..05a90b02110 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt @@ -20,7 +20,7 @@ import java.util.concurrent.TimeUnit * The default amount of time that should be waited before considering a process as 'hung', in * milliseconds. */ -const val WAIT_PROCESS_TIMEOUT_MS = 60_000L +const val WAIT_PROCESS_TIMEOUT_MS = 600_000L /** Default implementation of [CommandExecutor]. */ class CommandExecutorImpl( diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 0c7fb58ed20..b489f708b8f 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -50,6 +50,97 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { assertThat(bazelRcFile.exists()).isTrue() } + fun addSampleSourceAndTestFile( + filename: String, + sourceContent: String, + testContent: String, + subpackage: String + ) { + val sourceSubpackage = "$subpackage/main/java/com/example" + addSampleSourceContentAndBuildFile(filename, sourceContent, sourceSubpackage) + + val testSubpackage = "$subpackage/test/java/com/example" + val testFileName = "Test${filename}" + addSampleTestContentAndBuildFile(testFileName, testContent, testSubpackage) + } + + fun addSampleSourceContentAndBuildFile( + filename: String, + sourceContent: String, + sourceSubpackage: String + ) { + initEmptyWorkspace() + + // Create the source subpackage directory if it doesn't exist + if (!File(temporaryRootFolder.root, sourceSubpackage.replace(".", "/")).exists()) { + temporaryRootFolder.newFolder(*(sourceSubpackage.split(".")).toTypedArray()) + } + + // Create the source file + val sourceFile = temporaryRootFolder.newFile("${sourceSubpackage.replace(".", "/")}/$filename.java") + sourceFile.writeText(sourceContent) + + // Create or update the BUILD file for the source file + val buildFileRelativePath = "${sourceSubpackage.replace(".", "/")}/BUILD.bazel" + val buildFile = File(temporaryRootFolder.root, buildFileRelativePath) + if (!buildFile.exists()) { + temporaryRootFolder.newFile(buildFileRelativePath) + } + + //prepareBuildFileForLibraries(buildFile) + + //val libTargetName = "//${sourceSubpackage}:${filename}_lib" + buildFile.appendText( + """ + package( + default_visibility = ["//visibility:public"], + ) + + java_library( + name = "collatz_lib", + srcs=["Collatz.java"], + ) + """.trimIndent() + "\n" + ) + } + + fun addSampleTestContentAndBuildFile( + testName: String, + testContent: String, + testSubpackage: String + ) { + initEmptyWorkspace() + + // Create the test subpackage directory for the test file if it doesn't exist + if (!File(temporaryRootFolder.root, testSubpackage.replace(".", "/")).exists()) { + temporaryRootFolder.newFolder(*(testSubpackage.split(".")).toTypedArray()) + } + + // Create the test file + val testFile = temporaryRootFolder.newFile("${testSubpackage.replace(".", "/")}/$testName.java") + testFile.writeText(testContent) + + // Create or update the BUILD file for the test file + val testBuildFileRelativePath = "${testSubpackage.replace(".", "/")}/BUILD.bazel" + val testBuildFile = File(temporaryRootFolder.root, testBuildFileRelativePath) + if (!testBuildFile.exists()) { + temporaryRootFolder.newFile(testBuildFileRelativePath) + } + //prepareBuildFileForTests(testBuildFile) + + // Add the test file to the BUILD file with appropriate dependencies + testBuildFile.appendText( + """ + java_test( + name = "test", + srcs = ["TestCollatz.java"], + test_class = "com.example.TestCollatz", + deps = ["//coverage/main/java/com/example:collatz_lib"], + ) + """.trimIndent() + "\n" + ) + } + /** * Adds a source file with the specified name and content to the specified subpackage, * and updates the corresponding build configuration. @@ -65,6 +156,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { sourceSubpackage: String ): String { initEmptyWorkspace() // Ensure the workspace is at least initialized. + ensureWorkspaceIsConfiguredForKotlin() // Create the source subpackage directory if it doesn't exist if (!File(temporaryRootFolder.root, sourceSubpackage.replace(".", "/")).exists()) { @@ -84,9 +176,9 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { prepareBuildFileForLibraries(buildFile) - val libTargetName = "${sourceSubpackage}:${filename}_lib" + val libTargetName = "//${sourceSubpackage}:${filename}_lib" buildFile.appendText( - """" + """ kt_jvm_library( name = "${filename}_lib", srcs=["$filename}.kt"], @@ -112,6 +204,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { testSubpackage: String ) { initEmptyWorkspace() // Ensure the workspace is at least initialized. + ensureWorkspaceIsConfiguredForKotlin() // Create the test subpackage directory for the test file if it doesn't exist if (!File(temporaryRootFolder.root, testSubpackage.replace(".", "/")).exists()) { @@ -137,7 +230,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { name = "$testName", srcs = ["${testName}.kt"], deps = [ - "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + "@maven//:junit_junit", "$libTargetName", ], ) @@ -145,6 +238,39 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { ) } + fun setupGeneralCoverageBuildFile( + sourceLibTargetName: String, + testTargetName: String, + coverageSubpackage: String + ) { + initEmptyWorkspace() // Ensure the workspace is at least initialized. + ensureWorkspaceIsConfiguredForKotlin() // Ensure Kotlin rules are set up. + + // Create the coverage subpackage directory if it doesn't exist + if (!File(temporaryRootFolder.root, coverageSubpackage.replace(".", "/")).exists()) { + temporaryRootFolder.newFolder(*(coverageSubpackage.split(".")).toTypedArray()) + } + + // Create or update the BUILD file for the coverage package + val coverageBuildFileRelativePath = "${coverageSubpackage.replace(".", "/")}/BUILD.bazel" + val coverageBuildFile = File(temporaryRootFolder.root, coverageBuildFileRelativePath) + if (!coverageBuildFile.exists()) { + temporaryRootFolder.newFile(coverageBuildFileRelativePath) + } + + coverageBuildFile.appendText( + """ + kt_jvm_binary( + name = "coverage_runner", + srcs = ["//${coverageSubpackage.replace(".", "/")}:$testTargetName"], + deps = [ + "$sourceLibTargetName", + ], + ) + """.trimIndent() + "\n" + ) + } + /** * Adds a file with the specified name and content, along with its corresponding test file and * test content, to the specified subpackage. Ensures the appropriate build configurations are created. @@ -166,6 +292,8 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { val testSubpackage = "$subpackage/test" val testFileName = "${filename}Test" addTestContentAndBuildFile(testFileName, testContent, libTargetName, testSubpackage) + + setupGeneralCoverageBuildFile(libTargetName, testFileName, subpackage) } /** diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 3c764939468..32cbf21f084 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -379,23 +379,63 @@ class BazelClientTest { assertThat(thirdPartyDependenciesList).doesNotContain("@maven//:androidx_annotation_annotation") } - @Test + /*@Test fun testRunCodeCoverageForATestTarget() { -// val bazelClient = BazelClient(tempFolder.root, commandExecutor) + val bazelClient = BazelClient(tempFolder.root, commandExecutor) testBazelWorkspace.initEmptyWorkspace() - testBazelWorkspace.createTest("FirstTest") + //testBazelWorkspace.createTest("FirstTest") + // Verify the test file is created + *//*val testFile = File(tempFolder.root, "FirstTest.kt") + assertThat(testFile.exists()).isTrue() + assertThat(testFile.isFile).isTrue()*//* + + val sourceContent = """ + class SumTwoNumbers { + fun add(a: Int, b: Int): Int = a + b + } + """.trimIndent() + + val testContent = """ + import org.junit.Test + import com.google.common.truth.Truth.assertThat + + class SumTwoNumbersTest { + @Test + fun addTwoNumbers() { + val sumTwoNumbers = SumTwoNumbers() + assertThat(sumTwoNumbers.add(2, 3)).isEqualTo(5) + } + } + """.trimIndent() + + testBazelWorkspace.addSourceFileAndItsTestFileWithContent( + filename = "SumTwoNumbers", + sourceContent = sourceContent, + testContent = testContent, + subpackage = "coverage" + ) + + // Verify the source file is created + val sourceFile = File(tempFolder.root, "coverage/source/SumTwoNumbers.kt") + assertThat(sourceFile.exists()).isTrue() + assertThat(sourceFile.isFile).isTrue() + assertThat(sourceFile.readText()).isEqualTo(sourceContent) // Verify the test file is created - val testFile = File(tempFolder.root, "FirstTest.kt") + val testFile = File(tempFolder.root, "coverage/test/SumTwoNumbersTest.kt") assertThat(testFile.exists()).isTrue() assertThat(testFile.isFile).isTrue() + assertThat(testFile.readText()).isEqualTo(testContent) + + // Optionally, list all files and their contents for verification + println("Workspace directory structure and file contents:") + listFilesAndContents(tempFolder.root) - val addsource = testBazelWorkspace.addSourceFileAndItsTestFileWithContent("test1", "Hi", "@Test", "cc") - println("Add Source result: $addsource") + bazelClient.runCoverageForTestTarget("coverage/test:SumTwoNumbersTest") - listFilesInDirectory(tempFolder.root) -// bazelClient.runCoverageForTestTarget("//utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest") + *//*listFilesInDirectory(tempFolder.root) + //bazelClient.runCoverageForTestTarget("//utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest") // Verify the WORKSPACE file exists val workspaceFile = File(tempFolder.root, "WORKSPACE") @@ -406,15 +446,92 @@ class BazelClientTest { println("\nContents of WORKSPACE file:") println(workspaceFile.readText()) + // Verify the test file exists + val realtedTestFile = File(tempFolder.root, "/cc/source/test1.kt") + assertThat(realtedTestFile.exists()).isTrue() + assertThat(realtedTestFile.isFile).isTrue() + + // Print the contents of the test.bazel file + println("Contents of test file:") + println(realtedTestFile.readText()) + // Verify the BUILD.bazel file exists - val bazelFile = File(tempFolder.root, "BUILD.bazel") + val bazelFile = File(tempFolder.root, "/cc/test/BUILD.bazel") assertThat(bazelFile.exists()).isTrue() assertThat(bazelFile.isFile).isTrue() // Print the contents of the BUILD.bazel file - println("Contents of BUILD BAZEL file:") - println(bazelFile.readText()) + println("\nContents of BUILD BAZEL file:") + println(bazelFile.readText())*//* + }*/ + + @Test + fun testRunCodeCoverageForATestTarget() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = """ + package com.example; + + public class Collatz { + + public static int getCollatzFinal(int n) { + if (n == 1) { + return 1; + } + if (n % 2 == 0) { + return getCollatzFinal(n / 2); + } else { + return getCollatzFinal(n * 3 + 1); + } + } + } + """.trimIndent() + + val testContent = """ + package com.example; + + import static org.junit.Assert.assertEquals; + import org.junit.Test; + + public class TestCollatz { + + @Test + public void testGetCollatzFinal() { + assertEquals(Collatz.getCollatzFinal(1), 1); + assertEquals(Collatz.getCollatzFinal(5), 1); + assertEquals(Collatz.getCollatzFinal(10), 1); + assertEquals(Collatz.getCollatzFinal(21), 1); + } + } + """.trimIndent() + + testBazelWorkspace.addSampleSourceAndTestFile( + filename = "Collatz", + sourceContent = sourceContent, + testContent = testContent, + subpackage = "coverage" + ) + listFilesAndContents(tempFolder.root) + + println("Temp dir: ${tempFolder}") + println("Temp root: ${tempFolder.root}") + println("Temp root: ${tempFolder.root}") + + val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test") + println("Result: $result") + } + + private fun listFilesAndContents(directory: File) { + directory.walk().forEach { file -> + if (file.isFile) { + println("File: ${file.relativeTo(directory)}") + println("Contents:\n${file.readText()}\n") + } else if (file.isDirectory) { + println("Directory: ${file.relativeTo(directory)}") + } + } } private fun listFilesInDirectory(directory: File) { From b15b7bbdfcb78f959614da5af838b13781f84061 Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 9 Jun 2024 17:11:49 +0530 Subject: [PATCH 006/105] Added Test for BazelClient - for sample target and non target executions --- .../android/scripts/common/BazelClient.kt | 37 +-------- .../android/scripts/common/BazelClientTest.kt | 81 ++++++++++++++++++- 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index cf198c10963..706adbba03c 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -136,44 +136,11 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * @param bazelTestTarget Bazel test target for which code coverage will be run. * @return generated coverageResult output */ -// fun runCoverageForTestTarget(bazelTestTarget: String): List { - fun runCoverageForTestTarget(bazelTestTarget: String): String? { - /*return executeBazelCommand( - "coverage", - bazelTestTarget - )*/ - val result = executeBazelCommand( + fun runCoverageForTestTarget(bazelTestTarget: String): List { + return executeBazelCommand( "coverage", bazelTestTarget ) - - println("Coverage data from exe: $result") - val filedata = parseCoverageDataFile(result) - - println("Coverage data path from exe: $filedata") - val file = File(filedata) - - if (file.exists() && file.isFile) { - val contents = file.readText() - println(contents) - } else { - println("File does not exist or is not a valid file: $filedata") - } - - return filedata - } - - fun parseCoverageDataFile(data: List) : String? { - val regex = ".*coverage\\.dat$".toRegex() - for (line in data) { - val match = regex.find(line) - val extractedPath = match?.value?.substringAfterLast(",")?.trim() - if (extractedPath != null) { - println("Parsed Coverage Data File: $extractedPath") - return extractedPath - } - } - return null } /** diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 32cbf21f084..7394fbf8d1a 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -16,6 +16,12 @@ import org.oppia.android.testing.mockito.anyOrNull import java.io.File import java.util.concurrent.TimeUnit + + + + + + /** * Tests for [BazelClient]. * @@ -519,10 +525,83 @@ class BazelClientTest { println("Temp root: ${tempFolder.root}") println("Temp root: ${tempFolder.root}") - val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test") + val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test2") println("Result: $result") } + @Test + fun testRunCodeCoverage_forSampleTestTarget_returnsCoverageResult() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = """ + package com.example; + + public class Collatz { + + public static int getCollatzFinal(int n) { + if (n == 1) { + return 1; + } + if (n % 2 == 0) { + return getCollatzFinal(n / 2); + } else { + return getCollatzFinal(n * 3 + 1); + } + } + } + """.trimIndent() + + val testContent = """ + package com.example; + + import static org.junit.Assert.assertEquals; + import org.junit.Test; + + public class TestCollatz { + + @Test + public void testGetCollatzFinal() { + assertEquals(Collatz.getCollatzFinal(1), 1); + assertEquals(Collatz.getCollatzFinal(5), 1); + assertEquals(Collatz.getCollatzFinal(10), 1); + assertEquals(Collatz.getCollatzFinal(21), 1); + } + } + """.trimIndent() + + testBazelWorkspace.addSampleSourceAndTestFile( + filename = "Collatz", + sourceContent = sourceContent, + testContent = testContent, + subpackage = "coverage" + ) + + val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test") + + // Check that the test has "PASSED" + val containsPassedValue = result.any { it.contains("PASSED") } + assert(containsPassedValue) { "The test is not 'PASSED'" } + + // Check if the coverage.dat file is generated + val containsCoverageData = result.any { it.contains("coverage.dat") } + assert(containsCoverageData) { "The coverage.dat is not generated" } + } + + @Test + fun testRunCodeCoverage_forNonTestTarget_fails() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + testBazelWorkspace.initEmptyWorkspace() + + val exception = assertThrows() { + bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test") + } + + // Verify that the underlying Bazel command failed since the test target was not available. + assertThat(exception).hasMessageThat().contains("Expected non-zero exit code") + assertThat(exception).hasMessageThat().contains("no such package") + } + private fun listFilesAndContents(directory: File) { directory.walk().forEach { file -> if (file.isFile) { From f441d11c88dac123fdba7370acf9aabc15dc504c Mon Sep 17 00:00:00 2001 From: Rd Date: Tue, 11 Jun 2024 00:46:15 +0530 Subject: [PATCH 007/105] Added Coverage Runner functionality tests --- .../scripts/coverage/CoverageRunner.kt | 22 ++- .../coverage/RunCoverageForTestTarget.kt | 15 +- .../android/scripts/coverage/BUILD.bazel | 17 +++ .../scripts/coverage/CoverageRunnerTest.kt | 138 ++++++++++++++++++ 4 files changed, 174 insertions(+), 18 deletions(-) create mode 100644 scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel create mode 100644 scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt 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 ffd286b160c..79623f6472b 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -7,12 +7,16 @@ import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async import kotlinx.coroutines.Deferred +import kotlinx.coroutines.withContext import java.io.File /** * Class responsible for running coverage analysis asynchronously. */ -class CoverageRunner { +class CoverageRunner( + private val repoRoot: File, + private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher + ) { /** * Runs coverage analysis asynchronously for the Bazel test target. @@ -23,13 +27,11 @@ class CoverageRunner { * @return a deferred value that contains the path of the coverage data file [will contain the proto for the coverage data]. */ suspend fun runWithCoverageAsync( - repoRoot: File, - scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, bazelTestTarget: String ): Deferred { return CoroutineScope(scriptBgDispatcher).async { - val coverageData = getCoverage(repoRoot, scriptBgDispatcher, bazelTestTarget) - val data = coverageData.await() + val coverageData = getCoverage(bazelTestTarget) + val data = coverageData parseCoverageDataFile(data) } } @@ -40,19 +42,15 @@ class CoverageRunner { * @param repoRoot the absolute path to the working root directory * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command * @param bazelTestTarget Bazel test target to analyze coverage. - * @return a deferred value that contains the result of the coverage execution. + * @return a lisf of string that contains the result of the coverage execution. */ fun getCoverage( - repoRoot: File, - scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, bazelTestTarget: String - ): Deferred> { - return CoroutineScope(scriptBgDispatcher).async { + ): List { val commandExecutor: CommandExecutor = CommandExecutorImpl(scriptBgDispatcher) val bazelClient = BazelClient(repoRoot, commandExecutor) val coverageData = bazelClient.runCoverageForTestTarget(bazelTestTarget) - coverageData - } + return coverageData } /** diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index f57d798c4d1..51dc65a7031 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -14,13 +14,16 @@ fun main(vararg args: String) { val repoRoot = File(args[0]).absoluteFile.normalize() val targetPath = args[1] - RunCoverageForTestTarget().runCoverage(repoRoot, targetPath) + RunCoverageForTestTarget(repoRoot, targetPath).runCoverage() } /** * Class responsible for analyzing target files for coverage and generating reports. */ -class RunCoverageForTestTarget() { +class RunCoverageForTestTarget( + private val repoRoot: File, + private val targetPath : String +) { /** * Analyzes target file for coverage, generates chosen reports accordingly. @@ -28,8 +31,8 @@ class RunCoverageForTestTarget() { * @param repoRoot the absolute path to the working root directory * @param targetFile Path to the file to analyze. */ - fun runCoverage(repoRoot: File, targetPath: String) { - runWithCoverageAnalysis(repoRoot, targetPath) + fun runCoverage() { + runWithCoverageAnalysis() } /** @@ -39,10 +42,10 @@ class RunCoverageForTestTarget() { * @param targetFile Path to the target file to analyze coverage. * @return [A deferred result representing the coverage report]. */ - fun runWithCoverageAnalysis(repoRoot: File, targetPath: String) { + fun runWithCoverageAnalysis() { ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> runBlocking { - CoverageRunner().runWithCoverageAsync(repoRoot, scriptBgDispatcher, targetPath).await() + CoverageRunner(repoRoot, scriptBgDispatcher).runWithCoverageAsync(targetPath).await() } } } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel new file mode 100644 index 00000000000..f2e5c80564b --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel @@ -0,0 +1,17 @@ +""" +Tests corresponding to developer scripts that help with obtaining coverage data for test targets. +""" + +load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") + +kt_jvm_test( + name = "CoverageRunnerTest", + srcs = ["CoverageRunnerTest.kt"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", + "//scripts/src/java/org/oppia/android/scripts/testing:test_bazel_workspace", + "//testing:assertion_helpers", + "//third_party:com_google_truth_truth", + "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + ], +) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt new file mode 100644 index 00000000000..52ba07a6fe9 --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -0,0 +1,138 @@ +package org.oppia.android.scripts.coverage + +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.testing.assertThrows +import org.oppia.android.scripts.testing.TestBazelWorkspace +import kotlin.test.assertEquals +import java.io.File + +class CoverageRunnerTest { + @field:[Rule JvmField] val tempFolder = TemporaryFolder() + + private val scriptBgDispatcher by lazy { ScriptBackgroundCoroutineDispatcher() } + + private lateinit var coverageRunner: CoverageRunner + private lateinit var testBazelWorkspace: TestBazelWorkspace + private lateinit var bazelTestTarget: String + + @Before + fun setUp() { + coverageRunner = CoverageRunner(tempFolder.root, scriptBgDispatcher) + bazelTestTarget = "//:testTarget" + testBazelWorkspace = TestBazelWorkspace(tempFolder) + } + + @After + fun tearDown() { + scriptBgDispatcher.close() + } + + @Test + fun testParseCoverageDataFile_invalidData_returnsNull() { + // Result data from coverage execution that doesn't contain path to coverage data file [coverage.dat] + val invalidResultData = listOf("data1", "data2", "data3") + + val parsedData = coverageRunner.parseCoverageDataFile(invalidResultData) + // Return Null when the coverage data file path is not found + assertThat(parsedData).isNull() + } + + @Test + fun testParseCoverageDataFile_validData_returnsNull() { + // Result data from coverage execution that contains path to coverage data file [coverage.dat] + val validResultData = listOf( + "//package/test/example:test PASSED in 0.4s", + "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat", + "Executed 1 out of 1 test: 1 test passes." + ) + val expectedResultParsedData = "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat" + + val parsedData = coverageRunner.parseCoverageDataFile(validResultData) + assertThat(parsedData).isEqualTo(expectedResultParsedData) + } + + @Test + fun testRunCoverage_emptyDirectory_throwsException() { + val exception = assertThrows() { + coverageRunner.getCoverage(bazelTestTarget) + } + + assertThat(exception).hasMessageThat().contains("not invoked from within a workspace") + } + + @Test + fun testRunCoverage_invalidTestTarget_throwsException() { + testBazelWorkspace.initEmptyWorkspace() + + val exception = assertThrows() { + coverageRunner.getCoverage(bazelTestTarget) + } + + assertThat(exception).hasMessageThat().contains("Expected non-zero exit code") + assertThat(exception).hasMessageThat().contains("no such package") + } + + @Test + fun testRunCoverage_validSampleTestTarget_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = """ + package com.example; + + public class Collatz { + + public static int getCollatzFinal(int n) { + if (n == 1) { + return 1; + } + if (n % 2 == 0) { + return getCollatzFinal(n / 2); + } else { + return getCollatzFinal(n * 3 + 1); + } + } + } + """.trimIndent() + + val testContent = """ + package com.example; + + import static org.junit.Assert.assertEquals; + import org.junit.Test; + + public class TestCollatz { + + @Test + public void testGetCollatzFinal() { + assertEquals(Collatz.getCollatzFinal(1), 1); + assertEquals(Collatz.getCollatzFinal(5), 1); + assertEquals(Collatz.getCollatzFinal(10), 1); + assertEquals(Collatz.getCollatzFinal(21), 1); + } + } + """.trimIndent() + + testBazelWorkspace.addSampleSourceAndTestFile( + filename = "Collatz", + sourceContent = sourceContent, + testContent = testContent, + subpackage = "coverage" + ) + + val result = coverageRunner.getCoverage("//coverage/test/java/com/example:test") + + // Check that the test has "PASSED" + val containsPassedValue = result.any { it.contains("PASSED") } + assert(containsPassedValue) { "The test is not 'PASSED'" } + + // Check if the coverage.dat file is generated + val containsCoverageData = result.any { it.contains("coverage.dat") } + assert(containsCoverageData) { "The coverage.dat is not generated" } + } +} From cc863091746f2071a6a33d63565f9bde9bb4afb7 Mon Sep 17 00:00:00 2001 From: Rd Date: Tue, 11 Jun 2024 22:17:18 +0530 Subject: [PATCH 008/105] Added tests for the RunCoverageForTestTarget utility --- .../scripts/coverage/CoverageRunner.kt | 3 + .../coverage/RunCoverageForTestTarget.kt | 30 +++-- .../android/scripts/coverage/BUILD.bazel | 12 ++ .../scripts/coverage/CoverageRunnerTest.kt | 1 + .../coverage/RunCoverageForTestTargetTest.kt | 116 ++++++++++++++++++ 5 files changed, 150 insertions(+), 12 deletions(-) create mode 100644 scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt 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 79623f6472b..3210ae4c978 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -12,6 +12,9 @@ import java.io.File /** * Class responsible for running coverage analysis asynchronously. + * + * @param repoRoot the absolute path to the working root directory + * @param targetFile Path to the target file to analyze coverage. */ class CoverageRunner( private val repoRoot: File, diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index 51dc65a7031..07477fa1a48 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -8,7 +8,16 @@ import java.io.File /** * Entry point function for running coverage analysis for a single test target. * - * @param args Command-line arguments. + * Usage: + * bazel run //scripts:run_coverage_for_test_target -- + * + * Arguments: + * - path_to_root: directory path to the root of the Oppia Android repository. + * - test_targetname: bazel target name of the test + * + * Example: + * bazel run //scripts:run_coverage_for_test_target -- $(pwd) + * //utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest */ fun main(vararg args: String) { val repoRoot = File(args[0]).absoluteFile.normalize() @@ -27,25 +36,22 @@ class RunCoverageForTestTarget( /** * Analyzes target file for coverage, generates chosen reports accordingly. - * - * @param repoRoot the absolute path to the working root directory - * @param targetFile Path to the file to analyze. */ - fun runCoverage() { - runWithCoverageAnalysis() + fun runCoverage(): String? { + return runWithCoverageAnalysis() } /** * Runs coverage analysis on the specified target file asynchronously. * - * @param repoRoot the absolute path to the working root directory - * @param targetFile Path to the target file to analyze coverage. - * @return [A deferred result representing the coverage report]. + * @return [Path of the coverage data file]. */ - fun runWithCoverageAnalysis() { - ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> + fun runWithCoverageAnalysis(): String? { + return ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> runBlocking { - CoverageRunner(repoRoot, scriptBgDispatcher).runWithCoverageAsync(targetPath).await() + val result = + CoverageRunner(repoRoot, scriptBgDispatcher).runWithCoverageAsync(targetPath).await() + result } } } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel index f2e5c80564b..cb20129dd61 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel @@ -15,3 +15,15 @@ kt_jvm_test( "//third_party:org_jetbrains_kotlin_kotlin-test-junit", ], ) + +kt_jvm_test( + name = "RunCoverageForTestTargetTest", + srcs = ["RunCoverageForTestTargetTest.kt"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", + "//scripts/src/java/org/oppia/android/scripts/testing:test_bazel_workspace", + "//testing:assertion_helpers", + "//third_party:com_google_truth_truth", + "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + ], +) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 52ba07a6fe9..d88d3d5e03b 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -12,6 +12,7 @@ import org.oppia.android.scripts.testing.TestBazelWorkspace import kotlin.test.assertEquals import java.io.File +/** Tests for [CoverageRunner] */ class CoverageRunnerTest { @field:[Rule JvmField] val tempFolder = TemporaryFolder() diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt new file mode 100644 index 00000000000..c2c1a9d47ef --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -0,0 +1,116 @@ +package org.oppia.android.scripts.coverage + +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.scripts.testing.TestBazelWorkspace +import org.oppia.android.testing.assertThrows + +/** Tests for [RunCoverageForTestTarget] */ +class RunCoverageForTestTargetTest { + @field:[Rule JvmField] val tempFolder = TemporaryFolder() + + private val scriptBgDispatcher by lazy { ScriptBackgroundCoroutineDispatcher() } + + private lateinit var testBazelWorkspace: TestBazelWorkspace + private lateinit var bazelTestTarget: String + + @Before + fun setUp() { + bazelTestTarget = "//:testTarget" + testBazelWorkspace = TestBazelWorkspace(tempFolder) + } + + @After + fun tearDown() { + scriptBgDispatcher.close() + } + + @Test + fun testRunCoverageForTestTarget_emptyDirectory_throwsException() { + val exception = assertThrows() { + RunCoverageForTestTarget( + tempFolder.root, + bazelTestTarget + ).runCoverage() + } + + assertThat(exception).hasMessageThat().contains("not invoked from within a workspace") + } + + @Test + fun testRunCoverageForTestTarget_invalidTestTarget_throwsException() { + testBazelWorkspace.initEmptyWorkspace() + + val exception = assertThrows() { + RunCoverageForTestTarget( + tempFolder.root, + bazelTestTarget + ).runCoverage() + } + + assertThat(exception).hasMessageThat().contains("Expected non-zero exit code") + assertThat(exception).hasMessageThat().contains("no such package") + } + + @Test + fun testRunCoverageForTestTarget_validSampleTestTarget_returnsCoverageDataPath() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = """ + package com.example; + + public class Collatz { + + public static int getCollatzFinal(int n) { + if (n == 1) { + return 1; + } + if (n % 2 == 0) { + return getCollatzFinal(n / 2); + } else { + return getCollatzFinal(n * 3 + 1); + } + } + } + """.trimIndent() + + val testContent = """ + package com.example; + + import static org.junit.Assert.assertEquals; + import org.junit.Test; + + public class TestCollatz { + + @Test + public void testGetCollatzFinal() { + assertEquals(Collatz.getCollatzFinal(1), 1); + assertEquals(Collatz.getCollatzFinal(5), 1); + assertEquals(Collatz.getCollatzFinal(10), 1); + assertEquals(Collatz.getCollatzFinal(21), 1); + } + } + """.trimIndent() + + testBazelWorkspace.addSampleSourceAndTestFile( + filename = "Collatz", + sourceContent = sourceContent, + testContent = testContent, + subpackage = "coverage" + ) + + val result = RunCoverageForTestTarget( + tempFolder.root, + "//coverage/test/java/com/example:test" + ).runCoverage() + + // Check if the coverage.dat file is generated and parsed as result + val parsedCoverageDataPath = result?.endsWith("coverage.dat") + assert(parsedCoverageDataPath!!) { "The coverage.dat is not generated" } + } +} \ No newline at end of file From 4a6073b987d755f9b07b6e5b0d6c819e34fcab18 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 13 Jun 2024 09:45:46 +0530 Subject: [PATCH 009/105] Replaced Java Test Sources with Kotlin Sources --- .../scripts/testing/TestBazelWorkspace.kt | 188 +++------------ .../android/scripts/common/BazelClientTest.kt | 217 +++--------------- .../scripts/coverage/CoverageRunnerTest.kt | 56 +++-- .../coverage/RunCoverageForTestTargetTest.kt | 56 +++-- 4 files changed, 110 insertions(+), 407 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index b489f708b8f..14ceac6ed9c 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -50,95 +50,18 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { assertThat(bazelRcFile.exists()).isTrue() } - fun addSampleSourceAndTestFile( + fun addSourceAndTestFileWithContent( filename: String, sourceContent: String, testContent: String, subpackage: String ) { val sourceSubpackage = "$subpackage/main/java/com/example" - addSampleSourceContentAndBuildFile(filename, sourceContent, sourceSubpackage) + addSourceContentAndBuildFile(filename, sourceContent, sourceSubpackage) val testSubpackage = "$subpackage/test/java/com/example" - val testFileName = "Test${filename}" - addSampleTestContentAndBuildFile(testFileName, testContent, testSubpackage) - } - - fun addSampleSourceContentAndBuildFile( - filename: String, - sourceContent: String, - sourceSubpackage: String - ) { - initEmptyWorkspace() - - // Create the source subpackage directory if it doesn't exist - if (!File(temporaryRootFolder.root, sourceSubpackage.replace(".", "/")).exists()) { - temporaryRootFolder.newFolder(*(sourceSubpackage.split(".")).toTypedArray()) - } - - // Create the source file - val sourceFile = temporaryRootFolder.newFile("${sourceSubpackage.replace(".", "/")}/$filename.java") - sourceFile.writeText(sourceContent) - - // Create or update the BUILD file for the source file - val buildFileRelativePath = "${sourceSubpackage.replace(".", "/")}/BUILD.bazel" - val buildFile = File(temporaryRootFolder.root, buildFileRelativePath) - if (!buildFile.exists()) { - temporaryRootFolder.newFile(buildFileRelativePath) - } - - //prepareBuildFileForLibraries(buildFile) - - //val libTargetName = "//${sourceSubpackage}:${filename}_lib" - buildFile.appendText( - """ - package( - default_visibility = ["//visibility:public"], - ) - - java_library( - name = "collatz_lib", - srcs=["Collatz.java"], - ) - """.trimIndent() + "\n" - ) - } - - fun addSampleTestContentAndBuildFile( - testName: String, - testContent: String, - testSubpackage: String - ) { - initEmptyWorkspace() - - // Create the test subpackage directory for the test file if it doesn't exist - if (!File(temporaryRootFolder.root, testSubpackage.replace(".", "/")).exists()) { - temporaryRootFolder.newFolder(*(testSubpackage.split(".")).toTypedArray()) - } - - // Create the test file - val testFile = temporaryRootFolder.newFile("${testSubpackage.replace(".", "/")}/$testName.java") - testFile.writeText(testContent) - - // Create or update the BUILD file for the test file - val testBuildFileRelativePath = "${testSubpackage.replace(".", "/")}/BUILD.bazel" - val testBuildFile = File(temporaryRootFolder.root, testBuildFileRelativePath) - if (!testBuildFile.exists()) { - temporaryRootFolder.newFile(testBuildFileRelativePath) - } - //prepareBuildFileForTests(testBuildFile) - - // Add the test file to the BUILD file with appropriate dependencies - testBuildFile.appendText( - """ - java_test( - name = "test", - srcs = ["TestCollatz.java"], - test_class = "com.example.TestCollatz", - deps = ["//coverage/main/java/com/example:collatz_lib"], - ) - """.trimIndent() + "\n" - ) + val testFileName = "${filename}Test" + addTestContentAndBuildFile(filename, testFileName, testContent, testSubpackage) } /** @@ -147,16 +70,19 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { * * @param filename the name of the source file (without the .kt extension) * @param sourceContent the content of the source file - * @param subpackage the subpackage under which the source file should be added + * @param sourceSubpackage the subpackage under which the source file should be added * @return the target name of the added source file */ fun addSourceContentAndBuildFile( filename: String, sourceContent: String, sourceSubpackage: String - ): String { - initEmptyWorkspace() // Ensure the workspace is at least initialized. + ) { + initEmptyWorkspace() ensureWorkspaceIsConfiguredForKotlin() + setUpWorkspaceForRulesJvmExternal( + listOf("junit:junit:4.12") + ) // Create the source subpackage directory if it doesn't exist if (!File(temporaryRootFolder.root, sourceSubpackage.replace(".", "/")).exists()) { @@ -174,37 +100,36 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { temporaryRootFolder.newFile(buildFileRelativePath) } - prepareBuildFileForLibraries(buildFile) - - val libTargetName = "//${sourceSubpackage}:${filename}_lib" buildFile.appendText( """ + load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") + kt_jvm_library( - name = "${filename}_lib", - srcs=["$filename}.kt"], + name = "${filename.lowercase()}", + srcs = ["${filename}.kt"], + visibility = ["//visibility:public"], + deps = [], ) """.trimIndent() + "\n" ) - return libTargetName } /** * Adds a test file with the specified name and content to the specified subpackage, * and updates the corresponding build configuration. * + * @param filename the name of the source file (without the .kt extension) * @param testName the name of the test file (without the .kt extension) * @param testContent the content of the test file - * @param libTargetName the target name of the library the test depends on * @param testSubpackage the subpackage for the test file */ fun addTestContentAndBuildFile( + filename: String, testName: String, testContent: String, - libTargetName: String, testSubpackage: String ) { - initEmptyWorkspace() // Ensure the workspace is at least initialized. - ensureWorkspaceIsConfiguredForKotlin() + initEmptyWorkspace() // Create the test subpackage directory for the test file if it doesn't exist if (!File(temporaryRootFolder.root, testSubpackage.replace(".", "/")).exists()) { @@ -221,81 +146,26 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { if (!testBuildFile.exists()) { temporaryRootFolder.newFile(testBuildFileRelativePath) } - prepareBuildFileForTests(testBuildFile) // Add the test file to the BUILD file with appropriate dependencies testBuildFile.appendText( """ + load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") + kt_jvm_test( - name = "$testName", - srcs = ["${testName}.kt"], - deps = [ - "@maven//:junit_junit", - "$libTargetName", - ], + name = "test", + srcs = ["${testName}.kt"], + deps = [ + "//coverage/main/java/com/example:${filename.lowercase()}", + "@maven//:junit_junit", + ], + visibility = ["//visibility:public"], + test_class = "com.example.${testName}", ) """.trimIndent() + "\n" ) } - fun setupGeneralCoverageBuildFile( - sourceLibTargetName: String, - testTargetName: String, - coverageSubpackage: String - ) { - initEmptyWorkspace() // Ensure the workspace is at least initialized. - ensureWorkspaceIsConfiguredForKotlin() // Ensure Kotlin rules are set up. - - // Create the coverage subpackage directory if it doesn't exist - if (!File(temporaryRootFolder.root, coverageSubpackage.replace(".", "/")).exists()) { - temporaryRootFolder.newFolder(*(coverageSubpackage.split(".")).toTypedArray()) - } - - // Create or update the BUILD file for the coverage package - val coverageBuildFileRelativePath = "${coverageSubpackage.replace(".", "/")}/BUILD.bazel" - val coverageBuildFile = File(temporaryRootFolder.root, coverageBuildFileRelativePath) - if (!coverageBuildFile.exists()) { - temporaryRootFolder.newFile(coverageBuildFileRelativePath) - } - - coverageBuildFile.appendText( - """ - kt_jvm_binary( - name = "coverage_runner", - srcs = ["//${coverageSubpackage.replace(".", "/")}:$testTargetName"], - deps = [ - "$sourceLibTargetName", - ], - ) - """.trimIndent() + "\n" - ) - } - - /** - * Adds a file with the specified name and content, along with its corresponding test file and - * test content, to the specified subpackage. Ensures the appropriate build configurations are created. - * - * @param filename the name of the source file (without the .kt extension) - * @param sourceContent the content of the source file - * @param testContent the content of the test file - * @param subpackage the subpackage for the source and test files - */ - fun addSourceFileAndItsTestFileWithContent( - filename: String, - sourceContent: String, - testContent: String, - subpackage: String, - ) { - val sourceSubpackage = "$subpackage/source" - val libTargetName = addSourceContentAndBuildFile(filename, sourceContent, sourceSubpackage) - - val testSubpackage = "$subpackage/test" - val testFileName = "${filename}Test" - addTestContentAndBuildFile(testFileName, testContent, libTargetName, testSubpackage) - - setupGeneralCoverageBuildFile(libTargetName, testFileName, subpackage) - } - /** * Generates and adds a new kt_jvm_test target with the target name [testName] and test file * [testFile]. This can be used to add multiple tests to the same build file, and will diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 7394fbf8d1a..a6560782a06 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -385,193 +385,47 @@ class BazelClientTest { assertThat(thirdPartyDependenciesList).doesNotContain("@maven//:androidx_annotation_annotation") } - /*@Test - fun testRunCodeCoverageForATestTarget() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - testBazelWorkspace.initEmptyWorkspace() - //testBazelWorkspace.createTest("FirstTest") - - // Verify the test file is created - *//*val testFile = File(tempFolder.root, "FirstTest.kt") - assertThat(testFile.exists()).isTrue() - assertThat(testFile.isFile).isTrue()*//* - - val sourceContent = """ - class SumTwoNumbers { - fun add(a: Int, b: Int): Int = a + b - } - """.trimIndent() - - val testContent = """ - import org.junit.Test - import com.google.common.truth.Truth.assertThat - - class SumTwoNumbersTest { - @Test - fun addTwoNumbers() { - val sumTwoNumbers = SumTwoNumbers() - assertThat(sumTwoNumbers.add(2, 3)).isEqualTo(5) - } - } - """.trimIndent() - - testBazelWorkspace.addSourceFileAndItsTestFileWithContent( - filename = "SumTwoNumbers", - sourceContent = sourceContent, - testContent = testContent, - subpackage = "coverage" - ) - - // Verify the source file is created - val sourceFile = File(tempFolder.root, "coverage/source/SumTwoNumbers.kt") - assertThat(sourceFile.exists()).isTrue() - assertThat(sourceFile.isFile).isTrue() - assertThat(sourceFile.readText()).isEqualTo(sourceContent) - - // Verify the test file is created - val testFile = File(tempFolder.root, "coverage/test/SumTwoNumbersTest.kt") - assertThat(testFile.exists()).isTrue() - assertThat(testFile.isFile).isTrue() - assertThat(testFile.readText()).isEqualTo(testContent) - - // Optionally, list all files and their contents for verification - println("Workspace directory structure and file contents:") - listFilesAndContents(tempFolder.root) - - bazelClient.runCoverageForTestTarget("coverage/test:SumTwoNumbersTest") - - *//*listFilesInDirectory(tempFolder.root) - //bazelClient.runCoverageForTestTarget("//utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest") - - // Verify the WORKSPACE file exists - val workspaceFile = File(tempFolder.root, "WORKSPACE") - assertThat(workspaceFile.exists()).isTrue() - assertThat(workspaceFile.isFile).isTrue() - - // Print the contents of the WORKSPACE file - println("\nContents of WORKSPACE file:") - println(workspaceFile.readText()) - - // Verify the test file exists - val realtedTestFile = File(tempFolder.root, "/cc/source/test1.kt") - assertThat(realtedTestFile.exists()).isTrue() - assertThat(realtedTestFile.isFile).isTrue() - - // Print the contents of the test.bazel file - println("Contents of test file:") - println(realtedTestFile.readText()) - - // Verify the BUILD.bazel file exists - val bazelFile = File(tempFolder.root, "/cc/test/BUILD.bazel") - assertThat(bazelFile.exists()).isTrue() - assertThat(bazelFile.isFile).isTrue() - - // Print the contents of the BUILD.bazel file - println("\nContents of BUILD BAZEL file:") - println(bazelFile.readText())*//* - }*/ - - @Test - fun testRunCodeCoverageForATestTarget() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - testBazelWorkspace.initEmptyWorkspace() - - val sourceContent = """ - package com.example; - - public class Collatz { - - public static int getCollatzFinal(int n) { - if (n == 1) { - return 1; - } - if (n % 2 == 0) { - return getCollatzFinal(n / 2); - } else { - return getCollatzFinal(n * 3 + 1); - } - } - } - """.trimIndent() - - val testContent = """ - package com.example; - - import static org.junit.Assert.assertEquals; - import org.junit.Test; - - public class TestCollatz { - - @Test - public void testGetCollatzFinal() { - assertEquals(Collatz.getCollatzFinal(1), 1); - assertEquals(Collatz.getCollatzFinal(5), 1); - assertEquals(Collatz.getCollatzFinal(10), 1); - assertEquals(Collatz.getCollatzFinal(21), 1); - } - } - """.trimIndent() - - testBazelWorkspace.addSampleSourceAndTestFile( - filename = "Collatz", - sourceContent = sourceContent, - testContent = testContent, - subpackage = "coverage" - ) - - listFilesAndContents(tempFolder.root) - - println("Temp dir: ${tempFolder}") - println("Temp root: ${tempFolder.root}") - println("Temp root: ${tempFolder.root}") - - val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test2") - println("Result: $result") - } - @Test fun testRunCodeCoverage_forSampleTestTarget_returnsCoverageResult() { val bazelClient = BazelClient(tempFolder.root, commandExecutor) testBazelWorkspace.initEmptyWorkspace() val sourceContent = """ - package com.example; - - public class Collatz { - - public static int getCollatzFinal(int n) { - if (n == 1) { - return 1; - } - if (n % 2 == 0) { - return getCollatzFinal(n / 2); - } else { - return getCollatzFinal(n * 3 + 1); - } + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } } - } + } """.trimIndent() val testContent = """ - package com.example; - - import static org.junit.Assert.assertEquals; - import org.junit.Test; - - public class TestCollatz { - + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + @Test - public void testGetCollatzFinal() { - assertEquals(Collatz.getCollatzFinal(1), 1); - assertEquals(Collatz.getCollatzFinal(5), 1); - assertEquals(Collatz.getCollatzFinal(10), 1); - assertEquals(Collatz.getCollatzFinal(21), 1); + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") } - } + } """.trimIndent() - testBazelWorkspace.addSampleSourceAndTestFile( - filename = "Collatz", + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, subpackage = "coverage" @@ -602,23 +456,6 @@ class BazelClientTest { assertThat(exception).hasMessageThat().contains("no such package") } - private fun listFilesAndContents(directory: File) { - directory.walk().forEach { file -> - if (file.isFile) { - println("File: ${file.relativeTo(directory)}") - println("Contents:\n${file.readText()}\n") - } else if (file.isDirectory) { - println("Directory: ${file.relativeTo(directory)}") - } - } - } - - private fun listFilesInDirectory(directory: File) { - directory.walk().forEach { - println(it.relativeTo(directory)) - } - } - private fun fakeCommandExecutorWithResult(singleLine: String) { // Fake a Bazel command's results to return jumbled results. This has been observed to happen // sometimes in CI, but doesn't have a known cause. The utility is meant to de-jumble these in diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index d88d3d5e03b..083fb870bd4 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -84,43 +84,41 @@ class CoverageRunnerTest { testBazelWorkspace.initEmptyWorkspace() val sourceContent = """ - package com.example; - - public class Collatz { - - public static int getCollatzFinal(int n) { - if (n == 1) { - return 1; - } - if (n % 2 == 0) { - return getCollatzFinal(n / 2); - } else { - return getCollatzFinal(n * 3 + 1); - } + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } } - } + } """.trimIndent() val testContent = """ - package com.example; - - import static org.junit.Assert.assertEquals; - import org.junit.Test; - - public class TestCollatz { - + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + @Test - public void testGetCollatzFinal() { - assertEquals(Collatz.getCollatzFinal(1), 1); - assertEquals(Collatz.getCollatzFinal(5), 1); - assertEquals(Collatz.getCollatzFinal(10), 1); - assertEquals(Collatz.getCollatzFinal(21), 1); + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") } - } + } """.trimIndent() - testBazelWorkspace.addSampleSourceAndTestFile( - filename = "Collatz", + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, subpackage = "coverage" diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index c2c1a9d47ef..9c28fd9a4b2 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -62,43 +62,41 @@ class RunCoverageForTestTargetTest { testBazelWorkspace.initEmptyWorkspace() val sourceContent = """ - package com.example; - - public class Collatz { - - public static int getCollatzFinal(int n) { - if (n == 1) { - return 1; - } - if (n % 2 == 0) { - return getCollatzFinal(n / 2); - } else { - return getCollatzFinal(n * 3 + 1); - } + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } } - } + } """.trimIndent() val testContent = """ - package com.example; - - import static org.junit.Assert.assertEquals; - import org.junit.Test; - - public class TestCollatz { - + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + @Test - public void testGetCollatzFinal() { - assertEquals(Collatz.getCollatzFinal(1), 1); - assertEquals(Collatz.getCollatzFinal(5), 1); - assertEquals(Collatz.getCollatzFinal(10), 1); - assertEquals(Collatz.getCollatzFinal(21), 1); + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") } - } + } """.trimIndent() - testBazelWorkspace.addSampleSourceAndTestFile( - filename = "Collatz", + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, subpackage = "coverage" From 13534a1a80e44278c7fdeeb95e74c90c45cd8055 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 13 Jun 2024 11:13:58 +0530 Subject: [PATCH 010/105] Fix Static Checks / Lint warnings --- .../scripts/coverage/CoverageRunner.kt | 23 +++--- .../coverage/RunCoverageForTestTarget.kt | 5 +- .../scripts/testing/TestBazelWorkspace.kt | 19 ++++- .../android/scripts/common/BazelClientTest.kt | 74 +++++++++--------- .../scripts/coverage/CoverageRunnerTest.kt | 75 ++++++++++--------- .../coverage/RunCoverageForTestTargetTest.kt | 70 ++++++++--------- 6 files changed, 137 insertions(+), 129 deletions(-) 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 3210ae4c978..a88e4b6f0a5 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -1,13 +1,12 @@ package org.oppia.android.scripts.coverage +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async import org.oppia.android.scripts.common.BazelClient import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.async -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.withContext import java.io.File /** @@ -17,9 +16,9 @@ import java.io.File * @param targetFile Path to the target file to analyze coverage. */ class CoverageRunner( - private val repoRoot: File, - private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher - ) { + private val repoRoot: File, + private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher +) { /** * Runs coverage analysis asynchronously for the Bazel test target. @@ -50,10 +49,10 @@ class CoverageRunner( fun getCoverage( bazelTestTarget: String ): List { - val commandExecutor: CommandExecutor = CommandExecutorImpl(scriptBgDispatcher) - val bazelClient = BazelClient(repoRoot, commandExecutor) - val coverageData = bazelClient.runCoverageForTestTarget(bazelTestTarget) - return coverageData + val commandExecutor: CommandExecutor = CommandExecutorImpl(scriptBgDispatcher) + val bazelClient = BazelClient(repoRoot, commandExecutor) + val coverageData = bazelClient.runCoverageForTestTarget(bazelTestTarget) + return coverageData } /** @@ -62,7 +61,7 @@ class CoverageRunner( * @param data the result from the execution of the coverage command * @return the extracted path of the coverage data file. */ - fun parseCoverageDataFile(data: List) : String? { + fun parseCoverageDataFile(data: List): String? { val regex = ".*coverage\\.dat$".toRegex() for (line in data) { val match = regex.find(line) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index 07477fa1a48..9ddf3a04450 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -1,8 +1,7 @@ package org.oppia.android.scripts.coverage -import org.oppia.android.scripts.coverage.CoverageRunner -import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import kotlinx.coroutines.runBlocking +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import java.io.File /** @@ -31,7 +30,7 @@ fun main(vararg args: String) { */ class RunCoverageForTestTarget( private val repoRoot: File, - private val targetPath : String + private val targetPath: String ) { /** diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 14ceac6ed9c..30fde89364d 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -50,6 +50,15 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { assertThat(bazelRcFile.exists()).isTrue() } + /** + * Adds a source file and test file with the specified name and content, + * and updates the corresponding build configuration. + * + * @param filename the name of the source file (without the .kt extension) + * @param sourceContent the content of the source file + * @param testContent the content of the test file + * @param subpackage the subpackage under which the source and test files should be added + */ fun addSourceAndTestFileWithContent( filename: String, sourceContent: String, @@ -90,7 +99,9 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { } // Create the source file - val sourceFile = temporaryRootFolder.newFile("${sourceSubpackage.replace(".", "/")}/$filename.kt") + val sourceFile = temporaryRootFolder.newFile( + "${sourceSubpackage.replace(".", "/")}/$filename.kt" + ) sourceFile.writeText(sourceContent) // Create or update the BUILD file for the source file @@ -106,7 +117,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { kt_jvm_library( name = "${filename.lowercase()}", - srcs = ["${filename}.kt"], + srcs = ["$filename.kt"], visibility = ["//visibility:public"], deps = [], ) @@ -154,13 +165,13 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { kt_jvm_test( name = "test", - srcs = ["${testName}.kt"], + srcs = ["$testName.kt"], deps = [ "//coverage/main/java/com/example:${filename.lowercase()}", "@maven//:junit_junit", ], visibility = ["//visibility:public"], - test_class = "com.example.${testName}", + test_class = "com.example.$testName", ) """.trimIndent() + "\n" ) diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index a6560782a06..9740c1acc3d 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -16,12 +16,6 @@ import org.oppia.android.testing.mockito.anyOrNull import java.io.File import java.util.concurrent.TimeUnit - - - - - - /** * Tests for [BazelClient]. * @@ -390,39 +384,41 @@ class BazelClientTest { val bazelClient = BazelClient(tempFolder.root, commandExecutor) testBazelWorkspace.initEmptyWorkspace() - val sourceContent = """ - package com.example - - class TwoSum { - - companion object { - fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { - "Both numbers are zero" - } else { - a + b - } - } - } - } - """.trimIndent() - - val testContent = """ - package com.example - - import org.junit.Assert.assertEquals - import org.junit.Test - - class TwoSumTest { - - @Test - fun testSumNumbers() { - assertEquals(TwoSum.sumNumbers(0, 1), 1) - assertEquals(TwoSum.sumNumbers(3, 4), 7) - assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") - } - } - """.trimIndent() + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a == 0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 083fb870bd4..7d3ced9b557 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -7,10 +7,8 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.testing.assertThrows import org.oppia.android.scripts.testing.TestBazelWorkspace -import kotlin.test.assertEquals -import java.io.File +import org.oppia.android.testing.assertThrows /** Tests for [CoverageRunner] */ class CoverageRunnerTest { @@ -52,7 +50,8 @@ class CoverageRunnerTest { "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat", "Executed 1 out of 1 test: 1 test passes." ) - val expectedResultParsedData = "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat" + val expectedResultParsedData = + "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat" val parsedData = coverageRunner.parseCoverageDataFile(validResultData) assertThat(parsedData).isEqualTo(expectedResultParsedData) @@ -83,39 +82,41 @@ class CoverageRunnerTest { fun testRunCoverage_validSampleTestTarget_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() - val sourceContent = """ - package com.example - - class TwoSum { - - companion object { - fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { - "Both numbers are zero" - } else { - a + b - } - } - } - } - """.trimIndent() - - val testContent = """ - package com.example - - import org.junit.Assert.assertEquals - import org.junit.Test - - class TwoSumTest { - - @Test - fun testSumNumbers() { - assertEquals(TwoSum.sumNumbers(0, 1), 1) - assertEquals(TwoSum.sumNumbers(3, 4), 7) - assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") - } - } - """.trimIndent() + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index 9c28fd9a4b2..2c1d579168f 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -61,39 +61,41 @@ class RunCoverageForTestTargetTest { fun testRunCoverageForTestTarget_validSampleTestTarget_returnsCoverageDataPath() { testBazelWorkspace.initEmptyWorkspace() - val sourceContent = """ - package com.example - - class TwoSum { - - companion object { - fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { - "Both numbers are zero" - } else { - a + b - } - } - } - } - """.trimIndent() - - val testContent = """ - package com.example - - import org.junit.Assert.assertEquals - import org.junit.Test - - class TwoSumTest { - - @Test - fun testSumNumbers() { - assertEquals(TwoSum.sumNumbers(0, 1), 1) - assertEquals(TwoSum.sumNumbers(3, 4), 7) - assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") - } - } - """.trimIndent() + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", @@ -111,4 +113,4 @@ class RunCoverageForTestTargetTest { val parsedCoverageDataPath = result?.endsWith("coverage.dat") assert(parsedCoverageDataPath!!) { "The coverage.dat is not generated" } } -} \ No newline at end of file +} From fc52d82d76fc82902686cd20dccbc4fa21cac437 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 13 Jun 2024 11:31:27 +0530 Subject: [PATCH 011/105] Fix Buildifier Lint checks --- .../src/java/org/oppia/android/scripts/coverage/BUILD.bazel | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 924011c5225..53f09dbb98c 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -1,3 +1,7 @@ +""" +Libraries corresponding to developer scripts that obtain coverage data for test targets. +""" + load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") kt_jvm_library( @@ -8,9 +12,9 @@ kt_jvm_library( ], visibility = ["//scripts:oppia_script_binary_visibility"], deps = [ - "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", "//scripts/src/java/org/oppia/android/scripts/common:git_client", + "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", ], ) From 0226baa912692c2c7deac297fa90fd7d5d183396 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 13 Jun 2024 15:38:37 +0530 Subject: [PATCH 012/105] Added tests for TestBazelWorkspaceTest to check addition of source and test files with corresponding build configurations and content --- .../scripts/common/CommandExecutorImpl.kt | 2 +- .../scripts/coverage/CoverageRunner.kt | 5 +- .../scripts/testing/TestBazelWorkspace.kt | 14 +- .../android/scripts/common/BazelClientTest.kt | 5 + .../scripts/testing/TestBazelWorkspaceTest.kt | 132 ++++++++++++++++++ 5 files changed, 148 insertions(+), 10 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt b/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt index 05a90b02110..01476cbf3cd 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/CommandExecutorImpl.kt @@ -20,7 +20,7 @@ import java.util.concurrent.TimeUnit * The default amount of time that should be waited before considering a process as 'hung', in * milliseconds. */ -const val WAIT_PROCESS_TIMEOUT_MS = 600_000L +const val WAIT_PROCESS_TIMEOUT_MS = 60_000L /** Default implementation of [CommandExecutor]. */ class CommandExecutorImpl( 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 a88e4b6f0a5..1cee918a176 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -8,6 +8,7 @@ import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import java.io.File +import java.util.concurrent.TimeUnit /** * Class responsible for running coverage analysis asynchronously. @@ -49,7 +50,9 @@ class CoverageRunner( fun getCoverage( bazelTestTarget: String ): List { - val commandExecutor: CommandExecutor = CommandExecutorImpl(scriptBgDispatcher) + val commandExecutor: CommandExecutor = CommandExecutorImpl( + scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES + ) val bazelClient = BazelClient(repoRoot, commandExecutor) val coverageData = bazelClient.runCoverageForTestTarget(bazelTestTarget) return coverageData diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 30fde89364d..fb0e48cba50 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -70,7 +70,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { val testSubpackage = "$subpackage/test/java/com/example" val testFileName = "${filename}Test" - addTestContentAndBuildFile(filename, testFileName, testContent, testSubpackage) + addTestContentAndBuildFile(filename, testFileName, testContent, sourceSubpackage, testSubpackage) } /** @@ -110,16 +110,14 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { if (!buildFile.exists()) { temporaryRootFolder.newFile(buildFileRelativePath) } + prepareBuildFileForLibraries(buildFile) buildFile.appendText( """ - load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") - kt_jvm_library( name = "${filename.lowercase()}", srcs = ["$filename.kt"], - visibility = ["//visibility:public"], - deps = [], + visibility = ["//visibility:public"] ) """.trimIndent() + "\n" ) @@ -138,6 +136,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { filename: String, testName: String, testContent: String, + sourceSubpackage: String, testSubpackage: String ) { initEmptyWorkspace() @@ -157,17 +156,16 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { if (!testBuildFile.exists()) { temporaryRootFolder.newFile(testBuildFileRelativePath) } + prepareBuildFileForTests(testBuildFile) // Add the test file to the BUILD file with appropriate dependencies testBuildFile.appendText( """ - load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") - kt_jvm_test( name = "test", srcs = ["$testName.kt"], deps = [ - "//coverage/main/java/com/example:${filename.lowercase()}", + "//$sourceSubpackage:${filename.lowercase()}", "@maven//:junit_junit", ], visibility = ["//visibility:public"], diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 9740c1acc3d..be38e436ab2 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -381,6 +381,11 @@ class BazelClientTest { @Test fun testRunCodeCoverage_forSampleTestTarget_returnsCoverageResult() { + val commandExecutor = CommandExecutorImpl( + scriptBgDispatcher, + processTimeout = 5, + processTimeoutUnit = TimeUnit.MINUTES + ) val bazelClient = BazelClient(tempFolder.root, commandExecutor) testBazelWorkspace.initEmptyWorkspace() diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index 2ea2f42b1bf..2492ea6aa58 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -254,6 +254,138 @@ class TestBazelWorkspaceTest { assertThat(buildFile.length()).isNotEqualTo(originalLength) } + @Test + fun testAddSourceAndTestFileWithContent_createsSourceAndTestFiles() { + val testBazelWorkspace = TestBazelWorkspace(tempFolder) + val sourceContent = """ + fun main() { + println("Hello, World!") + } + """ + + val testContent = """ + import org.junit.Test + import kotlin.test.assertEquals + + class MainTest { + + @Test + fun testMain() { + assertEquals(1, 1) + } + } + """ + + testBazelWorkspace.addSourceAndTestFileWithContent("Main", sourceContent, testContent, "coverage") + + val sourceFile = File(tempFolder.root, "coverage/main/java/com/example/Main.kt") + val testFile = File(tempFolder.root, "coverage/test/java/com/example/MainTest.kt") + + assertThat(sourceFile.exists()).isTrue() + assertThat(sourceFile.readText()).isEqualTo(sourceContent) + + assertThat(testFile.exists()).isTrue() + assertThat(testFile.readText()).isEqualTo(testContent) + } + + @Test + fun testAddSourceAndTestFileWithContent_updatesBuildFiles() { + val testBazelWorkspace = TestBazelWorkspace(tempFolder) + val sourceContent = "fun main() { println(\"Hello, World!\") }" + val testContent = """ + import org.junit.Test + import kotlin.test.assertEquals + + class MainTest { + @Test + fun testMain() { + assertEquals(1, 1) + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent("Main", sourceContent, testContent, "coverage") + + val sourceBuildFile = File(tempFolder.root, "coverage/main/java/com/example/BUILD.bazel") + val testBuildFile = File(tempFolder.root, "coverage/test/java/com/example/BUILD.bazel") + + assertThat(sourceBuildFile.exists()).isTrue() + assertThat(sourceBuildFile.readText()).contains(""" + kt_jvm_library( + name = "main", + srcs = ["Main.kt"], + visibility = ["//visibility:public"] + ) + """.trimIndent()) + + assertThat(testBuildFile.exists()).isTrue() + assertThat(testBuildFile.readText()).contains(""" + load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") + kt_jvm_test( + name = "test", + srcs = ["MainTest.kt"], + deps = [ + "//coverage/main/java/com/example:main", + "@maven//:junit_junit", + ], + visibility = ["//visibility:public"], + test_class = "com.example.MainTest", + ) + """.trimIndent()) + } + + @Test + fun testAddSourceContentAndBuildFile_createsSourceFileAndBuildFile() { + val testBazelWorkspace = TestBazelWorkspace(tempFolder) + val sourceContent = "fun main() { println(\"Hello, World!\") }" + + testBazelWorkspace.addSourceContentAndBuildFile("Main", sourceContent, "coverage/main/java/com/example") + + val sourceFile = File(tempFolder.root, "coverage/main/java/com/example/Main.kt") + val buildFile = File(tempFolder.root, "coverage/main/java/com/example/BUILD.bazel") + + assertThat(sourceFile.exists()).isTrue() + assertThat(sourceFile.readText()).isEqualTo(sourceContent.trimIndent()) + + assertThat(buildFile.exists()).isTrue() + assertThat(buildFile.readText()).contains(""" + kt_jvm_library( + name = "main", + srcs = ["Main.kt"], + visibility = ["//visibility:public"] + ) + """.trimIndent()) + } + + @Test + fun testAddTestContentAndBuildFile_createsTestFileAndBuildFile() { + val testBazelWorkspace = TestBazelWorkspace(tempFolder) + val testContent = "import org.junit.Test\nimport kotlin.test.assertEquals\n\nclass MainTest {\n@Test\nfun testMain() {\nassertEquals(1, 1)\n}\n}" + + testBazelWorkspace.addTestContentAndBuildFile("Main", "MainTest", testContent, "coverage/main/java/com/example", "coverage/test/java/com/example") + + val testFile = File(tempFolder.root, "coverage/test/java/com/example/MainTest.kt") + val buildFile = File(tempFolder.root, "coverage/test/java/com/example/BUILD.bazel") + + assertThat(testFile.exists()).isTrue() + assertThat(testFile.readText()).isEqualTo(testContent.trimIndent()) + + assertThat(buildFile.exists()).isTrue() + assertThat(buildFile.readText()).contains(""" + load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") + kt_jvm_test( + name = "test", + srcs = ["MainTest.kt"], + deps = [ + "//coverage/main/java/com/example:main", + "@maven//:junit_junit", + ], + visibility = ["//visibility:public"], + test_class = "com.example.MainTest", + ) + """.trimIndent()) + } + @Test fun testAddTestToBuildFile_reusedTestName_throwsException() { val testBazelWorkspace = TestBazelWorkspace(tempFolder) From 2fe7485ce87ec6482f07bd4ceb2376084645640c Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 13 Jun 2024 20:44:07 +0530 Subject: [PATCH 013/105] Fix Lint warnings with TestBazelWorkspaceTest --- .../scripts/testing/TestBazelWorkspace.kt | 14 ++- .../scripts/testing/TestBazelWorkspaceTest.kt | 99 ++++++++++++------- 2 files changed, 78 insertions(+), 35 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index fb0e48cba50..71ee2eb542a 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -66,11 +66,21 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { subpackage: String ) { val sourceSubpackage = "$subpackage/main/java/com/example" - addSourceContentAndBuildFile(filename, sourceContent, sourceSubpackage) + addSourceContentAndBuildFile( + filename, + sourceContent, + sourceSubpackage + ) val testSubpackage = "$subpackage/test/java/com/example" val testFileName = "${filename}Test" - addTestContentAndBuildFile(filename, testFileName, testContent, sourceSubpackage, testSubpackage) + addTestContentAndBuildFile( + filename, + testFileName, + testContent, + sourceSubpackage, + testSubpackage + ) } /** diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index 2492ea6aa58..9d6a33378d6 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -257,26 +257,33 @@ class TestBazelWorkspaceTest { @Test fun testAddSourceAndTestFileWithContent_createsSourceAndTestFiles() { val testBazelWorkspace = TestBazelWorkspace(tempFolder) - val sourceContent = """ - fun main() { - println("Hello, World!") - } - """ - - val testContent = """ - import org.junit.Test - import kotlin.test.assertEquals - - class MainTest { - - @Test - fun testMain() { - assertEquals(1, 1) - } - } - """ + val sourceContent = + """ + fun main() { + println("Hello, World!") + } + """ - testBazelWorkspace.addSourceAndTestFileWithContent("Main", sourceContent, testContent, "coverage") + val testContent = + """ + import org.junit.Test + import kotlin.test.assertEquals + + class MainTest { + + @Test + fun testMain() { + assertEquals(1, 1) + } + } + """ + + testBazelWorkspace.addSourceAndTestFileWithContent( + "Main", + sourceContent, + testContent, + "coverage" + ) val sourceFile = File(tempFolder.root, "coverage/main/java/com/example/Main.kt") val testFile = File(tempFolder.root, "coverage/test/java/com/example/MainTest.kt") @@ -292,7 +299,8 @@ class TestBazelWorkspaceTest { fun testAddSourceAndTestFileWithContent_updatesBuildFiles() { val testBazelWorkspace = TestBazelWorkspace(tempFolder) val sourceContent = "fun main() { println(\"Hello, World!\") }" - val testContent = """ + val testContent = + """ import org.junit.Test import kotlin.test.assertEquals @@ -302,24 +310,32 @@ class TestBazelWorkspaceTest { assertEquals(1, 1) } } - """.trimIndent() + """.trimIndent() - testBazelWorkspace.addSourceAndTestFileWithContent("Main", sourceContent, testContent, "coverage") + testBazelWorkspace.addSourceAndTestFileWithContent( + "Main", + sourceContent, + testContent, + "coverage" + ) val sourceBuildFile = File(tempFolder.root, "coverage/main/java/com/example/BUILD.bazel") val testBuildFile = File(tempFolder.root, "coverage/test/java/com/example/BUILD.bazel") assertThat(sourceBuildFile.exists()).isTrue() - assertThat(sourceBuildFile.readText()).contains(""" + assertThat(sourceBuildFile.readText()).contains( + """ kt_jvm_library( name = "main", srcs = ["Main.kt"], visibility = ["//visibility:public"] ) - """.trimIndent()) + """.trimIndent() + ) assertThat(testBuildFile.exists()).isTrue() - assertThat(testBuildFile.readText()).contains(""" + assertThat(testBuildFile.readText()).contains( + """ load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") kt_jvm_test( name = "test", @@ -331,7 +347,8 @@ class TestBazelWorkspaceTest { visibility = ["//visibility:public"], test_class = "com.example.MainTest", ) - """.trimIndent()) + """.trimIndent() + ) } @Test @@ -339,7 +356,11 @@ class TestBazelWorkspaceTest { val testBazelWorkspace = TestBazelWorkspace(tempFolder) val sourceContent = "fun main() { println(\"Hello, World!\") }" - testBazelWorkspace.addSourceContentAndBuildFile("Main", sourceContent, "coverage/main/java/com/example") + testBazelWorkspace.addSourceContentAndBuildFile( + "Main", + sourceContent, + "coverage/main/java/com/example" + ) val sourceFile = File(tempFolder.root, "coverage/main/java/com/example/Main.kt") val buildFile = File(tempFolder.root, "coverage/main/java/com/example/BUILD.bazel") @@ -348,21 +369,31 @@ class TestBazelWorkspaceTest { assertThat(sourceFile.readText()).isEqualTo(sourceContent.trimIndent()) assertThat(buildFile.exists()).isTrue() - assertThat(buildFile.readText()).contains(""" + assertThat(buildFile.readText()).contains( + """ kt_jvm_library( name = "main", srcs = ["Main.kt"], visibility = ["//visibility:public"] ) - """.trimIndent()) + """.trimIndent() + ) } @Test fun testAddTestContentAndBuildFile_createsTestFileAndBuildFile() { val testBazelWorkspace = TestBazelWorkspace(tempFolder) - val testContent = "import org.junit.Test\nimport kotlin.test.assertEquals\n\nclass MainTest {\n@Test\nfun testMain() {\nassertEquals(1, 1)\n}\n}" + val testContent = "import org.junit.Test" + + "\nimport kotlin.test.assertEquals\n\nclass MainTest {" + + "\n@Test\nfun testMain() {\nassertEquals(1, 1)\n}\n}" - testBazelWorkspace.addTestContentAndBuildFile("Main", "MainTest", testContent, "coverage/main/java/com/example", "coverage/test/java/com/example") + testBazelWorkspace.addTestContentAndBuildFile( + "Main", + "MainTest", + testContent, + "coverage/main/java/com/example", + "coverage/test/java/com/example" + ) val testFile = File(tempFolder.root, "coverage/test/java/com/example/MainTest.kt") val buildFile = File(tempFolder.root, "coverage/test/java/com/example/BUILD.bazel") @@ -371,7 +402,8 @@ class TestBazelWorkspaceTest { assertThat(testFile.readText()).isEqualTo(testContent.trimIndent()) assertThat(buildFile.exists()).isTrue() - assertThat(buildFile.readText()).contains(""" + assertThat(buildFile.readText()).contains( + """ load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") kt_jvm_test( name = "test", @@ -383,7 +415,8 @@ class TestBazelWorkspaceTest { visibility = ["//visibility:public"], test_class = "com.example.MainTest", ) - """.trimIndent()) + """.trimIndent() + ) } @Test From bd683b55175055944ba351f67d7fd2b287d23271 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 13 Jun 2024 21:10:25 +0530 Subject: [PATCH 014/105] Fix Regex Pattern checks --- .../org/oppia/android/scripts/coverage/CoverageRunnerTest.kt | 2 +- .../android/scripts/coverage/RunCoverageForTestTargetTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 7d3ced9b557..5533d7f5b98 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -10,7 +10,7 @@ import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows -/** Tests for [CoverageRunner] */ +/** Tests for [CoverageRunner]. */ class CoverageRunnerTest { @field:[Rule JvmField] val tempFolder = TemporaryFolder() diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index 2c1d579168f..6d1d3cf5045 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -10,7 +10,7 @@ import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows -/** Tests for [RunCoverageForTestTarget] */ +/** Tests for [RunCoverageForTestTarget]. */ class RunCoverageForTestTargetTest { @field:[Rule JvmField] val tempFolder = TemporaryFolder() From d410d17326b86178e954f155fa79530efbdaa452 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 15 Jun 2024 13:46:34 +0530 Subject: [PATCH 015/105] Prototyped parsing and reading the extracted file data as byte array --- scripts/BUILD.bazel | 9 ++++ .../android/scripts/common/BazelClient.kt | 47 +++++++++++++++++-- .../scripts/coverage/CoverageRunner.kt | 10 ++-- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 689cf6e53d2..23587533fa0 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -237,6 +237,15 @@ kt_jvm_binary( ], ) +kt_jvm_binary( + name = "run_coverage_for_test_target", + testonly = True, + main_class = "org.oppia.android.scripts.coverage.RunCoverageForTestTargetKt", + runtime_deps = [ + "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", + ], +) + # Note that this is intentionally not test-only since it's used by the app build pipeline. Also, # this apparently needs to be a java_binary to set up runfiles correctly when executed within a # Starlark rule as a tool. diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 706adbba03c..881cdefd312 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -3,6 +3,8 @@ package org.oppia.android.scripts.common import java.io.File import java.lang.IllegalArgumentException import java.util.Locale +import java.nio.file.Files +import java.nio.file.Paths /** * Utility class to query & interact with a Bazel workspace on the local filesystem (residing within @@ -133,14 +135,51 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: /** * Runs code coverage for the specified Bazel test target. * - * @param bazelTestTarget Bazel test target for which code coverage will be run. - * @return generated coverageResult output + * @param bazelTestTarget Bazel test target for which code coverage will be run + * @return the coverage data file path generated from bazel coverage */ - fun runCoverageForTestTarget(bazelTestTarget: String): List { - return executeBazelCommand( + fun runCoverageForTestTarget(bazelTestTarget: String): String? { + val coverageData = executeBazelCommand( "coverage", bazelTestTarget ) + val coverageDataFilePath = parseCoverageDataFile(coverageData) + val coverageDataFileContent = readDatFileAsBinary(coverageDataFilePath!!) + println("Binary Data: $coverageDataFileContent") + println("Converated Data: ${convertByteArrayToString(coverageDataFileContent)}") + return "Stringing" + /*return executeBazelCommand( + "coverage", + bazelTestTarget + )*/ + } + + fun convertByteArrayToString(bytes: ByteArray?): String { + return String(bytes!!, Charsets.UTF_8) + } + + /** + * Parse the coverage command result to extract the path of the coverage data file. + * + * @param data the result from the execution of the coverage command + * @return the extracted path of the coverage data file. + */ + fun parseCoverageDataFile(data: List): String? { + val regex = ".*coverage\\.dat$".toRegex() + for (line in data) { + val match = regex.find(line) + val extractedPath = match?.value?.substringAfterLast(",")?.trim() + if (extractedPath != null) { + println("Parsed Coverage Data File: $extractedPath") + return extractedPath + } + } + return null + } + + fun readDatFileAsBinary(filePath: String?): ByteArray? { + val path = Paths.get(filePath!!) + return Files.readAllBytes(path!!) } /** 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 1cee918a176..717d8aad039 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -33,9 +33,8 @@ class CoverageRunner( bazelTestTarget: String ): Deferred { return CoroutineScope(scriptBgDispatcher).async { - val coverageData = getCoverage(bazelTestTarget) - val data = coverageData - parseCoverageDataFile(data) + val coverageDataFilePath = getCoverage(bazelTestTarget) + coverageDataFilePath } } @@ -49,7 +48,7 @@ class CoverageRunner( */ fun getCoverage( bazelTestTarget: String - ): List { + ): String? { val commandExecutor: CommandExecutor = CommandExecutorImpl( scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES ) @@ -63,7 +62,6 @@ class CoverageRunner( * * @param data the result from the execution of the coverage command * @return the extracted path of the coverage data file. - */ fun parseCoverageDataFile(data: List): String? { val regex = ".*coverage\\.dat$".toRegex() for (line in data) { @@ -75,5 +73,5 @@ class CoverageRunner( } } return null - } + }*/ } From ece147a249d6e955d4a8184a5a34c0ee11619f83 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 15 Jun 2024 14:21:54 +0530 Subject: [PATCH 016/105] Updated the runCoverageForTestTarget to parse the data file and read the contents as byte array --- .../android/scripts/common/BazelClient.kt | 20 ++++++------- .../scripts/coverage/CoverageRunner.kt | 28 ++++++++----------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 881cdefd312..87d66ea34b9 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -138,24 +138,14 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * @param bazelTestTarget Bazel test target for which code coverage will be run * @return the coverage data file path generated from bazel coverage */ - fun runCoverageForTestTarget(bazelTestTarget: String): String? { + fun runCoverageForTestTarget(bazelTestTarget: String): ByteArray? { val coverageData = executeBazelCommand( "coverage", bazelTestTarget ) val coverageDataFilePath = parseCoverageDataFile(coverageData) val coverageDataFileContent = readDatFileAsBinary(coverageDataFilePath!!) - println("Binary Data: $coverageDataFileContent") - println("Converated Data: ${convertByteArrayToString(coverageDataFileContent)}") - return "Stringing" - /*return executeBazelCommand( - "coverage", - bazelTestTarget - )*/ - } - - fun convertByteArrayToString(bytes: ByteArray?): String { - return String(bytes!!, Charsets.UTF_8) + return coverageDataFileContent } /** @@ -177,6 +167,12 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return null } + /** + * Reads the content of the .dat file as a binary blob. + * + * @param filePath path to the .dat file + * @return content of the .dat file as binary data + */ fun readDatFileAsBinary(filePath: String?): ByteArray? { val path = Paths.get(filePath!!) return Files.readAllBytes(path!!) 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 717d8aad039..ef645901683 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -53,25 +53,19 @@ class CoverageRunner( scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES ) val bazelClient = BazelClient(repoRoot, commandExecutor) - val coverageData = bazelClient.runCoverageForTestTarget(bazelTestTarget) - return coverageData + val coverageDataBinary = bazelClient.runCoverageForTestTarget(bazelTestTarget) + val coverageDataString = convertByteArrayToString(coverageDataBinary!!) + + return coverageDataString } /** - * Parse the coverage command result to extract the path of the coverage data file. + * Converts a ByteArray to a String using UTF-8 encoding. * - * @param data the result from the execution of the coverage command - * @return the extracted path of the coverage data file. - fun parseCoverageDataFile(data: List): String? { - val regex = ".*coverage\\.dat$".toRegex() - for (line in data) { - val match = regex.find(line) - val extractedPath = match?.value?.substringAfterLast(",")?.trim() - if (extractedPath != null) { - println("Parsed Coverage Data File: $extractedPath") - return extractedPath - } - } - return null - }*/ + * @param bytes byte array to convert + * @return string representation of the byte array + */ + fun convertByteArrayToString(coverageBinaryData: ByteArray?): String? { + return String(coverageBinaryData!!, Charsets.UTF_8) + } } From b101ec8568c4730b90aca213c4eda6019b672e87 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 15 Jun 2024 17:27:48 +0530 Subject: [PATCH 017/105] Updated Bazel Client Tests with updated execution to return byte array --- .../android/scripts/common/BazelClientTest.kt | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index be38e436ab2..e9d27929801 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -381,12 +381,7 @@ class BazelClientTest { @Test fun testRunCodeCoverage_forSampleTestTarget_returnsCoverageResult() { - val commandExecutor = CommandExecutorImpl( - scriptBgDispatcher, - processTimeout = 5, - processTimeoutUnit = TimeUnit.MINUTES - ) - val bazelClient = BazelClient(tempFolder.root, commandExecutor) + val bazelClient = BazelClient(tempFolder.root, longCommandExecutor) testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -434,18 +429,13 @@ class BazelClientTest { val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test") - // Check that the test has "PASSED" - val containsPassedValue = result.any { it.contains("PASSED") } - assert(containsPassedValue) { "The test is not 'PASSED'" } - - // Check if the coverage.dat file is generated - val containsCoverageData = result.any { it.contains("coverage.dat") } - assert(containsCoverageData) { "The coverage.dat is not generated" } + // Check if ByteArray is returned from executing coverage command + assertThat(result).isInstanceOf(ByteArray::class.java) } @Test fun testRunCodeCoverage_forNonTestTarget_fails() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) + val bazelClient = BazelClient(tempFolder.root, longCommandExecutor) testBazelWorkspace.initEmptyWorkspace() val exception = assertThrows() { From 5db06508236e7089c30739537f5dbfd7251e3497 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 10:16:06 +0530 Subject: [PATCH 018/105] Updated BazelClientTest for ParseCoverageDataFile and readDatFileAsBinary --- .../android/scripts/common/BazelClientTest.kt | 84 +++++++++++++++++++ .../scripts/coverage/CoverageRunnerTest.kt | 25 ------ 2 files changed, 84 insertions(+), 25 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index e9d27929801..94e689c2bad 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -15,6 +15,7 @@ import org.oppia.android.testing.assertThrows import org.oppia.android.testing.mockito.anyOrNull import java.io.File import java.util.concurrent.TimeUnit +import java.nio.file.NoSuchFileException /** * Tests for [BazelClient]. @@ -379,6 +380,89 @@ class BazelClientTest { assertThat(thirdPartyDependenciesList).doesNotContain("@maven//:androidx_annotation_annotation") } + @Test + fun testParseCoverageDataFile_invalidData_returnsNull() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + // Result data from coverage execution that doesn't contain path to coverage data file [coverage.dat] + val invalidResultData = listOf("data1", "data2", "data3") + + val parsedData = bazelClient.parseCoverageDataFile(invalidResultData) + // Return Null when the coverage data file path is not found + assertThat(parsedData).isNull() + } + + @Test + fun testParseCoverageDataFile_validData_returnsNull() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + // Result data from coverage execution that contains path to coverage data file [coverage.dat] + val validResultData = listOf( + "//package/test/example:test PASSED in 0.4s", + "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat", + "Executed 1 out of 1 test: 1 test passes." + ) + val expectedResultParsedData = + "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat" + + val parsedData = bazelClient.parseCoverageDataFile(validResultData) + assertThat(parsedData).isEqualTo(expectedResultParsedData) + } + + @Test + fun testReadDatFileAsBinary_WithValidCoverageDatFile_returnsBinaryData() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + // Create a temporary coverage.dat file with sample data + val tempFile = tempFolder.newFile("coverage.dat") + val content = """ + SF:/path/to/sourcefile.kt + FN:3,com/example/source:: ()V + FNF:1 + FNH:1 + DA:3,0 + DA:6,1 + LF:6 + end_of_record + """.trimIndent() + tempFile.appendText(content) + + // Call the function with the valid file path + val result = bazelClient.readDatFileAsBinary(tempFile.toPath().toString()) + + // Assert the content matches + assertThat(result).isEqualTo(content.toByteArray()) + } + + @Test + fun testReadDatFileAsBinary_WithNullFilePath_throwsException() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + + assertThrows() { + bazelClient.readDatFileAsBinary(null) + } + } + + @Test + fun testReadDatFileAsBinary_WithInvalidFilePath_throwsException() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + val invalidFilePath = "invalid_coverage.dat" + + assertThrows() { + bazelClient.readDatFileAsBinary(invalidFilePath) + } + } + + @Test + fun testReadDatFileAsBinary_WithEmptyCoverageDatFile_returnsEmptyBinaryData() { + val bazelClient = BazelClient(tempFolder.root, commandExecutor) + // Create a temporary coverage.dat file with empty data + val tempFile = tempFolder.newFile("coverage.dat") + + // Call the function with the valid file path + val result = bazelClient.readDatFileAsBinary(tempFile.toPath().toString()) + + // Assert the content matches + assertThat(result).isEqualTo(ByteArray(0)) + } + @Test fun testRunCodeCoverage_forSampleTestTarget_returnsCoverageResult() { val bazelClient = BazelClient(tempFolder.root, longCommandExecutor) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 5533d7f5b98..4f8493da51e 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -32,31 +32,6 @@ class CoverageRunnerTest { scriptBgDispatcher.close() } - @Test - fun testParseCoverageDataFile_invalidData_returnsNull() { - // Result data from coverage execution that doesn't contain path to coverage data file [coverage.dat] - val invalidResultData = listOf("data1", "data2", "data3") - - val parsedData = coverageRunner.parseCoverageDataFile(invalidResultData) - // Return Null when the coverage data file path is not found - assertThat(parsedData).isNull() - } - - @Test - fun testParseCoverageDataFile_validData_returnsNull() { - // Result data from coverage execution that contains path to coverage data file [coverage.dat] - val validResultData = listOf( - "//package/test/example:test PASSED in 0.4s", - "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat", - "Executed 1 out of 1 test: 1 test passes." - ) - val expectedResultParsedData = - "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat" - - val parsedData = coverageRunner.parseCoverageDataFile(validResultData) - assertThat(parsedData).isEqualTo(expectedResultParsedData) - } - @Test fun testRunCoverage_emptyDirectory_throwsException() { val exception = assertThrows() { From 87be11408b172b752834f663c60a744a0abdfa3f Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 11:29:48 +0530 Subject: [PATCH 019/105] Updated CoverageRunnerTest to check with updated getCoverage result returning coverage data --- .../scripts/coverage/CoverageRunnerTest.kt | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 4f8493da51e..ef8a662eed2 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -102,12 +102,28 @@ class CoverageRunnerTest { val result = coverageRunner.getCoverage("//coverage/test/java/com/example:test") - // Check that the test has "PASSED" - val containsPassedValue = result.any { it.contains("PASSED") } - assert(containsPassedValue) { "The test is not 'PASSED'" } - - // Check if the coverage.dat file is generated - val containsCoverageData = result.any { it.contains("coverage.dat") } - assert(containsCoverageData) { "The coverage.dat is not generated" } + assertThat(result).isEqualTo( + """ + SF:coverage/main/java/com/example/TwoSum.kt + FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; + FN:3,com/example/TwoSum:: ()V + FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; + FNDA:0,com/example/TwoSum:: ()V + FNF:2 + FNH:1 + BRDA:7,0,0,1 + BRDA:7,0,1,1 + BRDA:7,0,2,1 + BRDA:7,0,3,1 + BRF:4 + BRH:4 + DA:3,0 + DA:7,1 + DA:8,1 + DA:10,1 + LH:3 + LF:4 + end_of_record""".trimIndent() + "\n" + ) } } From 456e81b55b9fec782bbcc0f962577163c07b0fa4 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 11:45:51 +0530 Subject: [PATCH 020/105] Updated RunCoverageForTestTargetTest to check the returned coverage data --- .../coverage/RunCoverageForTestTargetTest.kt | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index 6d1d3cf5045..fba9c898374 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -109,8 +109,28 @@ class RunCoverageForTestTargetTest { "//coverage/test/java/com/example:test" ).runCoverage() - // Check if the coverage.dat file is generated and parsed as result - val parsedCoverageDataPath = result?.endsWith("coverage.dat") - assert(parsedCoverageDataPath!!) { "The coverage.dat is not generated" } + assertThat(result).isEqualTo( + """ + SF:coverage/main/java/com/example/TwoSum.kt + FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; + FN:3,com/example/TwoSum:: ()V + FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; + FNDA:0,com/example/TwoSum:: ()V + FNF:2 + FNH:1 + BRDA:7,0,0,1 + BRDA:7,0,1,1 + BRDA:7,0,2,1 + BRDA:7,0,3,1 + BRF:4 + BRH:4 + DA:3,0 + DA:7,1 + DA:8,1 + DA:10,1 + LH:3 + LF:4 + end_of_record""".trimIndent() + "\n" + ) } } From 2c655249ae49fca8caee094a1430013036b382f5 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 12:22:53 +0530 Subject: [PATCH 021/105] Update kdoc to match the function paramaters --- .../oppia/android/scripts/coverage/CoverageRunner.kt | 12 ++++-------- .../scripts/coverage/RunCoverageForTestTarget.kt | 5 ++++- 2 files changed, 8 insertions(+), 9 deletions(-) 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 ef645901683..b03b5ca8a60 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -13,8 +13,8 @@ import java.util.concurrent.TimeUnit /** * Class responsible for running coverage analysis asynchronously. * - * @param repoRoot the absolute path to the working root directory - * @param targetFile Path to the target file to analyze coverage. + * @param repoRoot the root directory of the repository + * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command */ class CoverageRunner( private val repoRoot: File, @@ -24,8 +24,6 @@ class CoverageRunner( /** * Runs coverage analysis asynchronously for the Bazel test target. * - * @param repoRoot the absolute path to the working root directory - * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command * @param bazelTestTarget Bazel test target to analyze coverage. * @return a deferred value that contains the path of the coverage data file [will contain the proto for the coverage data]. */ @@ -41,10 +39,8 @@ class CoverageRunner( /** * Runs coverage command for the Bazel test target. * - * @param repoRoot the absolute path to the working root directory - * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command * @param bazelTestTarget Bazel test target to analyze coverage. - * @return a lisf of string that contains the result of the coverage execution. + * @return the generated coverage data as a string. */ fun getCoverage( bazelTestTarget: String @@ -62,7 +58,7 @@ class CoverageRunner( /** * Converts a ByteArray to a String using UTF-8 encoding. * - * @param bytes byte array to convert + * @param coverageBinaryData byte array to convert * @return string representation of the byte array */ fun convertByteArrayToString(coverageBinaryData: ByteArray?): String? { diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index 9ddf3a04450..71f671303cc 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -27,6 +27,9 @@ fun main(vararg args: String) { /** * Class responsible for analyzing target files for coverage and generating reports. + * + * @param repoRoot the root directory of the repository + * @param targetPath Bazel test target to analyze coverage. */ class RunCoverageForTestTarget( private val repoRoot: File, @@ -43,7 +46,7 @@ class RunCoverageForTestTarget( /** * Runs coverage analysis on the specified target file asynchronously. * - * @return [Path of the coverage data file]. + * @return the generated coverage data. */ fun runWithCoverageAnalysis(): String? { return ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> From 62f9e1d9abf8ffb1f678d6eec93fa19dff2ddf2f Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 14:20:17 +0530 Subject: [PATCH 022/105] Removing suspend while keeping the async operations --- .../java/org/oppia/android/scripts/coverage/CoverageRunner.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b03b5ca8a60..52159b2d31c 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -25,9 +25,9 @@ class CoverageRunner( * Runs coverage analysis asynchronously for the Bazel test target. * * @param bazelTestTarget Bazel test target to analyze coverage. - * @return a deferred value that contains the path of the coverage data file [will contain the proto for the coverage data]. + * @return a deferred value that contains the coverage data [will contain the proto for the coverage data]. */ - suspend fun runWithCoverageAsync( + fun runWithCoverageAsync( bazelTestTarget: String ): Deferred { return CoroutineScope(scriptBgDispatcher).async { From 5e6d2ef8288011ac57c8d9ac1a1859f66474a305 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 16:13:40 +0530 Subject: [PATCH 023/105] Updated RunCoverageForTestTarget to take in custom process timeout as arguments and use them --- .../scripts/coverage/CoverageRunner.kt | 9 ++--- .../coverage/RunCoverageForTestTarget.kt | 34 +++++++++++++++---- .../scripts/coverage/CoverageRunnerTest.kt | 11 +++++- .../coverage/RunCoverageForTestTargetTest.kt | 22 ++++++++++-- 4 files changed, 59 insertions(+), 17 deletions(-) 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 52159b2d31c..5c29404983b 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -5,20 +5,20 @@ import kotlinx.coroutines.Deferred import kotlinx.coroutines.async import org.oppia.android.scripts.common.BazelClient import org.oppia.android.scripts.common.CommandExecutor -import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import java.io.File -import java.util.concurrent.TimeUnit /** * Class responsible for running coverage analysis asynchronously. * * @param repoRoot the root directory of the repository * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command + * @param commandExecutor Executes the specified command in the specified working directory */ class CoverageRunner( private val repoRoot: File, - private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher + private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, + private val commandExecutor: CommandExecutor ) { /** @@ -45,9 +45,6 @@ class CoverageRunner( fun getCoverage( bazelTestTarget: String ): String? { - val commandExecutor: CommandExecutor = CommandExecutorImpl( - scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES - ) val bazelClient = BazelClient(repoRoot, commandExecutor) val coverageDataBinary = bazelClient.runCoverageForTestTarget(bazelTestTarget) val coverageDataString = convertByteArrayToString(coverageDataBinary!!) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index 71f671303cc..bd4af64885e 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -2,7 +2,10 @@ package org.oppia.android.scripts.coverage import kotlinx.coroutines.runBlocking import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.scripts.common.CommandExecutor +import org.oppia.android.scripts.common.CommandExecutorImpl import java.io.File +import java.util.concurrent.TimeUnit /** * Entry point function for running coverage analysis for a single test target. @@ -17,23 +20,40 @@ import java.io.File * Example: * bazel run //scripts:run_coverage_for_test_target -- $(pwd) * //utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest + * Example with custom process timeout: + * bazel run //scripts:run_coverage_for_test_target -- $(pwd) + * //utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest processTimeout=10 + * */ fun main(vararg args: String) { val repoRoot = File(args[0]).absoluteFile.normalize() val targetPath = args[1] - RunCoverageForTestTarget(repoRoot, targetPath).runCoverage() + ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> + val processTimeout: Long = args.find { it.startsWith("processTimeout=") } + ?.substringAfter("=") + ?.toLongOrNull() ?: 5 + + val commandExecutor: CommandExecutor = CommandExecutorImpl( + scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES + ) + + RunCoverageForTestTarget(repoRoot, targetPath, commandExecutor, scriptBgDispatcher).runCoverage() + } } /** * Class responsible for analyzing target files for coverage and generating reports. * * @param repoRoot the root directory of the repository - * @param targetPath Bazel test target to analyze coverage. + * @param targetPath Bazel test target to analyze coverage + * @param commandExecutor Executes the specified command in the specified working directory */ class RunCoverageForTestTarget( private val repoRoot: File, - private val targetPath: String + private val targetPath: String, + private val commandExecutor: CommandExecutor, + private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher ) { /** @@ -49,12 +69,12 @@ class RunCoverageForTestTarget( * @return the generated coverage data. */ fun runWithCoverageAnalysis(): String? { - return ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> - runBlocking { + return runBlocking { val result = - CoverageRunner(repoRoot, scriptBgDispatcher).runWithCoverageAsync(targetPath).await() + CoverageRunner(repoRoot, scriptBgDispatcher, commandExecutor) + .runWithCoverageAsync(targetPath) + .await() result } } } -} diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index ef8a662eed2..2911a0fffb1 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -6,15 +6,18 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows +import java.util.concurrent.TimeUnit /** Tests for [CoverageRunner]. */ class CoverageRunnerTest { @field:[Rule JvmField] val tempFolder = TemporaryFolder() private val scriptBgDispatcher by lazy { ScriptBackgroundCoroutineDispatcher() } + private val longCommandExecutor by lazy { initializeCommandExecutorWithLongProcessWaitTime() } private lateinit var coverageRunner: CoverageRunner private lateinit var testBazelWorkspace: TestBazelWorkspace @@ -22,7 +25,7 @@ class CoverageRunnerTest { @Before fun setUp() { - coverageRunner = CoverageRunner(tempFolder.root, scriptBgDispatcher) + coverageRunner = CoverageRunner(tempFolder.root, scriptBgDispatcher, longCommandExecutor) bazelTestTarget = "//:testTarget" testBazelWorkspace = TestBazelWorkspace(tempFolder) } @@ -126,4 +129,10 @@ class CoverageRunnerTest { end_of_record""".trimIndent() + "\n" ) } + + private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { + return CommandExecutorImpl( + scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES + ) + } } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index fba9c898374..793eec2904b 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -6,15 +6,19 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows +import java.util.concurrent.TimeUnit /** Tests for [RunCoverageForTestTarget]. */ class RunCoverageForTestTargetTest { @field:[Rule JvmField] val tempFolder = TemporaryFolder() private val scriptBgDispatcher by lazy { ScriptBackgroundCoroutineDispatcher() } + private val commandExecutor by lazy { CommandExecutorImpl(scriptBgDispatcher) } + private val longCommandExecutor by lazy { initializeCommandExecutorWithLongProcessWaitTime() } private lateinit var testBazelWorkspace: TestBazelWorkspace private lateinit var bazelTestTarget: String @@ -35,7 +39,9 @@ class RunCoverageForTestTargetTest { val exception = assertThrows() { RunCoverageForTestTarget( tempFolder.root, - bazelTestTarget + bazelTestTarget, + commandExecutor, + scriptBgDispatcher ).runCoverage() } @@ -49,7 +55,9 @@ class RunCoverageForTestTargetTest { val exception = assertThrows() { RunCoverageForTestTarget( tempFolder.root, - bazelTestTarget + bazelTestTarget, + commandExecutor, + scriptBgDispatcher ).runCoverage() } @@ -106,7 +114,9 @@ class RunCoverageForTestTargetTest { val result = RunCoverageForTestTarget( tempFolder.root, - "//coverage/test/java/com/example:test" + "//coverage/test/java/com/example:test", + longCommandExecutor, + scriptBgDispatcher ).runCoverage() assertThat(result).isEqualTo( @@ -133,4 +143,10 @@ class RunCoverageForTestTargetTest { end_of_record""".trimIndent() + "\n" ) } + + private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { + return CommandExecutorImpl( + scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES + ) + } } From 31b6401a6d17e92d501e092e524af7b3939b14ea Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 16:39:05 +0530 Subject: [PATCH 024/105] Initialized bazelClient using lazy field --- .../java/org/oppia/android/scripts/coverage/CoverageRunner.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5c29404983b..5274ff92bbb 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -20,6 +20,7 @@ class CoverageRunner( private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher, private val commandExecutor: CommandExecutor ) { + private val bazelClient by lazy { BazelClient(repoRoot, commandExecutor) } /** * Runs coverage analysis asynchronously for the Bazel test target. @@ -45,7 +46,6 @@ class CoverageRunner( fun getCoverage( bazelTestTarget: String ): String? { - val bazelClient = BazelClient(repoRoot, commandExecutor) val coverageDataBinary = bazelClient.runCoverageForTestTarget(bazelTestTarget) val coverageDataString = convertByteArrayToString(coverageDataBinary!!) From 81d68550549d046aad154105185dae98b2d093bd Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 16:50:46 +0530 Subject: [PATCH 025/105] Adjusted visibility and removed unnecessary documentation for private methods --- .../oppia/android/scripts/common/BazelClient.kt | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 87d66ea34b9..968b204b17e 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -148,13 +148,7 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return coverageDataFileContent } - /** - * Parse the coverage command result to extract the path of the coverage data file. - * - * @param data the result from the execution of the coverage command - * @return the extracted path of the coverage data file. - */ - fun parseCoverageDataFile(data: List): String? { + private fun parseCoverageDataFile(data: List): String? { val regex = ".*coverage\\.dat$".toRegex() for (line in data) { val match = regex.find(line) @@ -167,13 +161,7 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return null } - /** - * Reads the content of the .dat file as a binary blob. - * - * @param filePath path to the .dat file - * @return content of the .dat file as binary data - */ - fun readDatFileAsBinary(filePath: String?): ByteArray? { + private fun readDatFileAsBinary(filePath: String?): ByteArray? { val path = Paths.get(filePath!!) return Files.readAllBytes(path!!) } From 6cb1da7056f63c85f1327ba0366594b43428cf6d Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 17:06:44 +0530 Subject: [PATCH 026/105] Revoking visibility of bazelClient functions as that is called outside in testing the utilities --- .../oppia/android/scripts/common/BazelClient.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 968b204b17e..87d66ea34b9 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -148,7 +148,13 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return coverageDataFileContent } - private fun parseCoverageDataFile(data: List): String? { + /** + * Parse the coverage command result to extract the path of the coverage data file. + * + * @param data the result from the execution of the coverage command + * @return the extracted path of the coverage data file. + */ + fun parseCoverageDataFile(data: List): String? { val regex = ".*coverage\\.dat$".toRegex() for (line in data) { val match = regex.find(line) @@ -161,7 +167,13 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return null } - private fun readDatFileAsBinary(filePath: String?): ByteArray? { + /** + * Reads the content of the .dat file as a binary blob. + * + * @param filePath path to the .dat file + * @return content of the .dat file as binary data + */ + fun readDatFileAsBinary(filePath: String?): ByteArray? { val path = Paths.get(filePath!!) return Files.readAllBytes(path!!) } From b41fb01956d13115724f6a016732e582cc65f1ed Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 17 Jun 2024 18:11:53 +0530 Subject: [PATCH 027/105] Fix Lint Check issues --- .../android/scripts/common/BazelClient.kt | 2 +- .../coverage/RunCoverageForTestTarget.kt | 23 +++++---- .../android/scripts/common/BazelClientTest.kt | 23 ++++----- .../scripts/coverage/CoverageRunnerTest.kt | 47 +++++++++---------- .../coverage/RunCoverageForTestTargetTest.kt | 46 +++++++++--------- 5 files changed, 73 insertions(+), 68 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 87d66ea34b9..39fe26eff19 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -2,9 +2,9 @@ package org.oppia.android.scripts.common import java.io.File import java.lang.IllegalArgumentException -import java.util.Locale import java.nio.file.Files import java.nio.file.Paths +import java.util.Locale /** * Utility class to query & interact with a Bazel workspace on the local filesystem (residing within diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index bd4af64885e..7010dbf7f45 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -1,9 +1,9 @@ package org.oppia.android.scripts.coverage import kotlinx.coroutines.runBlocking -import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import java.io.File import java.util.concurrent.TimeUnit @@ -38,7 +38,12 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - RunCoverageForTestTarget(repoRoot, targetPath, commandExecutor, scriptBgDispatcher).runCoverage() + RunCoverageForTestTarget( + repoRoot, + targetPath, + commandExecutor, + scriptBgDispatcher + ).runCoverage() } } @@ -69,12 +74,12 @@ class RunCoverageForTestTarget( * @return the generated coverage data. */ fun runWithCoverageAnalysis(): String? { - return runBlocking { - val result = - CoverageRunner(repoRoot, scriptBgDispatcher, commandExecutor) - .runWithCoverageAsync(targetPath) - .await() - result - } + return runBlocking { + val result = + CoverageRunner(repoRoot, scriptBgDispatcher, commandExecutor) + .runWithCoverageAsync(targetPath) + .await() + result } } +} diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 94e689c2bad..4bbde885d47 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -14,8 +14,8 @@ import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import org.oppia.android.testing.mockito.anyOrNull import java.io.File -import java.util.concurrent.TimeUnit import java.nio.file.NoSuchFileException +import java.util.concurrent.TimeUnit /** * Tests for [BazelClient]. @@ -412,16 +412,17 @@ class BazelClientTest { val bazelClient = BazelClient(tempFolder.root, commandExecutor) // Create a temporary coverage.dat file with sample data val tempFile = tempFolder.newFile("coverage.dat") - val content = """ - SF:/path/to/sourcefile.kt - FN:3,com/example/source:: ()V - FNF:1 - FNH:1 - DA:3,0 - DA:6,1 - LF:6 - end_of_record - """.trimIndent() + val content = + """ + SF:/path/to/sourcefile.kt + FN:3,com/example/source:: ()V + FNF:1 + FNH:1 + DA:3,0 + DA:6,1 + LF:6 + end_of_record + """.trimIndent() tempFile.appendText(content) // Call the function with the valid file path diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 2911a0fffb1..6892535c598 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -104,30 +104,29 @@ class CoverageRunnerTest { ) val result = coverageRunner.getCoverage("//coverage/test/java/com/example:test") - - assertThat(result).isEqualTo( - """ - SF:coverage/main/java/com/example/TwoSum.kt - FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; - FN:3,com/example/TwoSum:: ()V - FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; - FNDA:0,com/example/TwoSum:: ()V - FNF:2 - FNH:1 - BRDA:7,0,0,1 - BRDA:7,0,1,1 - BRDA:7,0,2,1 - BRDA:7,0,3,1 - BRF:4 - BRH:4 - DA:3,0 - DA:7,1 - DA:8,1 - DA:10,1 - LH:3 - LF:4 - end_of_record""".trimIndent() + "\n" - ) + val expectedResult = + "SF:coverage/main/java/com/example/TwoSum.kt\n" + + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FN:3,com/example/TwoSum:: ()V\n" + + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FNDA:0,com/example/TwoSum:: ()V\n" + + "FNF:2\n" + + "FNH:1\n" + + "BRDA:7,0,0,1\n" + + "BRDA:7,0,1,1\n" + + "BRDA:7,0,2,1\n" + + "BRDA:7,0,3,1\n" + + "BRF:4\n" + + "BRH:4\n" + + "DA:3,0\n" + + "DA:7,1\n" + + "DA:8,1\n" + + "DA:10,1\n" + + "LH:3\n" + + "LF:4\n" + + "end_of_record\n" + + assertThat(result).isEqualTo(expectedResult) } private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index 793eec2904b..df2390a5efc 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -119,29 +119,29 @@ class RunCoverageForTestTargetTest { scriptBgDispatcher ).runCoverage() - assertThat(result).isEqualTo( - """ - SF:coverage/main/java/com/example/TwoSum.kt - FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; - FN:3,com/example/TwoSum:: ()V - FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object; - FNDA:0,com/example/TwoSum:: ()V - FNF:2 - FNH:1 - BRDA:7,0,0,1 - BRDA:7,0,1,1 - BRDA:7,0,2,1 - BRDA:7,0,3,1 - BRF:4 - BRH:4 - DA:3,0 - DA:7,1 - DA:8,1 - DA:10,1 - LH:3 - LF:4 - end_of_record""".trimIndent() + "\n" - ) + val expectedResult = + "SF:coverage/main/java/com/example/TwoSum.kt\n" + + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FN:3,com/example/TwoSum:: ()V\n" + + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FNDA:0,com/example/TwoSum:: ()V\n" + + "FNF:2\n" + + "FNH:1\n" + + "BRDA:7,0,0,1\n" + + "BRDA:7,0,1,1\n" + + "BRDA:7,0,2,1\n" + + "BRDA:7,0,3,1\n" + + "BRF:4\n" + + "BRH:4\n" + + "DA:3,0\n" + + "DA:7,1\n" + + "DA:8,1\n" + + "DA:10,1\n" + + "LH:3\n" + + "LF:4\n" + + "end_of_record\n" + + assertThat(result).isEqualTo(expectedResult) } private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { From 1ffc83d5f369add26d8e0ebee0d0d916c6c18b8a Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 19 Jun 2024 02:46:41 +0530 Subject: [PATCH 028/105] Introduce new script RunCoverage.kt to later take in source filename instead of test target --- scripts/BUILD.bazel | 9 +++++++ .../android/scripts/coverage/BUILD.bazel | 14 +++++++++++ .../android/scripts/coverage/RunCoverage.kt | 24 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 23587533fa0..b47c7312ed5 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -246,6 +246,15 @@ kt_jvm_binary( ], ) +kt_jvm_binary( + name = "run_coverage", + testonly = True, + main_class = "org.oppia.android.scripts.coverage.RunCoverageKt", + runtime_deps = [ + "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_lib", + ], +) + # Note that this is intentionally not test-only since it's used by the app build pipeline. Also, # this apparently needs to be a java_binary to set up runfiles correctly when executed within a # Starlark rule as a tool. diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 53f09dbb98c..7ef26e88519 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -4,6 +4,20 @@ Libraries corresponding to developer scripts that obtain coverage data for test load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") +kt_jvm_library( + name = "run_coverage_lib", + testonly = True, + srcs = [ + "RunCoverage.kt", + ], + visibility = ["//scripts:oppia_script_binary_visibility"], + deps = [ + "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", + "//scripts/src/java/org/oppia/android/scripts/common:git_client", + "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", + ], +) + kt_jvm_library( name = "run_coverage_for_test_target_lib", testonly = True, diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt new file mode 100644 index 00000000000..f3282935878 --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -0,0 +1,24 @@ +package org.oppia.android.scripts.coverage + +import org.oppia.android.scripts.common.CommandExecutor +import org.oppia.android.scripts.common.CommandExecutorImpl +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import java.io.File +import java.util.concurrent.TimeUnit + +fun main(vararg args: String) { + val repoRoot = File(args[0]).absoluteFile.normalize() + val targetPath = args[1] + + ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> + val commandExecutor: CommandExecutor = CommandExecutorImpl( + scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES + ) + RunCoverageForTestTarget( + repoRoot, + targetPath, + commandExecutor, + scriptBgDispatcher + ).runCoverage() + } +} \ No newline at end of file From d817c8561d49f4784ce61298c1b46891639498e7 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 19 Jun 2024 19:21:03 +0530 Subject: [PATCH 029/105] Map file names to appropriate test and localTest names --- scripts/BUILD.bazel | 1 + .../android/scripts/coverage/BUILD.bazel | 2 + .../android/scripts/coverage/RunCoverage.kt | 88 +++++++++++++++++-- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index b47c7312ed5..a895764d5f2 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -249,6 +249,7 @@ kt_jvm_binary( kt_jvm_binary( name = "run_coverage", testonly = True, + data = TEST_FILE_EXEMPTION_ASSETS, main_class = "org.oppia.android.scripts.coverage.RunCoverageKt", runtime_deps = [ "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_lib", diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 7ef26e88519..02ee6835fb0 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -14,6 +14,8 @@ kt_jvm_library( deps = [ "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", "//scripts/src/java/org/oppia/android/scripts/common:git_client", + "//scripts/src/java/org/oppia/android/scripts/common:repository_file", + "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", ], ) 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 f3282935878..19618ad65eb 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -3,22 +3,94 @@ package org.oppia.android.scripts.coverage import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import java.io.File +import org.oppia.android.scripts.proto.TestFileExemptions import java.util.concurrent.TimeUnit +import java.io.File +import java.io.FileInputStream fun main(vararg args: String) { - val repoRoot = File(args[0]).absoluteFile.normalize() + val repoRoot = args[0] val targetPath = args[1] + val filePath = args[2] + + println("Repo root: $repoRoot") + println("Targetpath: $targetPath") + println("Filepath: $filePath") + + val testFileExemptiontextProto = "scripts/assets/test_file_exemptions" + + // A list of all the files to be exempted for this check. + // TODO(#3436): Develop a mechanism for permanently exempting files which do not ever need tests. + val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptiontextProto) + .getExemptedFilePathList() + +// println("test file exemption list: $testFileExemptionList") + + val isExempted = testFileExemptionList.contains(filePath) + if(isExempted) { + println("This file is exempted from having a test file. Hence No coverage!") + return + } + + val testFilePath = findTestFile(repoRoot, filePath) + println("Test File path: $testFilePath") - ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> - val commandExecutor: CommandExecutor = CommandExecutorImpl( - scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES - ) - RunCoverageForTestTarget( +// ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> +// val commandExecutor: CommandExecutor = CommandExecutorImpl( +// scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES +// ) + /*RunCoverageForTestTarget( repoRoot, targetPath, commandExecutor, scriptBgDispatcher - ).runCoverage() + ).runCoverage()*/ +// } +} + +private fun findTestFile(repoRoot: String, filePath: String): List { + val file = File(filePath) + val parts = file.parent.split(File.separator) + val testFiles = mutableListOf() + + if (parts.isNotEmpty() && parts[0] == "scripts") { + val testFilePath = filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt") + if (File(testFilePath).exists()) { + testFiles.add(testFilePath) + } + } else if (parts.isNotEmpty() && parts[0] == "app") { + val sharedTestFilePath = filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt") + val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") + val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") + + if (File(repoRoot, sharedTestFilePath).exists()) { + testFiles.add(sharedTestFilePath) + } + if (File(repoRoot, testFilePath).exists()) { + testFiles.add(testFilePath) + } + if (File(repoRoot, localTestFilePath).exists()) { + testFiles.add(localTestFilePath) + } + } else { + val defaultTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") + if (File(defaultTestFilePath).exists()) { + testFiles.add(defaultTestFilePath) + } } + return testFiles +} + +private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { + val protoBinaryFile = File("$testFileExemptiontextProto.pb") + val builder = TestFileExemptions.getDefaultInstance().newBuilderForType() + + // This cast is type-safe since proto guarantees type consistency from mergeFrom(), + // and this method is bounded by the generic type T. + @Suppress("UNCHECKED_CAST") + val protoObj: TestFileExemptions = + FileInputStream(protoBinaryFile).use { + builder.mergeFrom(it) + }.build() as TestFileExemptions + return protoObj } \ No newline at end of file From 7f1be37be1910d8d90da990029b2e9b8a0262722 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 19 Jun 2024 20:14:20 +0530 Subject: [PATCH 030/105] Running Multiple test targets using hardcoded test target names --- .../android/scripts/coverage/RunCoverage.kt | 63 ++++++++++++++----- 1 file changed, 48 insertions(+), 15 deletions(-) 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 19618ad65eb..098e6b25c81 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -1,5 +1,6 @@ package org.oppia.android.scripts.coverage +import org.oppia.android.scripts.common.BazelClient import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher @@ -10,30 +11,58 @@ import java.io.FileInputStream fun main(vararg args: String) { val repoRoot = args[0] + val rootDirectory = File(repoRoot).absoluteFile val targetPath = args[1] val filePath = args[2] - println("Repo root: $repoRoot") - println("Targetpath: $targetPath") - println("Filepath: $filePath") + ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> + val commandExecutor: CommandExecutor = CommandExecutorImpl( + scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES + ) - val testFileExemptiontextProto = "scripts/assets/test_file_exemptions" + val bazelClient = BazelClient(rootDirectory, commandExecutor) - // A list of all the files to be exempted for this check. - // TODO(#3436): Develop a mechanism for permanently exempting files which do not ever need tests. - val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptiontextProto) - .getExemptedFilePathList() + println("Repo root: $repoRoot") + println("Targetpath: $targetPath") + println("Filepath: $filePath") + + val testFileExemptiontextProto = "scripts/assets/test_file_exemptions" + + // A list of all the files to be exempted for this check. + // TODO(#3436): Develop a mechanism for permanently exempting files which do not ever need tests. + val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptiontextProto) + .getExemptedFilePathList() // println("test file exemption list: $testFileExemptionList") - val isExempted = testFileExemptionList.contains(filePath) - if(isExempted) { - println("This file is exempted from having a test file. Hence No coverage!") - return + val isExempted = testFileExemptionList.contains(filePath) + if (isExempted) { + println("This file is exempted from having a test file. Hence No coverage!") + return + } + + val testFilePath = findTestFile(repoRoot, filePath) + println("Test File paths list: $testFilePath") + + val result = bazelClient.retrieveBazelTargets(testFilePath) + println("Result from Retrieve Bazel Target; $result") + + val testResults = listOf( + "//utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest", + "//utility/src/test/java/org/oppia/android/util/math:FloatExtensionsTest") + + //.substringBeforeLast(".kt") + + for (r in testResults) { + RunCoverageForTestTarget( + rootDirectory, + r, + commandExecutor, + scriptBgDispatcher + ).runCoverage() + } } - val testFilePath = findTestFile(repoRoot, filePath) - println("Test File path: $testFilePath") // ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> // val commandExecutor: CommandExecutor = CommandExecutorImpl( @@ -63,6 +92,10 @@ private fun findTestFile(repoRoot: String, filePath: String): List { val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") + println("Shared: $sharedTestFilePath") + println("Test: $testFilePath") + println("LocalTest: $localTestFilePath") + if (File(repoRoot, sharedTestFilePath).exists()) { testFiles.add(sharedTestFilePath) } @@ -74,7 +107,7 @@ private fun findTestFile(repoRoot: String, filePath: String): List { } } else { val defaultTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") - if (File(defaultTestFilePath).exists()) { + if (File(repoRoot, defaultTestFilePath).exists()) { testFiles.add(defaultTestFilePath) } } From 9e78d1a9fbb29f7d4be748a54e78d1ea7e6ac328 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 19 Jun 2024 21:16:00 +0530 Subject: [PATCH 031/105] Added Kdoc and processTimeout custom argument with basic clean up --- .../android/scripts/coverage/RunCoverage.kt | 93 ++++++++----------- 1 file changed, 41 insertions(+), 52 deletions(-) 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 098e6b25c81..692f195ca18 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -9,72 +9,65 @@ import java.util.concurrent.TimeUnit import java.io.File import java.io.FileInputStream +/** + * Entry point function for running coverage analysis for a source file. + * + * Usage: + * bazel run //scripts:run_coverage_for_test_target -- + * + * Arguments: + * - path_to_root: directory path to the root of the Oppia Android repository. + * - relative_path_to_file: the relative path to the file to analyse coverage + * + * Example: + * bazel run //scripts:run_coverage -- $(pwd) + * utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt + * Example with custom process timeout: + * bazel run //scripts:run_coverage -- $(pwd) + * utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt processTimeout=10 + * + */ fun main(vararg args: String) { val repoRoot = args[0] - val rootDirectory = File(repoRoot).absoluteFile - val targetPath = args[1] - val filePath = args[2] + val filePath = args[1] - ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> - val commandExecutor: CommandExecutor = CommandExecutorImpl( - scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES - ) + val rootDirectory = File(repoRoot).absoluteFile - val bazelClient = BazelClient(rootDirectory, commandExecutor) + val testFileExemptiontextProto = "scripts/assets/test_file_exemptions" - println("Repo root: $repoRoot") - println("Targetpath: $targetPath") - println("Filepath: $filePath") + // A list of all the files to be exempted for this check. + val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptiontextProto) + .getExemptedFilePathList() - val testFileExemptiontextProto = "scripts/assets/test_file_exemptions" + val isExempted = testFileExemptionList.contains(filePath) + if (isExempted) { + println("This file is exempted from having a test file. Hence No coverage!") + return + } - // A list of all the files to be exempted for this check. - // TODO(#3436): Develop a mechanism for permanently exempting files which do not ever need tests. - val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptiontextProto) - .getExemptedFilePathList() + ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> + val processTimeout: Long = args.find { it.startsWith("processTimeout=") } + ?.substringAfter("=") + ?.toLongOrNull() ?: 5 -// println("test file exemption list: $testFileExemptionList") + val commandExecutor: CommandExecutor = CommandExecutorImpl( + scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES + ) - val isExempted = testFileExemptionList.contains(filePath) - if (isExempted) { - println("This file is exempted from having a test file. Hence No coverage!") - return - } + val bazelClient = BazelClient(rootDirectory, commandExecutor) val testFilePath = findTestFile(repoRoot, filePath) - println("Test File paths list: $testFilePath") - - val result = bazelClient.retrieveBazelTargets(testFilePath) - println("Result from Retrieve Bazel Target; $result") - - val testResults = listOf( - "//utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest", - "//utility/src/test/java/org/oppia/android/util/math:FloatExtensionsTest") - - //.substringBeforeLast(".kt") + val testTargets = bazelClient.retrieveBazelTargets(testFilePath) - for (r in testResults) { + for (testTarget in testTargets) { RunCoverageForTestTarget( rootDirectory, - r, + testTarget.substringBeforeLast(".kt"), commandExecutor, scriptBgDispatcher ).runCoverage() } } - - -// ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> -// val commandExecutor: CommandExecutor = CommandExecutorImpl( -// scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES -// ) - /*RunCoverageForTestTarget( - repoRoot, - targetPath, - commandExecutor, - scriptBgDispatcher - ).runCoverage()*/ -// } } private fun findTestFile(repoRoot: String, filePath: String): List { @@ -92,10 +85,6 @@ private fun findTestFile(repoRoot: String, filePath: String): List { val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") - println("Shared: $sharedTestFilePath") - println("Test: $testFilePath") - println("LocalTest: $localTestFilePath") - if (File(repoRoot, sharedTestFilePath).exists()) { testFiles.add(sharedTestFilePath) } @@ -126,4 +115,4 @@ private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): Tes builder.mergeFrom(it) }.build() as TestFileExemptions return protoObj -} \ No newline at end of file +} From cc5e9816c012f973d72f1718b376890b8069db0d Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 20 Jun 2024 08:33:34 +0530 Subject: [PATCH 032/105] Seperated logic as class and functions, introduced test file with setup and one test case for exemption test --- .../android/scripts/coverage/BUILD.bazel | 3 - .../android/scripts/coverage/RunCoverage.kt | 144 ++++++++++-------- .../android/scripts/coverage/BUILD.bazel | 13 ++ .../scripts/coverage/RunCoverageTest.kt | 67 ++++++++ 4 files changed, 164 insertions(+), 63 deletions(-) create mode 100644 scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 02ee6835fb0..7aba008aaa6 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -13,8 +13,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/common:git_client", - "//scripts/src/java/org/oppia/android/scripts/common:repository_file", "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", ], @@ -29,7 +27,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/common:git_client", "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", ], ) 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 692f195ca18..b9a6e96e89e 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -31,20 +31,6 @@ fun main(vararg args: String) { val repoRoot = args[0] val filePath = args[1] - val rootDirectory = File(repoRoot).absoluteFile - - val testFileExemptiontextProto = "scripts/assets/test_file_exemptions" - - // A list of all the files to be exempted for this check. - val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptiontextProto) - .getExemptedFilePathList() - - val isExempted = testFileExemptionList.contains(filePath) - if (isExempted) { - println("This file is exempted from having a test file. Hence No coverage!") - return - } - ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> val processTimeout: Long = args.find { it.startsWith("processTimeout=") } ?.substringAfter("=") @@ -54,10 +40,48 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - val bazelClient = BazelClient(rootDirectory, commandExecutor) + RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute() + } +} + +/** + * Class responsible for executing coverage on a given file. + * + * @param repoRoot the root directory of the repository + * @param filePath the relative path to the file to analyse coverage + * @param commandExecutor Executes the specified command in the specified working directory + * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command + */ +class RunCoverage( + private val repoRoot: String, + private val filePath: String, + private val commandExecutor: CommandExecutor, + private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher +) { + private val rootDirectory = File(repoRoot).absoluteFile + private val testFileExemptionTextProto = "scripts/assets/test_file_exemptions" + + /** + * Executes coverage analysis for the specified file. + * + * Loads test file exemptions and checks if the specified file is exempted. If exempted, + * prints a message indicating no coverage analysis is performed. Otherwise, initializes + * a Bazel client, finds potential test file paths, retrieves Bazel targets, and initiates + * coverage analysis for each test target found. + */ + fun execute() { + val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) + .getExemptedFilePathList() + + val isExempted = testFileExemptionList.contains(filePath) + if (isExempted) { + println("This file is exempted from having a test file. Hence No coverage!") + return + } - val testFilePath = findTestFile(repoRoot, filePath) - val testTargets = bazelClient.retrieveBazelTargets(testFilePath) + val bazelClient = BazelClient(rootDirectory, commandExecutor) + val testFilePaths = findTestFile(repoRoot, filePath) + val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) for (testTarget in testTargets) { RunCoverageForTestTarget( @@ -68,51 +92,51 @@ fun main(vararg args: String) { ).runCoverage() } } -} - -private fun findTestFile(repoRoot: String, filePath: String): List { - val file = File(filePath) - val parts = file.parent.split(File.separator) - val testFiles = mutableListOf() - - if (parts.isNotEmpty() && parts[0] == "scripts") { - val testFilePath = filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt") - if (File(testFilePath).exists()) { - testFiles.add(testFilePath) - } - } else if (parts.isNotEmpty() && parts[0] == "app") { - val sharedTestFilePath = filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt") - val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") - val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") - if (File(repoRoot, sharedTestFilePath).exists()) { - testFiles.add(sharedTestFilePath) - } - if (File(repoRoot, testFilePath).exists()) { - testFiles.add(testFilePath) - } - if (File(repoRoot, localTestFilePath).exists()) { - testFiles.add(localTestFilePath) - } - } else { - val defaultTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") - if (File(repoRoot, defaultTestFilePath).exists()) { - testFiles.add(defaultTestFilePath) + private fun findTestFile(repoRoot: String, filePath: String): List { + val file = File(filePath) + val parts = file.parent.split(File.separator) + val testFiles = mutableListOf() + + if (parts.isNotEmpty() && parts[0] == "scripts") { + val testFilePath = filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt") + if (File(testFilePath).exists()) { + testFiles.add(testFilePath) + } + } else if (parts.isNotEmpty() && parts[0] == "app") { + val sharedTestFilePath = filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt") + val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") + val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") + + if (File(repoRoot, sharedTestFilePath).exists()) { + testFiles.add(sharedTestFilePath) + } + if (File(repoRoot, testFilePath).exists()) { + testFiles.add(testFilePath) + } + if (File(repoRoot, localTestFilePath).exists()) { + testFiles.add(localTestFilePath) + } + } else { + val defaultTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") + if (File(repoRoot, defaultTestFilePath).exists()) { + testFiles.add(defaultTestFilePath) + } } + return testFiles } - return testFiles -} - -private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { - val protoBinaryFile = File("$testFileExemptiontextProto.pb") - val builder = TestFileExemptions.getDefaultInstance().newBuilderForType() - // This cast is type-safe since proto guarantees type consistency from mergeFrom(), - // and this method is bounded by the generic type T. - @Suppress("UNCHECKED_CAST") - val protoObj: TestFileExemptions = - FileInputStream(protoBinaryFile).use { - builder.mergeFrom(it) - }.build() as TestFileExemptions - return protoObj + private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { + val protoBinaryFile = File("$testFileExemptiontextProto.pb") + val builder = TestFileExemptions.getDefaultInstance().newBuilderForType() + + // This cast is type-safe since proto guarantees type consistency from mergeFrom(), + // and this method is bounded by the generic type T. + @Suppress("UNCHECKED_CAST") + val protoObj: TestFileExemptions = + FileInputStream(protoBinaryFile).use { + builder.mergeFrom(it) + }.build() as TestFileExemptions + return protoObj + } } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel index cb20129dd61..49226a9e4f7 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel @@ -27,3 +27,16 @@ kt_jvm_test( "//third_party:org_jetbrains_kotlin_kotlin-test-junit", ], ) + +kt_jvm_test( + name = "RunCoverageTest", + srcs = ["RunCoverageTest.kt"], + deps = [ + "//scripts:test_file_check_assets", + "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_lib", + "//scripts/src/java/org/oppia/android/scripts/testing:test_bazel_workspace", + "//testing:assertion_helpers", + "//third_party:com_google_truth_truth", + "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + ], +) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt new file mode 100644 index 00000000000..aded2fffb2a --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -0,0 +1,67 @@ +package org.oppia.android.scripts.coverage + +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import org.oppia.android.scripts.common.CommandExecutorImpl +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.scripts.testing.TestBazelWorkspace +import org.oppia.android.testing.assertThrows +import java.util.concurrent.TimeUnit +import java.io.ByteArrayOutputStream +import java.io.PrintStream + +/** Tests for [RunCoverage]. */ +class RunCoverageTest { + @field:[Rule JvmField] val tempFolder = TemporaryFolder() + + private val outContent: ByteArrayOutputStream = ByteArrayOutputStream() + private val originalOut: PrintStream = System.out + + private val scriptBgDispatcher by lazy { ScriptBackgroundCoroutineDispatcher() } + private val commandExecutor by lazy { CommandExecutorImpl(scriptBgDispatcher) } + private val longCommandExecutor by lazy { initializeCommandExecutorWithLongProcessWaitTime() } + + private lateinit var testBazelWorkspace: TestBazelWorkspace + private lateinit var bazelTestTarget: String + + @Before + fun setUp() { + bazelTestTarget = "//:testTarget" + testBazelWorkspace = TestBazelWorkspace(tempFolder) + System.setOut(PrintStream(outContent)) + } + + @After + fun tearDown() { + System.setOut(originalOut) + scriptBgDispatcher.close() + } + + @Test + fun testRunCoverage_testFileExempted_noCoverage() { + val exemptedFilePath = "app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt" + + runScript(exemptedFilePath) + + assertThat(outContent.toString()).isEqualTo("This file is exempted from having a test file. Hence No coverage!\n") + } + + private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { + return CommandExecutorImpl( + scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES + ) + } + + /** Runs the run_coverage. */ + private fun runScript(filePath: String) { + RunCoverage( + "${tempFolder.root}", + filePath, + commandExecutor, + scriptBgDispatcher).execute() + } +} From 5075a1a15f274a77532ca14258d26ecae8e6b5b1 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 20 Jun 2024 10:18:18 +0530 Subject: [PATCH 033/105] Added tests for findTestFile() --- .../android/scripts/coverage/RunCoverage.kt | 4 +- .../scripts/coverage/RunCoverageTest.kt | 125 +++++++++++++++++- 2 files changed, 124 insertions(+), 5 deletions(-) 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 b9a6e96e89e..9e927ca1b6a 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -93,14 +93,14 @@ class RunCoverage( } } - private fun findTestFile(repoRoot: String, filePath: String): List { + fun findTestFile(repoRoot: String, filePath: String): List { val file = File(filePath) val parts = file.parent.split(File.separator) val testFiles = mutableListOf() if (parts.isNotEmpty() && parts[0] == "scripts") { val testFilePath = filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt") - if (File(testFilePath).exists()) { + if (File(repoRoot, testFilePath).exists()) { testFiles.add(testFilePath) } } else if (parts.isNotEmpty() && parts[0] == "app") { diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index aded2fffb2a..717049da50f 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -2,6 +2,7 @@ package org.oppia.android.scripts.coverage import com.google.common.truth.Truth.assertThat import org.junit.After +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule import org.junit.Test @@ -12,6 +13,7 @@ import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import java.util.concurrent.TimeUnit import java.io.ByteArrayOutputStream +import java.io.File import java.io.PrintStream /** Tests for [RunCoverage]. */ @@ -26,11 +28,11 @@ class RunCoverageTest { private val longCommandExecutor by lazy { initializeCommandExecutorWithLongProcessWaitTime() } private lateinit var testBazelWorkspace: TestBazelWorkspace - private lateinit var bazelTestTarget: String + private lateinit var sampleFilePath: String @Before fun setUp() { - bazelTestTarget = "//:testTarget" + sampleFilePath = "/path/to/Sample.kt" testBazelWorkspace = TestBazelWorkspace(tempFolder) System.setOut(PrintStream(outContent)) } @@ -45,11 +47,128 @@ class RunCoverageTest { fun testRunCoverage_testFileExempted_noCoverage() { val exemptedFilePath = "app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt" - runScript(exemptedFilePath) + RunCoverage( + "${tempFolder.root}", + exemptedFilePath, + commandExecutor, + scriptBgDispatcher).execute() assertThat(outContent.toString()).isEqualTo("This file is exempted from having a test file. Hence No coverage!\n") } + @Test + fun testRunCoverage_ScriptsPath_returnTestFilePath() { + val rootFolderPath = tempFolder.root.absolutePath + val expectedTestFilePath = "scripts/javatests/sample/ExampleTest.kt" + val file = File(rootFolderPath, expectedTestFilePath) + + file.parentFile?.mkdirs() + file.createNewFile() + + val expectedTestFilePaths = listOf(expectedTestFilePath) + + val result = RunCoverage( + rootFolderPath, + sampleFilePath, + commandExecutor, + scriptBgDispatcher + ).findTestFile(rootFolderPath, "scripts/java/sample/Example.kt") + + assertEquals(expectedTestFilePaths, result) + } + + @Test + fun testRunCoverage_AppPath_returnSharedTestFilePath() { + val rootFolderPath = tempFolder.root.absolutePath + val expectedSharedTestFilePath = "app/sharedTest/sample/ExampleTest.kt" + val file = File(rootFolderPath, expectedSharedTestFilePath) + + file.parentFile?.mkdirs() + file.createNewFile() + + val expectedSharedTestFilePaths = listOf(expectedSharedTestFilePath) + + val result = RunCoverage( + rootFolderPath, + sampleFilePath, + commandExecutor, + scriptBgDispatcher + ).findTestFile(rootFolderPath, "app/main/sample/Example.kt") + + assertEquals(expectedSharedTestFilePaths, result) + } + + @Test + fun testRunCoverage_AppPath_returnLocalTestFilePath() { + val rootFolderPath = tempFolder.root.absolutePath + val expectedLocalTestFilePath = "app/test/sample/ExampleTest.kt" + val file = File(rootFolderPath, expectedLocalTestFilePath) + + file.parentFile?.mkdirs() + file.createNewFile() + + val expectedLocalTestFilePaths = listOf(expectedLocalTestFilePath) + + val result = RunCoverage( + rootFolderPath, + sampleFilePath, + commandExecutor, + scriptBgDispatcher + ).findTestFile(rootFolderPath, "app/main/sample/Example.kt") + + assertEquals(expectedLocalTestFilePaths, result) + } + + @Test + fun testRunCoverage_AppPath_returnSharedAndLocalTestFilePath() { + val rootFolderPath = tempFolder.root.absolutePath + val expectedLocalTestFilePath = "app/test/sample/ExampleTest.kt" + val expectedSharedTestFilePath = "app/sharedTest/sample/ExampleTest.kt" + + val sharedFile = File(rootFolderPath, expectedSharedTestFilePath) + sharedFile.parentFile?.mkdirs() + sharedFile.createNewFile() + + val localFile = File(rootFolderPath, expectedLocalTestFilePath) + localFile.parentFile?.mkdirs() + localFile.createNewFile() + + val expectedLocalAndSharedTestFilePaths = listOf( + expectedSharedTestFilePath, + expectedLocalTestFilePath + ) + + val result = RunCoverage( + rootFolderPath, + sampleFilePath, + commandExecutor, + scriptBgDispatcher + ).findTestFile(rootFolderPath, "app/main/sample/Example.kt") + + assertEquals(expectedLocalAndSharedTestFilePaths, result) + } + + @Test + fun testRunCoverage_AppPath_returnDefaultTestFilePath() { + val rootFolderPath = tempFolder.root.absolutePath + val expectedLocalTestFilePath = "util/test/sample/ExampleTest.kt" + val file = File(rootFolderPath, expectedLocalTestFilePath) + + file.parentFile?.mkdirs() + file.createNewFile() + + val expectedLocalTestFilePaths = listOf(expectedLocalTestFilePath) + + val result = RunCoverage( + rootFolderPath, + sampleFilePath, + commandExecutor, + scriptBgDispatcher + ).findTestFile(rootFolderPath, "util/main/sample/Example.kt") + + assertEquals(expectedLocalTestFilePaths, result) + } + private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { return CommandExecutorImpl( scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES From fdaf9cb5bddbc229dc63e4085b4f3c6f255c6b9d Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 20 Jun 2024 16:11:33 +0530 Subject: [PATCH 034/105] Added tests case for RunCoverage to check execution of coverage and fixed other test cases with appropriate testFileName implementation --- .../android/scripts/coverage/RunCoverage.kt | 30 +++++- .../scripts/testing/TestBazelWorkspace.kt | 2 +- .../android/scripts/common/BazelClientTest.kt | 2 +- .../scripts/coverage/CoverageRunnerTest.kt | 8 +- .../coverage/RunCoverageForTestTargetTest.kt | 2 +- .../scripts/coverage/RunCoverageTest.kt | 101 ++++++++++++++++++ 6 files changed, 133 insertions(+), 12 deletions(-) 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 9e927ca1b6a..adb9b266132 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -58,8 +58,12 @@ class RunCoverage( private val commandExecutor: CommandExecutor, private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher ) { + private val bazelClient by lazy { BazelClient(File(repoRoot), commandExecutor) } + private val rootDirectory = File(repoRoot).absoluteFile private val testFileExemptionTextProto = "scripts/assets/test_file_exemptions" + var coverageDataList = mutableListOf() +// var covdat: String = "" /** * Executes coverage analysis for the specified file. @@ -69,28 +73,44 @@ class RunCoverage( * a Bazel client, finds potential test file paths, retrieves Bazel targets, and initiates * coverage analysis for each test target found. */ - fun execute() { + fun execute(): List { val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() val isExempted = testFileExemptionList.contains(filePath) if (isExempted) { println("This file is exempted from having a test file. Hence No coverage!") - return +// return null + return emptyList() } - val bazelClient = BazelClient(rootDirectory, commandExecutor) +// val bazelClient = BazelClient(rootDirectory, commandExecutor) val testFilePaths = findTestFile(repoRoot, filePath) +// return findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) +// val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) for (testTarget in testTargets) { - RunCoverageForTestTarget( + val coverageData = RunCoverageForTestTarget( rootDirectory, testTarget.substringBeforeLast(".kt"), commandExecutor, scriptBgDispatcher - ).runCoverage() + ).runCoverage()!! + coverageDataList.add(coverageData) } + return coverageDataList + + //this works + /*val covdat = RunCoverageForTestTarget( + rootDirectory, + "//coverage/test/java/com/example:test", + commandExecutor, + scriptBgDispatcher + ).runCoverage() + coverageDataList.add(covdat!!) + return coverageDataList*/ +// return covdat } fun findTestFile(repoRoot: String, filePath: String): List { diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 71ee2eb542a..83d802f3b89 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -172,7 +172,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { testBuildFile.appendText( """ kt_jvm_test( - name = "test", + name = "$testName", srcs = ["$testName.kt"], deps = [ "//$sourceSubpackage:${filename.lowercase()}", diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 4bbde885d47..bf99a7e3577 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -512,7 +512,7 @@ class BazelClientTest { subpackage = "coverage" ) - val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test") + val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:TwoSumTest") // Check if ByteArray is returned from executing coverage command assertThat(result).isInstanceOf(ByteArray::class.java) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 6892535c598..7560e0ad158 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -36,7 +36,7 @@ class CoverageRunnerTest { } @Test - fun testRunCoverage_emptyDirectory_throwsException() { + fun testCoverageRunner_emptyDirectory_throwsException() { val exception = assertThrows() { coverageRunner.getCoverage(bazelTestTarget) } @@ -45,7 +45,7 @@ class CoverageRunnerTest { } @Test - fun testRunCoverage_invalidTestTarget_throwsException() { + fun testCoverageRunner_invalidTestTarget_throwsException() { testBazelWorkspace.initEmptyWorkspace() val exception = assertThrows() { @@ -57,7 +57,7 @@ class CoverageRunnerTest { } @Test - fun testRunCoverage_validSampleTestTarget_returnsCoverageData() { + fun testCoverageRunner_validSampleTestTarget_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -103,7 +103,7 @@ class CoverageRunnerTest { subpackage = "coverage" ) - val result = coverageRunner.getCoverage("//coverage/test/java/com/example:test") + val result = coverageRunner.getCoverage("//coverage/test/java/com/example:TwoSumTest") val expectedResult = "SF:coverage/main/java/com/example/TwoSum.kt\n" + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index df2390a5efc..4210e54accf 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -114,7 +114,7 @@ class RunCoverageForTestTargetTest { val result = RunCoverageForTestTarget( tempFolder.root, - "//coverage/test/java/com/example:test", + "//coverage/test/java/com/example:TwoSumTest", longCommandExecutor, scriptBgDispatcher ).runCoverage() diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 717049da50f..fa4928f0aa5 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -169,6 +169,107 @@ class RunCoverageTest { assertEquals(expectedLocalTestFilePaths, result) } + @Test + fun testRunCoverage_validSampleTestFile_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + sourceContent = sourceContent, + testContent = testContent, + subpackage = "coverage" + ) + + val result = RunCoverage( + "${tempFolder.root}", + "coverage/main/java/com/example/TwoSum.kt", + longCommandExecutor, + scriptBgDispatcher).execute() + + /*val expectedResult = + "["+"SF:coverage/main/java/com/example/TwoSum.kt\n" + + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FN:3,com/example/TwoSum:: ()V\n" + + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FNDA:0,com/example/TwoSum:: ()V\n" + + "FNF:2\n" + + "FNH:1\n" + + "BRDA:7,0,0,1\n" + + "BRDA:7,0,1,1\n" + + "BRDA:7,0,2,1\n" + + "BRDA:7,0,3,1\n" + + "BRF:4\n" + + "BRH:4\n" + + "DA:3,0\n" + + "DA:7,1\n" + + "DA:8,1\n" + + "DA:10,1\n" + + "LH:3\n" + + "LF:4\n" + + "end_of_record\n"+"]"*/ + + val expectedResultList = listOf( + "SF:coverage/main/java/com/example/TwoSum.kt\n"+ + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n"+ + "FN:3,com/example/TwoSum:: ()V\n"+ + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n"+ + "FNDA:0,com/example/TwoSum:: ()V\n"+ + "FNF:2\n"+ + "FNH:1\n"+ + "BRDA:7,0,0,1\n"+ + "BRDA:7,0,1,1\n"+ + "BRDA:7,0,2,1\n"+ + "BRDA:7,0,3,1\n"+ + "BRF:4\n"+ + "BRH:4\n"+ + "DA:3,0\n"+ + "DA:7,1\n"+ + "DA:8,1\n"+ + "DA:10,1\n"+ + "LH:3\n"+ + "LF:4\n"+ + "end_of_record\n" + ) + + assertThat(result).isEqualTo(expectedResultList) + } + private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { return CommandExecutorImpl( scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES From 8e28f1d220307479b85dab629c14942cd7905678 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 20 Jun 2024 18:15:18 +0530 Subject: [PATCH 035/105] Cleanup of RunCoverageTest --- .../android/scripts/coverage/RunCoverage.kt | 15 --------- .../scripts/coverage/RunCoverageTest.kt | 31 ------------------- 2 files changed, 46 deletions(-) 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 adb9b266132..fb46019d694 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -80,15 +80,11 @@ class RunCoverage( val isExempted = testFileExemptionList.contains(filePath) if (isExempted) { println("This file is exempted from having a test file. Hence No coverage!") -// return null return emptyList() } -// val bazelClient = BazelClient(rootDirectory, commandExecutor) val testFilePaths = findTestFile(repoRoot, filePath) -// return findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) -// val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) for (testTarget in testTargets) { val coverageData = RunCoverageForTestTarget( @@ -100,17 +96,6 @@ class RunCoverage( coverageDataList.add(coverageData) } return coverageDataList - - //this works - /*val covdat = RunCoverageForTestTarget( - rootDirectory, - "//coverage/test/java/com/example:test", - commandExecutor, - scriptBgDispatcher - ).runCoverage() - coverageDataList.add(covdat!!) - return coverageDataList*/ -// return covdat } fun findTestFile(repoRoot: String, filePath: String): List { diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index fa4928f0aa5..506a9bcb1c1 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -222,28 +222,6 @@ class RunCoverageTest { longCommandExecutor, scriptBgDispatcher).execute() - /*val expectedResult = - "["+"SF:coverage/main/java/com/example/TwoSum.kt\n" + - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FN:3,com/example/TwoSum:: ()V\n" + - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FNDA:0,com/example/TwoSum:: ()V\n" + - "FNF:2\n" + - "FNH:1\n" + - "BRDA:7,0,0,1\n" + - "BRDA:7,0,1,1\n" + - "BRDA:7,0,2,1\n" + - "BRDA:7,0,3,1\n" + - "BRF:4\n" + - "BRH:4\n" + - "DA:3,0\n" + - "DA:7,1\n" + - "DA:8,1\n" + - "DA:10,1\n" + - "LH:3\n" + - "LF:4\n" + - "end_of_record\n"+"]"*/ - val expectedResultList = listOf( "SF:coverage/main/java/com/example/TwoSum.kt\n"+ "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n"+ @@ -275,13 +253,4 @@ class RunCoverageTest { scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES ) } - - /** Runs the run_coverage. */ - private fun runScript(filePath: String) { - RunCoverage( - "${tempFolder.root}", - filePath, - commandExecutor, - scriptBgDispatcher).execute() - } } From 92bf2669e776b8573fc515a8d6c3c1b84034a4c6 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 20 Jun 2024 21:07:02 +0530 Subject: [PATCH 036/105] Fix kdoc lint checks and TestBazelWorkspace Tests --- .../android/scripts/coverage/RunCoverage.kt | 12 +++- .../scripts/coverage/RunCoverageTest.kt | 58 ++++++++++--------- .../scripts/testing/TestBazelWorkspaceTest.kt | 4 +- 3 files changed, 41 insertions(+), 33 deletions(-) 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 fb46019d694..924f29c0b33 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -5,9 +5,9 @@ import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.proto.TestFileExemptions -import java.util.concurrent.TimeUnit import java.io.File import java.io.FileInputStream +import java.util.concurrent.TimeUnit /** * Entry point function for running coverage analysis for a source file. @@ -40,7 +40,7 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute() + RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute() } } @@ -63,7 +63,6 @@ class RunCoverage( private val rootDirectory = File(repoRoot).absoluteFile private val testFileExemptionTextProto = "scripts/assets/test_file_exemptions" var coverageDataList = mutableListOf() -// var covdat: String = "" /** * Executes coverage analysis for the specified file. @@ -98,6 +97,13 @@ class RunCoverage( return coverageDataList } + /** + * Finds potential test file paths corresponding to a given source file path within a repository. + * + * @param repoRoot the root directory of the repository + * @param filePath The file path of the source file for which the test files are to be found. + * @return A list of potential test file paths that exist in the repository. + */ fun findTestFile(repoRoot: String, filePath: String): List { val file = File(filePath) val parts = file.parent.split(File.separator) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 506a9bcb1c1..1a2fd495f77 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -10,11 +10,10 @@ import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace -import org.oppia.android.testing.assertThrows -import java.util.concurrent.TimeUnit import java.io.ByteArrayOutputStream import java.io.File import java.io.PrintStream +import java.util.concurrent.TimeUnit /** Tests for [RunCoverage]. */ class RunCoverageTest { @@ -51,9 +50,11 @@ class RunCoverageTest { "${tempFolder.root}", exemptedFilePath, commandExecutor, - scriptBgDispatcher).execute() + scriptBgDispatcher + ).execute() - assertThat(outContent.toString()).isEqualTo("This file is exempted from having a test file. Hence No coverage!\n") + assertThat(outContent.toString()) + .isEqualTo("This file is exempted from having a test file. Hence No coverage!\n") } @Test @@ -220,30 +221,31 @@ class RunCoverageTest { "${tempFolder.root}", "coverage/main/java/com/example/TwoSum.kt", longCommandExecutor, - scriptBgDispatcher).execute() - - val expectedResultList = listOf( - "SF:coverage/main/java/com/example/TwoSum.kt\n"+ - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n"+ - "FN:3,com/example/TwoSum:: ()V\n"+ - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n"+ - "FNDA:0,com/example/TwoSum:: ()V\n"+ - "FNF:2\n"+ - "FNH:1\n"+ - "BRDA:7,0,0,1\n"+ - "BRDA:7,0,1,1\n"+ - "BRDA:7,0,2,1\n"+ - "BRDA:7,0,3,1\n"+ - "BRF:4\n"+ - "BRH:4\n"+ - "DA:3,0\n"+ - "DA:7,1\n"+ - "DA:8,1\n"+ - "DA:10,1\n"+ - "LH:3\n"+ - "LF:4\n"+ - "end_of_record\n" - ) + scriptBgDispatcher + ).execute() + + val expectedResultList = listOf( + "SF:coverage/main/java/com/example/TwoSum.kt\n" + + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FN:3,com/example/TwoSum:: ()V\n" + + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FNDA:0,com/example/TwoSum:: ()V\n" + + "FNF:2\n" + + "FNH:1\n" + + "BRDA:7,0,0,1\n" + + "BRDA:7,0,1,1\n" + + "BRDA:7,0,2,1\n" + + "BRDA:7,0,3,1\n" + + "BRF:4\n" + + "BRH:4\n" + + "DA:3,0\n" + + "DA:7,1\n" + + "DA:8,1\n" + + "DA:10,1\n" + + "LH:3\n" + + "LF:4\n" + + "end_of_record\n" + ) assertThat(result).isEqualTo(expectedResultList) } diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index 9d6a33378d6..d62bbf11501 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -338,7 +338,7 @@ class TestBazelWorkspaceTest { """ load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") kt_jvm_test( - name = "test", + name = "MainTest", srcs = ["MainTest.kt"], deps = [ "//coverage/main/java/com/example:main", @@ -406,7 +406,7 @@ class TestBazelWorkspaceTest { """ load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") kt_jvm_test( - name = "test", + name = "MainTest", srcs = ["MainTest.kt"], deps = [ "//coverage/main/java/com/example:main", From eb7cdc21da6c9c4ddffb152aeafe28b96b342a3c Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 21 Jun 2024 00:09:23 +0530 Subject: [PATCH 037/105] Fix Lint Checks on indentation --- .../android/scripts/coverage/RunCoverage.kt | 2 +- .../scripts/coverage/RunCoverageTest.kt | 38 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) 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 924f29c0b33..380d8adb27e 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -62,7 +62,6 @@ class RunCoverage( private val rootDirectory = File(repoRoot).absoluteFile private val testFileExemptionTextProto = "scripts/assets/test_file_exemptions" - var coverageDataList = mutableListOf() /** * Executes coverage analysis for the specified file. @@ -73,6 +72,7 @@ class RunCoverage( * coverage analysis for each test target found. */ fun execute(): List { + var coverageDataList = mutableListOf() val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 1a2fd495f77..2d2a58dce25 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -226,25 +226,25 @@ class RunCoverageTest { val expectedResultList = listOf( "SF:coverage/main/java/com/example/TwoSum.kt\n" + - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FN:3,com/example/TwoSum:: ()V\n" + - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FNDA:0,com/example/TwoSum:: ()V\n" + - "FNF:2\n" + - "FNH:1\n" + - "BRDA:7,0,0,1\n" + - "BRDA:7,0,1,1\n" + - "BRDA:7,0,2,1\n" + - "BRDA:7,0,3,1\n" + - "BRF:4\n" + - "BRH:4\n" + - "DA:3,0\n" + - "DA:7,1\n" + - "DA:8,1\n" + - "DA:10,1\n" + - "LH:3\n" + - "LF:4\n" + - "end_of_record\n" + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FN:3,com/example/TwoSum:: ()V\n" + + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + + "FNDA:0,com/example/TwoSum:: ()V\n" + + "FNF:2\n" + + "FNH:1\n" + + "BRDA:7,0,0,1\n" + + "BRDA:7,0,1,1\n" + + "BRDA:7,0,2,1\n" + + "BRDA:7,0,3,1\n" + + "BRF:4\n" + + "BRH:4\n" + + "DA:3,0\n" + + "DA:7,1\n" + + "DA:8,1\n" + + "DA:10,1\n" + + "LH:3\n" + + "LF:4\n" + + "end_of_record\n" ) assertThat(result).isEqualTo(expectedResultList) From ee078e299a707ecdee4fbdc700ab2bc27360d900 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 21 Jun 2024 18:31:41 +0530 Subject: [PATCH 038/105] Refactored BazelClient coverage execution to return data as list of strings, made helper methods private and updated the related tests --- .../android/scripts/common/BazelClient.kt | 29 +++-- .../scripts/coverage/CoverageRunner.kt | 25 +--- .../coverage/RunCoverageForTestTarget.kt | 5 +- .../android/scripts/common/BazelClientTest.kt | 109 ++++-------------- .../scripts/coverage/CoverageRunnerTest.kt | 60 ++++++---- .../coverage/RunCoverageForTestTargetTest.kt | 43 +++---- 6 files changed, 108 insertions(+), 163 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 39fe26eff19..1d0553ecfe4 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -136,16 +136,21 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * Runs code coverage for the specified Bazel test target. * * @param bazelTestTarget Bazel test target for which code coverage will be run - * @return the coverage data file path generated from bazel coverage + * @return the generated coverage data as a list of strings + * or null if the coverage data file could not be parsed. + * + * Null return typically occurs when the coverage command fails to generate the 'coverage.dat' file. + * This can happen due to: Test failures or misconfigurations that prevent the coverage data + * from being generated properly. */ - fun runCoverageForTestTarget(bazelTestTarget: String): ByteArray? { + fun runCoverageForTestTarget(bazelTestTarget: String): List? { val coverageData = executeBazelCommand( "coverage", bazelTestTarget ) - val coverageDataFilePath = parseCoverageDataFile(coverageData) - val coverageDataFileContent = readDatFileAsBinary(coverageDataFilePath!!) - return coverageDataFileContent + return parseCoverageDataFile(coverageData)?.let { path -> + readDatFile(path) + } } /** @@ -154,7 +159,7 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * @param data the result from the execution of the coverage command * @return the extracted path of the coverage data file. */ - fun parseCoverageDataFile(data: List): String? { + private fun parseCoverageDataFile(data: List): String? { val regex = ".*coverage\\.dat$".toRegex() for (line in data) { val match = regex.find(line) @@ -168,14 +173,16 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: } /** - * Reads the content of the .dat file as a binary blob. + * Reads the content of the .dat file as a list of lines. * * @param filePath path to the .dat file - * @return content of the .dat file as binary data + * @return content of the .dat file as a list of strings */ - fun readDatFileAsBinary(filePath: String?): ByteArray? { - val path = Paths.get(filePath!!) - return Files.readAllBytes(path!!) + private fun readDatFile(filePath: String?): List? { + return filePath?.let { path -> + val pathObj = Paths.get(path) + File(pathObj.toUri()).readLines() + } } /** 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 5274ff92bbb..7339dcc2bab 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -26,13 +26,13 @@ class CoverageRunner( * Runs coverage analysis asynchronously for the Bazel test target. * * @param bazelTestTarget Bazel test target to analyze coverage. - * @return a deferred value that contains the coverage data [will contain the proto for the coverage data]. + * @return a deferred value that contains the coverage data. */ fun runWithCoverageAsync( bazelTestTarget: String - ): Deferred { + ): Deferred?> { return CoroutineScope(scriptBgDispatcher).async { - val coverageDataFilePath = getCoverage(bazelTestTarget) + val coverageDataFilePath = retrieveCoverageResult(bazelTestTarget) coverageDataFilePath } } @@ -43,22 +43,9 @@ class CoverageRunner( * @param bazelTestTarget Bazel test target to analyze coverage. * @return the generated coverage data as a string. */ - fun getCoverage( + private fun retrieveCoverageResult( bazelTestTarget: String - ): String? { - val coverageDataBinary = bazelClient.runCoverageForTestTarget(bazelTestTarget) - val coverageDataString = convertByteArrayToString(coverageDataBinary!!) - - return coverageDataString - } - - /** - * Converts a ByteArray to a String using UTF-8 encoding. - * - * @param coverageBinaryData byte array to convert - * @return string representation of the byte array - */ - fun convertByteArrayToString(coverageBinaryData: ByteArray?): String? { - return String(coverageBinaryData!!, Charsets.UTF_8) + ): List? { + return bazelClient.runCoverageForTestTarget(bazelTestTarget) } } diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index 7010dbf7f45..e5e1bdccd45 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -53,6 +53,7 @@ fun main(vararg args: String) { * @param repoRoot the root directory of the repository * @param targetPath Bazel test target to analyze coverage * @param commandExecutor Executes the specified command in the specified working directory + * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command */ class RunCoverageForTestTarget( private val repoRoot: File, @@ -64,7 +65,7 @@ class RunCoverageForTestTarget( /** * Analyzes target file for coverage, generates chosen reports accordingly. */ - fun runCoverage(): String? { + fun runCoverage(): List? { return runWithCoverageAnalysis() } @@ -73,7 +74,7 @@ class RunCoverageForTestTarget( * * @return the generated coverage data. */ - fun runWithCoverageAnalysis(): String? { + fun runWithCoverageAnalysis(): List? { return runBlocking { val result = CoverageRunner(repoRoot, scriptBgDispatcher, commandExecutor) diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 4bbde885d47..1c3b0adad21 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -380,90 +380,6 @@ class BazelClientTest { assertThat(thirdPartyDependenciesList).doesNotContain("@maven//:androidx_annotation_annotation") } - @Test - fun testParseCoverageDataFile_invalidData_returnsNull() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - // Result data from coverage execution that doesn't contain path to coverage data file [coverage.dat] - val invalidResultData = listOf("data1", "data2", "data3") - - val parsedData = bazelClient.parseCoverageDataFile(invalidResultData) - // Return Null when the coverage data file path is not found - assertThat(parsedData).isNull() - } - - @Test - fun testParseCoverageDataFile_validData_returnsNull() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - // Result data from coverage execution that contains path to coverage data file [coverage.dat] - val validResultData = listOf( - "//package/test/example:test PASSED in 0.4s", - "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat", - "Executed 1 out of 1 test: 1 test passes." - ) - val expectedResultParsedData = - "/path/.cache/bazel/4654367352564/sandbox/__main__/__tmp/coverage/package/test/coverage.dat" - - val parsedData = bazelClient.parseCoverageDataFile(validResultData) - assertThat(parsedData).isEqualTo(expectedResultParsedData) - } - - @Test - fun testReadDatFileAsBinary_WithValidCoverageDatFile_returnsBinaryData() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - // Create a temporary coverage.dat file with sample data - val tempFile = tempFolder.newFile("coverage.dat") - val content = - """ - SF:/path/to/sourcefile.kt - FN:3,com/example/source:: ()V - FNF:1 - FNH:1 - DA:3,0 - DA:6,1 - LF:6 - end_of_record - """.trimIndent() - tempFile.appendText(content) - - // Call the function with the valid file path - val result = bazelClient.readDatFileAsBinary(tempFile.toPath().toString()) - - // Assert the content matches - assertThat(result).isEqualTo(content.toByteArray()) - } - - @Test - fun testReadDatFileAsBinary_WithNullFilePath_throwsException() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - - assertThrows() { - bazelClient.readDatFileAsBinary(null) - } - } - - @Test - fun testReadDatFileAsBinary_WithInvalidFilePath_throwsException() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - val invalidFilePath = "invalid_coverage.dat" - - assertThrows() { - bazelClient.readDatFileAsBinary(invalidFilePath) - } - } - - @Test - fun testReadDatFileAsBinary_WithEmptyCoverageDatFile_returnsEmptyBinaryData() { - val bazelClient = BazelClient(tempFolder.root, commandExecutor) - // Create a temporary coverage.dat file with empty data - val tempFile = tempFolder.newFile("coverage.dat") - - // Call the function with the valid file path - val result = bazelClient.readDatFileAsBinary(tempFile.toPath().toString()) - - // Assert the content matches - assertThat(result).isEqualTo(ByteArray(0)) - } - @Test fun testRunCodeCoverage_forSampleTestTarget_returnsCoverageResult() { val bazelClient = BazelClient(tempFolder.root, longCommandExecutor) @@ -513,9 +429,30 @@ class BazelClientTest { ) val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:test") + val expectedResult = listOf( + "SF:coverage/main/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ) - // Check if ByteArray is returned from executing coverage command - assertThat(result).isInstanceOf(ByteArray::class.java) + assertThat(result).isEqualTo(expectedResult) } @Test diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 6892535c598..172916db920 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -1,11 +1,14 @@ package org.oppia.android.scripts.coverage import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.runBlocking import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import kotlinx.coroutines.async +import kotlinx.coroutines.CoroutineScope import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace @@ -38,7 +41,9 @@ class CoverageRunnerTest { @Test fun testRunCoverage_emptyDirectory_throwsException() { val exception = assertThrows() { - coverageRunner.getCoverage(bazelTestTarget) + runBlocking { + coverageRunner.runWithCoverageAsync(bazelTestTarget).await() + } } assertThat(exception).hasMessageThat().contains("not invoked from within a workspace") @@ -49,7 +54,9 @@ class CoverageRunnerTest { testBazelWorkspace.initEmptyWorkspace() val exception = assertThrows() { - coverageRunner.getCoverage(bazelTestTarget) + runBlocking { + coverageRunner.runWithCoverageAsync(bazelTestTarget).await() + } } assertThat(exception).hasMessageThat().contains("Expected non-zero exit code") @@ -103,28 +110,33 @@ class CoverageRunnerTest { subpackage = "coverage" ) - val result = coverageRunner.getCoverage("//coverage/test/java/com/example:test") - val expectedResult = - "SF:coverage/main/java/com/example/TwoSum.kt\n" + - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FN:3,com/example/TwoSum:: ()V\n" + - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FNDA:0,com/example/TwoSum:: ()V\n" + - "FNF:2\n" + - "FNH:1\n" + - "BRDA:7,0,0,1\n" + - "BRDA:7,0,1,1\n" + - "BRDA:7,0,2,1\n" + - "BRDA:7,0,3,1\n" + - "BRF:4\n" + - "BRH:4\n" + - "DA:3,0\n" + - "DA:7,1\n" + - "DA:8,1\n" + - "DA:10,1\n" + - "LH:3\n" + - "LF:4\n" + - "end_of_record\n" + val result = runBlocking { + coverageRunner.runWithCoverageAsync( + "//coverage/test/java/com/example:test" + ).await() + } + val expectedResult = listOf( + "SF:coverage/main/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ) assertThat(result).isEqualTo(expectedResult) } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index df2390a5efc..f696a8f1059 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -119,27 +119,28 @@ class RunCoverageForTestTargetTest { scriptBgDispatcher ).runCoverage() - val expectedResult = - "SF:coverage/main/java/com/example/TwoSum.kt\n" + - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FN:3,com/example/TwoSum:: ()V\n" + - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FNDA:0,com/example/TwoSum:: ()V\n" + - "FNF:2\n" + - "FNH:1\n" + - "BRDA:7,0,0,1\n" + - "BRDA:7,0,1,1\n" + - "BRDA:7,0,2,1\n" + - "BRDA:7,0,3,1\n" + - "BRF:4\n" + - "BRH:4\n" + - "DA:3,0\n" + - "DA:7,1\n" + - "DA:8,1\n" + - "DA:10,1\n" + - "LH:3\n" + - "LF:4\n" + - "end_of_record\n" + val expectedResult = listOf( + "SF:coverage/main/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ) assertThat(result).isEqualTo(expectedResult) } From f15e087f9977b8c930d027aca2d2bda04af3aa19 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 21 Jun 2024 18:35:50 +0530 Subject: [PATCH 039/105] Fix Lint checks --- .../src/java/org/oppia/android/scripts/common/BazelClient.kt | 1 - .../org/oppia/android/scripts/common/BazelClientTest.kt | 1 - .../org/oppia/android/scripts/coverage/CoverageRunnerTest.kt | 2 -- 3 files changed, 4 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 1d0553ecfe4..2410ebb9613 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -2,7 +2,6 @@ package org.oppia.android.scripts.common import java.io.File import java.lang.IllegalArgumentException -import java.nio.file.Files import java.nio.file.Paths import java.util.Locale diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 1c3b0adad21..80bc82291c2 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -14,7 +14,6 @@ import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import org.oppia.android.testing.mockito.anyOrNull import java.io.File -import java.nio.file.NoSuchFileException import java.util.concurrent.TimeUnit /** diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 172916db920..bae58d98feb 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -7,8 +7,6 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder -import kotlinx.coroutines.async -import kotlinx.coroutines.CoroutineScope import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace From 506916dec0e897b0cdb11cfbb29af1e83e76f2a4 Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 21 Jun 2024 19:23:51 +0530 Subject: [PATCH 040/105] Removed ending periods in KDoc Strings --- .../oppia/android/scripts/common/BazelClient.kt | 8 ++++---- .../android/scripts/coverage/CoverageRunner.kt | 14 +++++++------- .../scripts/coverage/RunCoverageForTestTarget.kt | 8 ++++---- .../android/scripts/common/BazelClientTest.kt | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 2410ebb9613..9316d47d01d 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -132,15 +132,15 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: } /** - * Runs code coverage for the specified Bazel test target. + * Runs code coverage for the specified Bazel test target * * @param bazelTestTarget Bazel test target for which code coverage will be run * @return the generated coverage data as a list of strings - * or null if the coverage data file could not be parsed. + * or null if the coverage data file could not be parsed * - * Null return typically occurs when the coverage command fails to generate the 'coverage.dat' file. + * Null return typically occurs when the coverage command fails to generate the 'coverage.dat' file * This can happen due to: Test failures or misconfigurations that prevent the coverage data - * from being generated properly. + * from being generated properly */ fun runCoverageForTestTarget(bazelTestTarget: String): List? { val coverageData = executeBazelCommand( 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 7339dcc2bab..bff5ad55cae 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -9,7 +9,7 @@ import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import java.io.File /** - * Class responsible for running coverage analysis asynchronously. + * Class responsible for running coverage analysis asynchronously * * @param repoRoot the root directory of the repository * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command @@ -23,10 +23,10 @@ class CoverageRunner( private val bazelClient by lazy { BazelClient(repoRoot, commandExecutor) } /** - * Runs coverage analysis asynchronously for the Bazel test target. + * Runs coverage analysis asynchronously for the Bazel test target * - * @param bazelTestTarget Bazel test target to analyze coverage. - * @return a deferred value that contains the coverage data. + * @param bazelTestTarget Bazel test target to analyze coverage + * @return a deferred value that contains the coverage data */ fun runWithCoverageAsync( bazelTestTarget: String @@ -38,10 +38,10 @@ class CoverageRunner( } /** - * Runs coverage command for the Bazel test target. + * Runs coverage command for the Bazel test target * - * @param bazelTestTarget Bazel test target to analyze coverage. - * @return the generated coverage data as a string. + * @param bazelTestTarget Bazel test target to analyze coverage + * @return the generated coverage data as a string */ private fun retrieveCoverageResult( bazelTestTarget: String diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index e5e1bdccd45..f3362232aad 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -8,13 +8,13 @@ import java.io.File import java.util.concurrent.TimeUnit /** - * Entry point function for running coverage analysis for a single test target. + * Entry point function for running coverage analysis for a single test target * * Usage: * bazel run //scripts:run_coverage_for_test_target -- * * Arguments: - * - path_to_root: directory path to the root of the Oppia Android repository. + * - path_to_root: directory path to the root of the Oppia Android repository * - test_targetname: bazel target name of the test * * Example: @@ -70,9 +70,9 @@ class RunCoverageForTestTarget( } /** - * Runs coverage analysis on the specified target file asynchronously. + * Runs coverage analysis on the specified target file asynchronously * - * @return the generated coverage data. + * @return the generated coverage data */ fun runWithCoverageAnalysis(): List? { return runBlocking { diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 80bc82291c2..f6ebb382029 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -20,10 +20,10 @@ import java.util.concurrent.TimeUnit * Tests for [BazelClient]. * * Note that this test executes real commands on the local filesystem & requires Bazel in the local - * environment. + * environment */ -// Same parameter value: helpers reduce test context, even if they are used by 1 test. -// Function name: test names are conventionally named with underscores. +// Same parameter value: helpers reduce test context, even if they are used by 1 test +// Function name: test names are conventionally named with underscores @Suppress("SameParameterValue", "FunctionName") class BazelClientTest { @field:[Rule JvmField] val tempFolder = TemporaryFolder() From 87d34ad7ddc7fdbd108bc0c4af1e705cb8e164fc Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 21 Jun 2024 21:24:39 +0530 Subject: [PATCH 041/105] Update the script to align with changes in BazelClient PR 1.1 to return the coverage data as a List of String --- .../android/scripts/coverage/BUILD.bazel | 3 +- .../android/scripts/coverage/RunCoverage.kt | 7 +-- .../scripts/coverage/RunCoverageTest.kt | 44 ++++++++++--------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 7aba008aaa6..9a484e0bc35 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -13,8 +13,8 @@ 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:script_exemptions_java_proto", "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", + "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", ], ) @@ -40,6 +40,5 @@ 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/common:git_client", ], ) 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 380d8adb27e..d0b2ce66bdc 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -71,15 +71,15 @@ class RunCoverage( * a Bazel client, finds potential test file paths, retrieves Bazel targets, and initiates * coverage analysis for each test target found. */ - fun execute(): List { - var coverageDataList = mutableListOf() + fun execute(): MutableList> { + var coverageDataList = mutableListOf>() val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() val isExempted = testFileExemptionList.contains(filePath) if (isExempted) { println("This file is exempted from having a test file. Hence No coverage!") - return emptyList() + return mutableListOf() } val testFilePaths = findTestFile(repoRoot, filePath) @@ -94,6 +94,7 @@ class RunCoverage( ).runCoverage()!! coverageDataList.add(coverageData) } + println("Coverage Data List: $coverageDataList") return coverageDataList } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 2d2a58dce25..8e5c6c02460 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -224,27 +224,29 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedResultList = listOf( - "SF:coverage/main/java/com/example/TwoSum.kt\n" + - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FN:3,com/example/TwoSum:: ()V\n" + - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;\n" + - "FNDA:0,com/example/TwoSum:: ()V\n" + - "FNF:2\n" + - "FNH:1\n" + - "BRDA:7,0,0,1\n" + - "BRDA:7,0,1,1\n" + - "BRDA:7,0,2,1\n" + - "BRDA:7,0,3,1\n" + - "BRF:4\n" + - "BRH:4\n" + - "DA:3,0\n" + - "DA:7,1\n" + - "DA:8,1\n" + - "DA:10,1\n" + - "LH:3\n" + - "LF:4\n" + - "end_of_record\n" + val expectedResultList = mutableListOf( + listOf( + "SF:coverage/main/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ) ) assertThat(result).isEqualTo(expectedResultList) From 0735c64340c0586e9048ed5f4b1a023aa6e62ab5 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 01:02:22 +0530 Subject: [PATCH 042/105] Introduced coverage.proto and parsed the coverage data and store them to the proto --- .../android/scripts/coverage/BUILD.bazel | 1 + .../scripts/coverage/CoverageRunner.kt | 135 ++++++++++++++++++ .../oppia/android/scripts/proto/BUILD.bazel | 11 ++ .../android/scripts/proto/coverage.proto | 62 ++++++++ 4 files changed, 209 insertions(+) create mode 100644 scripts/src/java/org/oppia/android/scripts/proto/coverage.proto diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 9a484e0bc35..42d30000dc0 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -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", ], ) 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 bff5ad55cae..137c8186d30 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -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 @@ -33,6 +38,12 @@ class CoverageRunner( ): Deferred?> { return CoroutineScope(scriptBgDispatcher).async { val coverageDataFilePath = retrieveCoverageResult(bazelTestTarget) + + val coverageReport = coverageDataFilePath?.let { + parseCoverageData(it, bazelTestTarget) + } + println("Coverage Report: $coverageReport") + coverageDataFilePath } } @@ -48,4 +59,128 @@ class CoverageRunner( ): List? { return bazelClient.runCoverageForTestTarget(bazelTestTarget) } + + private fun parseCoverageData(coverageData: List, bazelTestTarget: String): CoverageReport { + var filePath = "" + var linesFound = 0 + var linesHit = 0 + val coveredLines = mutableListOf() + val branchCoverage = mutableListOf() + val functionCoverage = mutableListOf() + + var functionsFound = 0 + var functionsHit = 0 + var branchesFound = 0 + var branchesHit = 0 + + coverageData.forEach { line -> + when { + // SF: + line.startsWith("SF:") -> { + filePath = line.substringAfter("SF:") + } + // DA:, + 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.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.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:, + 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: + line.startsWith("FNF:") -> { + functionsFound = line.substringAfter("FNF:").toInt() + } + // FNH: + line.startsWith("FNH:") -> { + functionsHit = line.substringAfter("FNH:").toInt() + } + // BRF: + line.startsWith("BRF:") -> { + branchesFound = line.substringAfter("BRF:").toInt() + } + // BRH: + line.startsWith("BRH:") -> { + branchesHit = line.substringAfter("BRH:").toInt() + } + // LF: + line.startsWith("LF:") -> { + linesFound = line.substringAfter("LF:").toInt() + } + // LH: + 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() + } + } diff --git a/scripts/src/java/org/oppia/android/scripts/proto/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/proto/BUILD.bazel index 7265ff0efc3..72956d786a5 100644 --- a/scripts/src/java/org/oppia/android/scripts/proto/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/proto/BUILD.bazel @@ -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"], diff --git a/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto b/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto new file mode 100644 index 00000000000..badf4c55bac --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto @@ -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; + } +} From 307214a61e2fb11a48f32d6897d5e784880f57cd Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 01:42:21 +0530 Subject: [PATCH 043/105] Added sha hash and hit count for branches --- .../scripts/coverage/CoverageRunner.kt | 20 +++++++++++++------ .../android/scripts/proto/coverage.proto | 3 ++- 2 files changed, 16 insertions(+), 7 deletions(-) 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 137c8186d30..e228d03dbc6 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -12,6 +12,9 @@ import org.oppia.android.scripts.common.BazelClient import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import java.io.File +import java.nio.file.Files +import java.nio.file.Paths +import java.security.MessageDigest /** * Class responsible for running coverage analysis asynchronously @@ -48,12 +51,6 @@ class CoverageRunner( } } - /** - * Runs coverage command for the Bazel test target - * - * @param bazelTestTarget Bazel test target to analyze coverage - * @return the generated coverage data as a string - */ private fun retrieveCoverageResult( bazelTestTarget: String ): List? { @@ -105,6 +102,7 @@ class CoverageRunner( .setLineNumber(lineNumber) .setBlockNumber(blockNumber) .setBranchNumber(branchNumber) + .setHitCount(hitCount) .setCoverage(coverage) .build() ) @@ -164,8 +162,12 @@ class CoverageRunner( } } + val file = File(repoRoot, filePath) + val fileSha1Hash = calculateSha1(file.absolutePath) + val coveredFile = CoveredFile.newBuilder() .setFilePath(filePath) + .setFileSha1Hash(fileSha1Hash) .addAllCoveredLine(coveredLines) .addAllBranchCoverage(branchCoverage) .addAllFunctionCoverage(functionCoverage) @@ -182,5 +184,11 @@ class CoverageRunner( .addCoveredFile(coveredFile) .build() } +} +private fun calculateSha1(filePath: String): String { + val fileBytes = Files.readAllBytes(Paths.get(filePath)) + val digest = MessageDigest.getInstance("SHA-1") + val hashBytes = digest.digest(fileBytes) + return hashBytes.joinToString("") { "%02x".format(it) } } diff --git a/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto b/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto index badf4c55bac..6422d5f8ae1 100644 --- a/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto +++ b/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto @@ -39,7 +39,8 @@ message BranchCoverage { int32 line_number = 1; optional int32 block_number = 2; optional int32 branch_number = 3; - BranchCoverage.Coverage coverage = 4; + optional int32 hit_count = 4; + BranchCoverage.Coverage coverage = 5; enum Coverage { UNSPECIFIED = 0; From bb2cbb2829d04234bfcebedb0915f10516849d16 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 03:58:45 +0530 Subject: [PATCH 044/105] Isolate the coverage data to only contain the target coverage data --- .../scripts/coverage/CoverageRunner.kt | 187 ++++++++++-------- 1 file changed, 105 insertions(+), 82 deletions(-) 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 e228d03dbc6..edbaa88c55c 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -70,94 +70,112 @@ class CoverageRunner( var branchesFound = 0 var branchesHit = 0 + var parseFile = false + val extractedFileName = "${extractTargetName(bazelTestTarget)}.kt" + coverageData.forEach { line -> when { // SF: line.startsWith("SF:") -> { - filePath = line.substringAfter("SF:") - } - // DA:, - 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.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) - .setHitCount(hitCount) - .setCoverage(coverage) - .build() - ) - } - // FN:, - 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:, - 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 + val sourceFilePath = line.substringAfter("SF:") + if (sourceFilePath.substringAfterLast("/") == extractedFileName) { + filePath = line.substringAfter("SF:") + parseFile = true + } else { + parseFile = false } } - // FNF: - line.startsWith("FNF:") -> { - functionsFound = line.substringAfter("FNF:").toInt() - } - // FNH: - line.startsWith("FNH:") -> { - functionsHit = line.substringAfter("FNH:").toInt() - } - // BRF: - line.startsWith("BRF:") -> { - branchesFound = line.substringAfter("BRF:").toInt() - } - // BRH: - line.startsWith("BRH:") -> { - branchesHit = line.substringAfter("BRH:").toInt() - } - // LF: - line.startsWith("LF:") -> { - linesFound = line.substringAfter("LF:").toInt() - } - // LH: - line.startsWith("LH:") -> { - linesHit = line.substringAfter("LH:").toInt() + parseFile -> { + when { + // DA:, + 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.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) + .setHitCount(hitCount) + .setCoverage(coverage) + .build() + ) + } + // FN:, + 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:, + 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: + line.startsWith("FNF:") -> { + functionsFound = line.substringAfter("FNF:").toInt() + } + // FNH: + line.startsWith("FNH:") -> { + functionsHit = line.substringAfter("FNH:").toInt() + } + // BRF: + line.startsWith("BRF:") -> { + branchesFound = line.substringAfter("BRF:").toInt() + } + // BRH: + line.startsWith("BRH:") -> { + branchesHit = line.substringAfter("BRH:").toInt() + } + // LF: + line.startsWith("LF:") -> { + linesFound = line.substringAfter("LF:").toInt() + } + // LH: + line.startsWith("LH:") -> { + linesHit = line.substringAfter("LH:").toInt() + } + line.startsWith("end_of_record") -> { + parseFile = false + } + } } } } @@ -186,6 +204,11 @@ class CoverageRunner( } } +private fun extractTargetName(bazelTestTarget: String): String { + val targetName = bazelTestTarget.substringAfterLast(":").trim() + return targetName.removeSuffix("Test").removeSuffix("LocalTest") +} + private fun calculateSha1(filePath: String): String { val fileBytes = Files.readAllBytes(Paths.get(filePath)) val digest = MessageDigest.getInstance("SHA-1") From 653ec689cf1d215090f1abf64230b2ea0a2f8926 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 04:13:22 +0530 Subject: [PATCH 045/105] Fix Lint Checks --- .../scripts/coverage/CoverageRunner.kt | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) 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 edbaa88c55c..11ecc08d195 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -3,14 +3,14 @@ package org.oppia.android.scripts.coverage import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.async +import org.oppia.android.scripts.common.BazelClient +import org.oppia.android.scripts.common.CommandExecutor +import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.scripts.proto.BranchCoverage 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 import java.io.File import java.nio.file.Files import java.nio.file.Paths @@ -57,7 +57,10 @@ class CoverageRunner( return bazelClient.runCoverageForTestTarget(bazelTestTarget) } - private fun parseCoverageData(coverageData: List, bazelTestTarget: String): CoverageReport { + private fun parseCoverageData( + coverageData: List, + bazelTestTarget: String + ): CoverageReport { var filePath = "" var linesFound = 0 var linesHit = 0 @@ -93,7 +96,10 @@ class CoverageRunner( val lineNumber = parts[0].toInt() val hitCount = parts[1].toInt() val coverage = - if (hitCount > 0) CoveredLine.Coverage.FULL else CoveredLine.Coverage.NONE + if (hitCount > 0) + CoveredLine.Coverage.FULL + else + CoveredLine.Coverage.NONE coveredLines.add( CoveredLine.newBuilder() .setLineNumber(lineNumber) @@ -109,7 +115,10 @@ class CoverageRunner( val branchNumber = parts[2].toInt() val hitCount = parts[3].toInt() val coverage = - if (hitCount > 0) BranchCoverage.Coverage.FULL else BranchCoverage.Coverage.NONE + if (hitCount > 0) + BranchCoverage.Coverage.FULL + else + BranchCoverage.Coverage.NONE branchCoverage.add( BranchCoverage.newBuilder() .setLineNumber(lineNumber) @@ -143,7 +152,12 @@ class CoverageRunner( if (index != -1) { val updatedFunctionCoverage = functionCoverage[index].toBuilder() .setExecutionCount(executionCount) - .setCoverage(if (executionCount > 0) FunctionCoverage.Coverage.FULL else FunctionCoverage.Coverage.NONE) + .setCoverage( + if (executionCount > 0) + FunctionCoverage.Coverage.FULL + else + FunctionCoverage.Coverage.NONE + ) .build() functionCoverage[index] = updatedFunctionCoverage } From 46cc3ff9276ea63130474aa0bd54392c1e7204de Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 05:04:05 +0530 Subject: [PATCH 046/105] Include coverage data to proto for any related tests - LocalTest and return as a list of CoverageReport --- .../oppia/android/scripts/coverage/CoverageRunner.kt | 10 ++++------ .../org/oppia/android/scripts/coverage/RunCoverage.kt | 10 ++++++++-- .../scripts/coverage/RunCoverageForTestTarget.kt | 5 +++-- 3 files changed, 15 insertions(+), 10 deletions(-) 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 11ecc08d195..5dacf330a9a 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -38,16 +38,14 @@ class CoverageRunner( */ fun runWithCoverageAsync( bazelTestTarget: String - ): Deferred?> { + ): Deferred { return CoroutineScope(scriptBgDispatcher).async { - val coverageDataFilePath = retrieveCoverageResult(bazelTestTarget) + val coverageResult = retrieveCoverageResult(bazelTestTarget) - val coverageReport = coverageDataFilePath?.let { + val coverageReport = coverageResult?.let { parseCoverageData(it, bazelTestTarget) } - println("Coverage Report: $coverageReport") - - coverageDataFilePath + coverageReport } } 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 d0b2ce66bdc..8e267ea72c8 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -4,6 +4,7 @@ import org.oppia.android.scripts.common.BazelClient import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.scripts.proto.CoverageReport import org.oppia.android.scripts.proto.TestFileExemptions import java.io.File import java.io.FileInputStream @@ -71,8 +72,8 @@ class RunCoverage( * a Bazel client, finds potential test file paths, retrieves Bazel targets, and initiates * coverage analysis for each test target found. */ - fun execute(): MutableList> { - var coverageDataList = mutableListOf>() + fun execute(): MutableList { + var coverageDataList = mutableListOf() val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() @@ -85,6 +86,11 @@ class RunCoverage( val testFilePaths = findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) + /*val testResults = listOf( + "//utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest", + "//utility/src/test/java/org/oppia/android/util/math:FloatExtensionsTest")*/ + +// for (testTarget in testResults) { for (testTarget in testTargets) { val coverageData = RunCoverageForTestTarget( rootDirectory, diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index f3362232aad..1c508b5e932 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.runBlocking import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.scripts.proto.CoverageReport import java.io.File import java.util.concurrent.TimeUnit @@ -65,7 +66,7 @@ class RunCoverageForTestTarget( /** * Analyzes target file for coverage, generates chosen reports accordingly. */ - fun runCoverage(): List? { + fun runCoverage(): CoverageReport? { return runWithCoverageAnalysis() } @@ -74,7 +75,7 @@ class RunCoverageForTestTarget( * * @return the generated coverage data */ - fun runWithCoverageAnalysis(): List? { + fun runWithCoverageAnalysis(): CoverageReport? { return runBlocking { val result = CoverageRunner(repoRoot, scriptBgDispatcher, commandExecutor) From 25a064e555894a21b18a0c5aa759e9f8e28b3a19 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 06:07:54 +0530 Subject: [PATCH 047/105] Updated the tests to now check with the CoverageReport proto result --- .../scripts/coverage/CoverageRunnerTest.kt | 81 +++++++++++++----- .../coverage/RunCoverageForTestTargetTest.kt | 81 +++++++++++++----- .../scripts/coverage/RunCoverageTest.kt | 84 +++++++++++++------ 3 files changed, 178 insertions(+), 68 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 4651154b186..ecd7db78374 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -10,6 +10,11 @@ import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace +import org.oppia.android.scripts.proto.BranchCoverage +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.FunctionCoverage import org.oppia.android.testing.assertThrows import java.util.concurrent.TimeUnit @@ -113,28 +118,60 @@ class CoverageRunnerTest { "//coverage/test/java/com/example:TwoSumTest" ).await() } - val expectedResult = listOf( - "SF:coverage/main/java/com/example/TwoSum.kt", - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FN:3,com/example/TwoSum:: ()V", - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FNDA:0,com/example/TwoSum:: ()V", - "FNF:2", - "FNH:1", - "BRDA:7,0,0,1", - "BRDA:7,0,1,1", - "BRDA:7,0,2,1", - "BRDA:7,0,3,1", - "BRF:4", - "BRH:4", - "DA:3,0", - "DA:7,1", - "DA:8,1", - "DA:10,1", - "LH:3", - "LF:4", - "end_of_record" - ) + + val expectedCoveredFile = CoveredFile.newBuilder() + .setFilePath("coverage/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(CoveredLine.Coverage.NONE).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(CoveredLine.Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(CoveredLine.Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(CoveredLine.Coverage.FULL).build()) + .setLinesFound(4) + .setLinesHit(3) + .addFunctionCoverage(FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(FunctionCoverage.Coverage.FULL).build()) + .addFunctionCoverage(FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(FunctionCoverage.Coverage.NONE).build()) + .setFunctionsFound(2) + .setFunctionsHit(1) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .setBranchesFound(4) + .setBranchesHit(4) + .build() + + val expectedResult = CoverageReport.newBuilder() + .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") + .addCoveredFile(expectedCoveredFile) + .build() assertThat(result).isEqualTo(expectedResult) } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index 19fcdd0ef31..ee2172268a3 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -9,6 +9,11 @@ import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace +import org.oppia.android.scripts.proto.BranchCoverage +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.FunctionCoverage import org.oppia.android.testing.assertThrows import java.util.concurrent.TimeUnit @@ -119,28 +124,60 @@ class RunCoverageForTestTargetTest { scriptBgDispatcher ).runCoverage() - val expectedResult = listOf( - "SF:coverage/main/java/com/example/TwoSum.kt", - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FN:3,com/example/TwoSum:: ()V", - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FNDA:0,com/example/TwoSum:: ()V", - "FNF:2", - "FNH:1", - "BRDA:7,0,0,1", - "BRDA:7,0,1,1", - "BRDA:7,0,2,1", - "BRDA:7,0,3,1", - "BRF:4", - "BRH:4", - "DA:3,0", - "DA:7,1", - "DA:8,1", - "DA:10,1", - "LH:3", - "LF:4", - "end_of_record" - ) + + val expectedCoveredFile = CoveredFile.newBuilder() + .setFilePath("coverage/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(CoveredLine.Coverage.NONE).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(CoveredLine.Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(CoveredLine.Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(CoveredLine.Coverage.FULL).build()) + .setLinesFound(4) + .setLinesHit(3) + .addFunctionCoverage(FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(FunctionCoverage.Coverage.FULL).build()) + .addFunctionCoverage(FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(FunctionCoverage.Coverage.NONE).build()) + .setFunctionsFound(2) + .setFunctionsHit(1) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .setBranchesFound(4) + .setBranchesHit(4) + .build() + + val expectedResult = CoverageReport.newBuilder() + .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") + .addCoveredFile(expectedCoveredFile) + .build() assertThat(result).isEqualTo(expectedResult) } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 8e5c6c02460..8c034cf9c30 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -9,6 +9,11 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.scripts.proto.BranchCoverage +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.FunctionCoverage import org.oppia.android.scripts.testing.TestBazelWorkspace import java.io.ByteArrayOutputStream import java.io.File @@ -224,30 +229,61 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedResultList = mutableListOf( - listOf( - "SF:coverage/main/java/com/example/TwoSum.kt", - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FN:3,com/example/TwoSum:: ()V", - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FNDA:0,com/example/TwoSum:: ()V", - "FNF:2", - "FNH:1", - "BRDA:7,0,0,1", - "BRDA:7,0,1,1", - "BRDA:7,0,2,1", - "BRDA:7,0,3,1", - "BRF:4", - "BRH:4", - "DA:3,0", - "DA:7,1", - "DA:8,1", - "DA:10,1", - "LH:3", - "LF:4", - "end_of_record" - ) - ) + val expectedCoveredFile = CoveredFile.newBuilder() + .setFilePath("coverage/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(CoveredLine.Coverage.NONE).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(CoveredLine.Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(CoveredLine.Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(CoveredLine.Coverage.FULL).build()) + .setLinesFound(4) + .setLinesHit(3) + .addFunctionCoverage(FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(FunctionCoverage.Coverage.FULL).build()) + .addFunctionCoverage(FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(FunctionCoverage.Coverage.NONE).build()) + .setFunctionsFound(2) + .setFunctionsHit(1) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .addBranchCoverage(BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(BranchCoverage.Coverage.FULL).build()) + .setBranchesFound(4) + .setBranchesHit(4) + .build() + + val expectedResult = CoverageReport.newBuilder() + .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") + .addCoveredFile(expectedCoveredFile) + .build() + + val expectedResultList = mutableListOf(expectedResult) assertThat(result).isEqualTo(expectedResultList) } From ba1c66ab62ef2dd03edfa11a6eb561db7bfabedc Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 07:13:20 +0530 Subject: [PATCH 048/105] Fix KDoc String punctuations, more clearer variable names and simplified implementations --- .../android/scripts/common/BazelClient.kt | 36 ++++++------------- .../scripts/coverage/CoverageRunner.kt | 15 +++----- .../coverage/RunCoverageForTestTarget.kt | 6 ++-- .../android/scripts/common/BazelClientTest.kt | 2 +- 4 files changed, 18 insertions(+), 41 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 9316d47d01d..44d61ba40ce 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -132,35 +132,28 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: } /** - * Runs code coverage for the specified Bazel test target + * Runs code coverage for the specified Bazel test target. + * Null return typically occurs when the coverage command fails to generate the 'coverage.dat' file + * This can happen due to: Test failures or misconfigurations that prevent the coverage data + * from being generated properly. * * @param bazelTestTarget Bazel test target for which code coverage will be run * @return the generated coverage data as a list of strings * or null if the coverage data file could not be parsed - * - * Null return typically occurs when the coverage command fails to generate the 'coverage.dat' file - * This can happen due to: Test failures or misconfigurations that prevent the coverage data - * from being generated properly */ fun runCoverageForTestTarget(bazelTestTarget: String): List? { - val coverageData = executeBazelCommand( + val coverageCommandOutputLines = executeBazelCommand( "coverage", bazelTestTarget ) - return parseCoverageDataFile(coverageData)?.let { path -> + return parseCoverageDataFilePath(coverageCommandOutputLines)?.let { path -> readDatFile(path) } } - /** - * Parse the coverage command result to extract the path of the coverage data file. - * - * @param data the result from the execution of the coverage command - * @return the extracted path of the coverage data file. - */ - private fun parseCoverageDataFile(data: List): String? { + private fun parseCoverageDataFilePath(coverageCommandOutputLines: List): String? { val regex = ".*coverage\\.dat$".toRegex() - for (line in data) { + for (line in coverageCommandOutputLines) { val match = regex.find(line) val extractedPath = match?.value?.substringAfterLast(",")?.trim() if (extractedPath != null) { @@ -171,17 +164,8 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return null } - /** - * Reads the content of the .dat file as a list of lines. - * - * @param filePath path to the .dat file - * @return content of the .dat file as a list of strings - */ - private fun readDatFile(filePath: String?): List? { - return filePath?.let { path -> - val pathObj = Paths.get(path) - File(pathObj.toUri()).readLines() - } + private fun readDatFile(filePath: String): List { + return File(filePath).readLines() } /** 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 bff5ad55cae..e4701cd2da3 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -9,11 +9,11 @@ import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import java.io.File /** - * Class responsible for running coverage analysis asynchronously + * Class responsible for running coverage analysis asynchronously. * * @param repoRoot the root directory of the repository * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command - * @param commandExecutor Executes the specified command in the specified working directory + * @param commandExecutor executes the specified command in the specified working directory */ class CoverageRunner( private val repoRoot: File, @@ -23,7 +23,7 @@ class CoverageRunner( private val bazelClient by lazy { BazelClient(repoRoot, commandExecutor) } /** - * Runs coverage analysis asynchronously for the Bazel test target + * Runs coverage analysis asynchronously for the Bazel test target. * * @param bazelTestTarget Bazel test target to analyze coverage * @return a deferred value that contains the coverage data @@ -32,17 +32,10 @@ class CoverageRunner( bazelTestTarget: String ): Deferred?> { return CoroutineScope(scriptBgDispatcher).async { - val coverageDataFilePath = retrieveCoverageResult(bazelTestTarget) - coverageDataFilePath + retrieveCoverageResult(bazelTestTarget) } } - /** - * Runs coverage command for the Bazel test target - * - * @param bazelTestTarget Bazel test target to analyze coverage - * @return the generated coverage data as a string - */ private fun retrieveCoverageResult( bazelTestTarget: String ): List? { diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt index f3362232aad..6875bd9141f 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt @@ -8,7 +8,7 @@ import java.io.File import java.util.concurrent.TimeUnit /** - * Entry point function for running coverage analysis for a single test target + * Entry point function for running coverage analysis for a single test target. * * Usage: * bazel run //scripts:run_coverage_for_test_target -- @@ -52,7 +52,7 @@ fun main(vararg args: String) { * * @param repoRoot the root directory of the repository * @param targetPath Bazel test target to analyze coverage - * @param commandExecutor Executes the specified command in the specified working directory + * @param commandExecutor executes the specified command in the specified working directory * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command */ class RunCoverageForTestTarget( @@ -70,7 +70,7 @@ class RunCoverageForTestTarget( } /** - * Runs coverage analysis on the specified target file asynchronously + * Runs coverage analysis on the specified target file asynchronously. * * @return the generated coverage data */ diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index f6ebb382029..075feeab3fe 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -20,7 +20,7 @@ import java.util.concurrent.TimeUnit * Tests for [BazelClient]. * * Note that this test executes real commands on the local filesystem & requires Bazel in the local - * environment + * environment. */ // Same parameter value: helpers reduce test context, even if they are used by 1 test // Function name: test names are conventionally named with underscores From 438476c4185c72da82ca727060a4c19fe775e428 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 07:33:11 +0530 Subject: [PATCH 049/105] Removed unused Paths import --- scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 44d61ba40ce..a9979689176 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -2,7 +2,6 @@ package org.oppia.android.scripts.common import java.io.File import java.lang.IllegalArgumentException -import java.nio.file.Paths import java.util.Locale /** From c7c2f2f107b3377908a8159499fe2df200899059 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 09:46:43 +0530 Subject: [PATCH 050/105] Fixed indentation and line spaces for better readability --- .../java/org/oppia/android/scripts/common/BazelClient.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index a9979689176..62ce53bfb82 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -132,13 +132,14 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: /** * Runs code coverage for the specified Bazel test target. + * * Null return typically occurs when the coverage command fails to generate the 'coverage.dat' file * This can happen due to: Test failures or misconfigurations that prevent the coverage data * from being generated properly. * * @param bazelTestTarget Bazel test target for which code coverage will be run * @return the generated coverage data as a list of strings - * or null if the coverage data file could not be parsed + * or null if the coverage data file could not be parsed */ fun runCoverageForTestTarget(bazelTestTarget: String): List? { val coverageCommandOutputLines = executeBazelCommand( @@ -146,7 +147,7 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: bazelTestTarget ) return parseCoverageDataFilePath(coverageCommandOutputLines)?.let { path -> - readDatFile(path) + File(path).readLines() } } @@ -163,10 +164,6 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: return null } - private fun readDatFile(filePath: String): List { - return File(filePath).readLines() - } - /** * Returns the results of a query command with a potentially large list of [values] that will be * split up into multiple commands to avoid overflow the system's maximum argument limit. From 6a2a0291bfe3a5a20e4b59914c2c1a2b0827ea27 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 17:04:33 +0530 Subject: [PATCH 051/105] For Reference: Multiple test cases with LocalTest and Test works but without sharedTest path with sharedTest NPE is thrown --- .../android/scripts/coverage/RunCoverage.kt | 2 +- .../scripts/testing/TestBazelWorkspace.kt | 35 +++++ .../scripts/coverage/RunCoverageTest.kt | 122 ++++++++++++++++++ 3 files changed, 158 insertions(+), 1 deletion(-) 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 d0b2ce66bdc..df8192eb3ca 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -116,7 +116,7 @@ class RunCoverage( testFiles.add(testFilePath) } } else if (parts.isNotEmpty() && parts[0] == "app") { - val sharedTestFilePath = filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt") + val sharedTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 83d802f3b89..c70b1aa7e14 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -83,6 +83,41 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { ) } + fun addAppLevelSourceAndTestFileWithContent( + filename: String, + sourceContent: String, + testContentShared: String, + testContentLocal: String, + subpackage: String + ) { + val sourceSubpackage = "$subpackage/main/java/com/example" + addSourceContentAndBuildFile( + filename, + sourceContent, + sourceSubpackage + ) + + val testSubpackageShared = "$subpackage/test/java/com/example" + val testFileNameShared = "${filename}Test" + addTestContentAndBuildFile( + filename, + testFileNameShared, + testContentShared, + sourceSubpackage, + testSubpackageShared + ) + + val testSubpackageLocal = "$subpackage/test/java/com/example" + val testFileNameLocal = "${filename}LocalTest" + addTestContentAndBuildFile( + filename, + testFileNameLocal, + testContentLocal, + sourceSubpackage, + testSubpackageLocal + ) + } + /** * Adds a source file with the specified name and content to the specified subpackage, * and updates the corresponding build configuration. diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 8e5c6c02460..a13cf4362d8 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -252,6 +252,128 @@ class RunCoverageTest { assertThat(result).isEqualTo(expectedResultList) } + @Test + fun testRunCoverage_validMultiSampleTestFile_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContentShared = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + val testContentLocal = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumLocalTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addAppLevelSourceAndTestFileWithContent( + filename = "TwoSum", + sourceContent = sourceContent, + testContentShared = testContentShared, + testContentLocal = testContentLocal, + subpackage = "app" + ) + + val result = RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val expectedResultList = mutableListOf( + listOf( + "SF:app/main/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ),listOf( + "SF:app/main/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ) + ) + + assertThat(result).isEqualTo(expectedResultList) + } + private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { return CommandExecutorImpl( scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES From e4ede829edd60af932a6c36b06d74f38d19a61c7 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 17:24:17 +0530 Subject: [PATCH 052/105] For Reference: Added package group for sharedTest and Test, yet multiple test files didn't work --- .../android/scripts/coverage/RunCoverage.kt | 2 +- .../scripts/testing/TestBazelWorkspace.kt | 46 ++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) 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 df8192eb3ca..d0b2ce66bdc 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -116,7 +116,7 @@ class RunCoverage( testFiles.add(testFilePath) } } else if (parts.isNotEmpty() && parts[0] == "app") { - val sharedTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") + val sharedTestFilePath = filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt") val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index c70b1aa7e14..8ac4d373869 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -90,6 +90,50 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { testContentLocal: String, subpackage: String ) { + initEmptyWorkspace() + ensureWorkspaceIsConfiguredForKotlin() + setUpWorkspaceForRulesJvmExternal( + listOf("junit:junit:4.12") + ) + + // Create the source subpackage directory if it doesn't exist + if (!File(temporaryRootFolder.root, subpackage.replace(".", "/")).exists()) { + temporaryRootFolder.newFolder(*(subpackage.split(".")).toTypedArray()) + } + + // Create or update the BUILD file for the source file + val buildFilePath = "${subpackage.replace(".", "/")}/BUILD.bazel" + val buildFile = File(temporaryRootFolder.root, buildFilePath) + if (!buildFile.exists()) { + temporaryRootFolder.newFile(buildFilePath) + } + prepareBuildFileForLibraries(buildFile) + + buildFile.appendText( + """ + package_group( + name = "app_visibility", + packages = [ + "//app/...", + ], + ) + + package_group( + name = "app_testing_visibility", + packages = [ + "//app/sharedTest/...", + "//app/test/...", + ], + ) + + kt_jvm_library( + name = "${filename.lowercase()}", + srcs = ["$filename.kt"], + visibility = ["//visibility:public"] + ) + """.trimIndent() + "\n" + ) + val sourceSubpackage = "$subpackage/main/java/com/example" addSourceContentAndBuildFile( filename, @@ -97,7 +141,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { sourceSubpackage ) - val testSubpackageShared = "$subpackage/test/java/com/example" + val testSubpackageShared = "$subpackage/sharedTest/java/com/example" val testFileNameShared = "${filename}Test" addTestContentAndBuildFile( filename, From 9e0189df28de2391d8bbf3bdf6baadc9bd4259e7 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 17:49:03 +0530 Subject: [PATCH 053/105] Added implementation for script module test content files (to be refactored to just one case) --- .../scripts/testing/TestBazelWorkspace.kt | 66 ++++++--------- .../scripts/coverage/RunCoverageTest.kt | 82 +++++++++++++++++++ 2 files changed, 105 insertions(+), 43 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 8ac4d373869..a66a99747c2 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -83,57 +83,37 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { ) } - fun addAppLevelSourceAndTestFileWithContent( + fun addScriptSourceAndTestFileWithContent( filename: String, sourceContent: String, - testContentShared: String, - testContentLocal: String, + testContent: String, subpackage: String ) { - initEmptyWorkspace() - ensureWorkspaceIsConfiguredForKotlin() - setUpWorkspaceForRulesJvmExternal( - listOf("junit:junit:4.12") + val sourceSubpackage = "$subpackage/java/com/example" + addSourceContentAndBuildFile( + filename, + sourceContent, + sourceSubpackage ) - // Create the source subpackage directory if it doesn't exist - if (!File(temporaryRootFolder.root, subpackage.replace(".", "/")).exists()) { - temporaryRootFolder.newFolder(*(subpackage.split(".")).toTypedArray()) - } - - // Create or update the BUILD file for the source file - val buildFilePath = "${subpackage.replace(".", "/")}/BUILD.bazel" - val buildFile = File(temporaryRootFolder.root, buildFilePath) - if (!buildFile.exists()) { - temporaryRootFolder.newFile(buildFilePath) - } - prepareBuildFileForLibraries(buildFile) - - buildFile.appendText( - """ - package_group( - name = "app_visibility", - packages = [ - "//app/...", - ], - ) - - package_group( - name = "app_testing_visibility", - packages = [ - "//app/sharedTest/...", - "//app/test/...", - ], - ) - - kt_jvm_library( - name = "${filename.lowercase()}", - srcs = ["$filename.kt"], - visibility = ["//visibility:public"] - ) - """.trimIndent() + "\n" + val testSubpackage = "$subpackage/javatests/com/example" + val testFileName = "${filename}Test" + addTestContentAndBuildFile( + filename, + testFileName, + testContent, + sourceSubpackage, + testSubpackage ) + } + fun addAppLevelSourceAndTestFileWithContent( + filename: String, + sourceContent: String, + testContentShared: String, + testContentLocal: String, + subpackage: String + ) { val sourceSubpackage = "$subpackage/main/java/com/example" addSourceContentAndBuildFile( filename, diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index a13cf4362d8..90ef5f5e927 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -252,6 +252,88 @@ class RunCoverageTest { assertThat(result).isEqualTo(expectedResultList) } + @Test + fun testRunCoverage_validScriptPathSampleTestFile_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addScriptSourceAndTestFileWithContent( + filename = "TwoSum", + sourceContent = sourceContent, + testContent = testContent, + subpackage = "scripts" + ) + + val result = RunCoverage( + "${tempFolder.root}", + "scripts/java/com/example/TwoSum.kt", + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val expectedResultList = mutableListOf( + listOf( + "SF:scripts/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ) + ) + + assertThat(result).isEqualTo(expectedResultList) + } + @Test fun testRunCoverage_validMultiSampleTestFile_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() From d477d20687b87001ec843cf4769651c5989d13d5 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 18:06:18 +0530 Subject: [PATCH 054/105] Refactored the addSourceAndTestFileWithContent to be suitable for multiple module subpackages --- .../scripts/testing/TestBazelWorkspace.kt | 29 ++----------------- .../android/scripts/common/BazelClientTest.kt | 3 +- .../scripts/coverage/CoverageRunnerTest.kt | 3 +- .../coverage/RunCoverageForTestTargetTest.kt | 3 +- .../scripts/coverage/RunCoverageTest.kt | 8 +++-- .../scripts/testing/TestBazelWorkspaceTest.kt | 6 ++-- 6 files changed, 17 insertions(+), 35 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index a66a99747c2..71b9466cd65 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -63,40 +63,15 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { filename: String, sourceContent: String, testContent: String, - subpackage: String - ) { - val sourceSubpackage = "$subpackage/main/java/com/example" - addSourceContentAndBuildFile( - filename, - sourceContent, - sourceSubpackage - ) - - val testSubpackage = "$subpackage/test/java/com/example" - val testFileName = "${filename}Test" - addTestContentAndBuildFile( - filename, - testFileName, - testContent, - sourceSubpackage, - testSubpackage - ) - } - - fun addScriptSourceAndTestFileWithContent( - filename: String, - sourceContent: String, - testContent: String, - subpackage: String + sourceSubpackage: String, + testSubpackage: String ) { - val sourceSubpackage = "$subpackage/java/com/example" addSourceContentAndBuildFile( filename, sourceContent, sourceSubpackage ) - val testSubpackage = "$subpackage/javatests/com/example" val testFileName = "${filename}Test" addTestContentAndBuildFile( filename, diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index 8ca26de9a28..db725861d16 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -424,7 +424,8 @@ class BazelClientTest { filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, - subpackage = "coverage" + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" ) val result = bazelClient.runCoverageForTestTarget("//coverage/test/java/com/example:TwoSumTest") diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 4651154b186..5b6a8a62047 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -105,7 +105,8 @@ class CoverageRunnerTest { filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, - subpackage = "coverage" + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" ) val result = runBlocking { diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt index 19fcdd0ef31..27b4e20bf08 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt @@ -109,7 +109,8 @@ class RunCoverageForTestTargetTest { filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, - subpackage = "coverage" + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" ) val result = RunCoverageForTestTarget( diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 90ef5f5e927..cb902e26b83 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -214,7 +214,8 @@ class RunCoverageTest { filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, - subpackage = "coverage" + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" ) val result = RunCoverage( @@ -292,11 +293,12 @@ class RunCoverageTest { } """.trimIndent() - testBazelWorkspace.addScriptSourceAndTestFileWithContent( + testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", sourceContent = sourceContent, testContent = testContent, - subpackage = "scripts" + sourceSubpackage = "scripts/java/com/example", + testSubpackage = "scripts/javatests/com/example" ) val result = RunCoverage( diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index d62bbf11501..4c81c768db6 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -282,7 +282,8 @@ class TestBazelWorkspaceTest { "Main", sourceContent, testContent, - "coverage" + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" ) val sourceFile = File(tempFolder.root, "coverage/main/java/com/example/Main.kt") @@ -316,7 +317,8 @@ class TestBazelWorkspaceTest { "Main", sourceContent, testContent, - "coverage" + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" ) val sourceBuildFile = File(tempFolder.root, "coverage/main/java/com/example/BUILD.bazel") From 6720de78593da40404368d27603918e9d75e4c8c Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 18:24:49 +0530 Subject: [PATCH 055/105] For Reference: Added App cases, but just having sharedTest in package fails, but with just having test passes --- .../scripts/coverage/RunCoverageTest.kt | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index cb902e26b83..cf8b0423bb7 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -336,6 +336,89 @@ class RunCoverageTest { assertThat(result).isEqualTo(expectedResultList) } + @Test + fun testRunCoverage_validAppPathSampleTestFile_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "app/main/java/com/example", + testSubpackage = "app/sharedTest/java/com/example" + ) + + val result = RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val expectedResultList = mutableListOf( + listOf( + "SF:app/main/java/com/example/TwoSum.kt", + "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FN:3,com/example/TwoSum:: ()V", + "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", + "FNDA:0,com/example/TwoSum:: ()V", + "FNF:2", + "FNH:1", + "BRDA:7,0,0,1", + "BRDA:7,0,1,1", + "BRDA:7,0,2,1", + "BRDA:7,0,3,1", + "BRF:4", + "BRH:4", + "DA:3,0", + "DA:7,1", + "DA:8,1", + "DA:10,1", + "LH:3", + "LF:4", + "end_of_record" + ) + ) + + assertThat(result).isEqualTo(expectedResultList) + } + @Test fun testRunCoverage_validMultiSampleTestFile_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() From 04243f1ddc67a8575f663f40898dffc379f4684a Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 18:33:00 +0530 Subject: [PATCH 056/105] KDoC and reverting sharedTest to test, this passes test --- .../android/scripts/testing/TestBazelWorkspace.kt | 15 +++++++++++++-- .../android/scripts/coverage/RunCoverageTest.kt | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 71b9466cd65..2e4f1b20c0f 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -57,7 +57,8 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { * @param filename the name of the source file (without the .kt extension) * @param sourceContent the content of the source file * @param testContent the content of the test file - * @param subpackage the subpackage under which the source and test files should be added + * @param sourceSubpackage the subpackage under which the source files should be added + * @param testSubpackage the subpackage under which the test files should be added */ fun addSourceAndTestFileWithContent( filename: String, @@ -82,7 +83,17 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { ) } - fun addAppLevelSourceAndTestFileWithContent( + /** + * Adds a source file and 2 test files with the specified name and content, + * and updates the corresponding build configuration. + * + * @param filename the name of the source file (without the .kt extension) + * @param sourceContent the content of the source file + * @param testContentShared the content of the test file for SharedTest Package + * @param testContentLocal the content of the test file for Test Package + * @param subpackage the subpackage under which the source and test files should be added + */ + fun addMultiLevelSourceAndTestFileWithContent( filename: String, sourceContent: String, testContentShared: String, diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index cf8b0423bb7..611737202b6 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -381,7 +381,7 @@ class RunCoverageTest { sourceContent = sourceContent, testContent = testContent, sourceSubpackage = "app/main/java/com/example", - testSubpackage = "app/sharedTest/java/com/example" + testSubpackage = "app/test/java/com/example" ) val result = RunCoverage( From 985e861e342d162231e695a999a0728e982d2f04 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 18:51:55 +0530 Subject: [PATCH 057/105] For Reference: Even doing app/test fails with NPE --- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 611737202b6..285ba709c9a 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -477,17 +477,17 @@ class RunCoverageTest { } """.trimIndent() - testBazelWorkspace.addAppLevelSourceAndTestFileWithContent( + testBazelWorkspace.addMultiLevelSourceAndTestFileWithContent( filename = "TwoSum", sourceContent = sourceContent, testContentShared = testContentShared, testContentLocal = testContentLocal, - subpackage = "app" + subpackage = "app/test" ) val result = RunCoverage( "${tempFolder.root}", - "app/main/java/com/example/TwoSum.kt", + "app/test/main/java/com/example/TwoSum.kt", longCommandExecutor, scriptBgDispatcher ).execute() From 33f9a0bb3ae47a284222a552f0821bae6ccbbd03 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 18:54:29 +0530 Subject: [PATCH 058/105] Made findTestFile private and removed related tests --- .../android/scripts/coverage/RunCoverage.kt | 9 +- .../scripts/coverage/RunCoverageTest.kt | 117 +----------------- 2 files changed, 3 insertions(+), 123 deletions(-) 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 d0b2ce66bdc..e5f154dea16 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -98,14 +98,7 @@ class RunCoverage( return coverageDataList } - /** - * Finds potential test file paths corresponding to a given source file path within a repository. - * - * @param repoRoot the root directory of the repository - * @param filePath The file path of the source file for which the test files are to be found. - * @return A list of potential test file paths that exist in the repository. - */ - fun findTestFile(repoRoot: String, filePath: String): List { + private fun findTestFile(repoRoot: String, filePath: String): List { val file = File(filePath) val parts = file.parent.split(File.separator) val testFiles = mutableListOf() diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 285ba709c9a..617a4b3ac7c 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -57,119 +57,6 @@ class RunCoverageTest { .isEqualTo("This file is exempted from having a test file. Hence No coverage!\n") } - @Test - fun testRunCoverage_ScriptsPath_returnTestFilePath() { - val rootFolderPath = tempFolder.root.absolutePath - val expectedTestFilePath = "scripts/javatests/sample/ExampleTest.kt" - val file = File(rootFolderPath, expectedTestFilePath) - - file.parentFile?.mkdirs() - file.createNewFile() - - val expectedTestFilePaths = listOf(expectedTestFilePath) - - val result = RunCoverage( - rootFolderPath, - sampleFilePath, - commandExecutor, - scriptBgDispatcher - ).findTestFile(rootFolderPath, "scripts/java/sample/Example.kt") - - assertEquals(expectedTestFilePaths, result) - } - - @Test - fun testRunCoverage_AppPath_returnSharedTestFilePath() { - val rootFolderPath = tempFolder.root.absolutePath - val expectedSharedTestFilePath = "app/sharedTest/sample/ExampleTest.kt" - val file = File(rootFolderPath, expectedSharedTestFilePath) - - file.parentFile?.mkdirs() - file.createNewFile() - - val expectedSharedTestFilePaths = listOf(expectedSharedTestFilePath) - - val result = RunCoverage( - rootFolderPath, - sampleFilePath, - commandExecutor, - scriptBgDispatcher - ).findTestFile(rootFolderPath, "app/main/sample/Example.kt") - - assertEquals(expectedSharedTestFilePaths, result) - } - - @Test - fun testRunCoverage_AppPath_returnLocalTestFilePath() { - val rootFolderPath = tempFolder.root.absolutePath - val expectedLocalTestFilePath = "app/test/sample/ExampleTest.kt" - val file = File(rootFolderPath, expectedLocalTestFilePath) - - file.parentFile?.mkdirs() - file.createNewFile() - - val expectedLocalTestFilePaths = listOf(expectedLocalTestFilePath) - - val result = RunCoverage( - rootFolderPath, - sampleFilePath, - commandExecutor, - scriptBgDispatcher - ).findTestFile(rootFolderPath, "app/main/sample/Example.kt") - - assertEquals(expectedLocalTestFilePaths, result) - } - - @Test - fun testRunCoverage_AppPath_returnSharedAndLocalTestFilePath() { - val rootFolderPath = tempFolder.root.absolutePath - val expectedLocalTestFilePath = "app/test/sample/ExampleTest.kt" - val expectedSharedTestFilePath = "app/sharedTest/sample/ExampleTest.kt" - - val sharedFile = File(rootFolderPath, expectedSharedTestFilePath) - sharedFile.parentFile?.mkdirs() - sharedFile.createNewFile() - - val localFile = File(rootFolderPath, expectedLocalTestFilePath) - localFile.parentFile?.mkdirs() - localFile.createNewFile() - - val expectedLocalAndSharedTestFilePaths = listOf( - expectedSharedTestFilePath, - expectedLocalTestFilePath - ) - - val result = RunCoverage( - rootFolderPath, - sampleFilePath, - commandExecutor, - scriptBgDispatcher - ).findTestFile(rootFolderPath, "app/main/sample/Example.kt") - - assertEquals(expectedLocalAndSharedTestFilePaths, result) - } - - @Test - fun testRunCoverage_AppPath_returnDefaultTestFilePath() { - val rootFolderPath = tempFolder.root.absolutePath - val expectedLocalTestFilePath = "util/test/sample/ExampleTest.kt" - val file = File(rootFolderPath, expectedLocalTestFilePath) - - file.parentFile?.mkdirs() - file.createNewFile() - - val expectedLocalTestFilePaths = listOf(expectedLocalTestFilePath) - - val result = RunCoverage( - rootFolderPath, - sampleFilePath, - commandExecutor, - scriptBgDispatcher - ).findTestFile(rootFolderPath, "util/main/sample/Example.kt") - - assertEquals(expectedLocalTestFilePaths, result) - } - @Test fun testRunCoverage_validSampleTestFile_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() @@ -482,12 +369,12 @@ class RunCoverageTest { sourceContent = sourceContent, testContentShared = testContentShared, testContentLocal = testContentLocal, - subpackage = "app/test" + subpackage = "app" ) val result = RunCoverage( "${tempFolder.root}", - "app/test/main/java/com/example/TwoSum.kt", + "app/main/java/com/example/TwoSum.kt", longCommandExecutor, scriptBgDispatcher ).execute() From 5229ecdd05ca9161cb60998b10533827a0833c61 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 19:19:53 +0530 Subject: [PATCH 059/105] Used kotlin patterns to simplify the and make it more readable --- .../android/scripts/coverage/RunCoverage.kt | 70 ++++++++----------- .../scripts/coverage/CoverageRunnerTest.kt | 6 +- 2 files changed, 32 insertions(+), 44 deletions(-) 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 e5f154dea16..07d2319ef5d 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -49,7 +49,7 @@ fun main(vararg args: String) { * * @param repoRoot the root directory of the repository * @param filePath the relative path to the file to analyse coverage - * @param commandExecutor Executes the specified command in the specified working directory + * @param commandExecutor executes the specified command in the specified working directory * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command */ class RunCoverage( @@ -76,19 +76,20 @@ class RunCoverage( val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() - val isExempted = testFileExemptionList.contains(filePath) - if (isExempted) { + if (filePath in testFileExemptionList) { println("This file is exempted from having a test file. Hence No coverage!") return mutableListOf() } val testFilePaths = findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) + println("Test file paths: $testFilePaths") + println("Test targets: $testTargets") for (testTarget in testTargets) { val coverageData = RunCoverageForTestTarget( rootDirectory, - testTarget.substringBeforeLast(".kt"), + testTarget.removeSuffix(".kt"), commandExecutor, scriptBgDispatcher ).runCoverage()!! @@ -99,49 +100,36 @@ class RunCoverage( } private fun findTestFile(repoRoot: String, filePath: String): List { - val file = File(filePath) - val parts = file.parent.split(File.separator) - val testFiles = mutableListOf() - - if (parts.isNotEmpty() && parts[0] == "scripts") { - val testFilePath = filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt") - if (File(repoRoot, testFilePath).exists()) { - testFiles.add(testFilePath) + val possibleTestFilePaths = when { + filePath.startsWith("scripts/") -> { + listOf(filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt")) } - } else if (parts.isNotEmpty() && parts[0] == "app") { - val sharedTestFilePath = filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt") - val testFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") - val localTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") - - if (File(repoRoot, sharedTestFilePath).exists()) { - testFiles.add(sharedTestFilePath) - } - if (File(repoRoot, testFilePath).exists()) { - testFiles.add(testFilePath) + filePath.startsWith("app/") -> { + listOf( + filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt"), + filePath.replace("/main/", "/test/").replace(".kt", "Test.kt"), + filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") + ) } - if (File(repoRoot, localTestFilePath).exists()) { - testFiles.add(localTestFilePath) - } - } else { - val defaultTestFilePath = filePath.replace("/main/", "/test/").replace(".kt", "Test.kt") - if (File(repoRoot, defaultTestFilePath).exists()) { - testFiles.add(defaultTestFilePath) + else -> { + listOf(filePath.replace("/main/", "/test/").replace(".kt", "Test.kt")) } } - return testFiles + + val repoRootFile = File(repoRoot).absoluteFile + + return possibleTestFilePaths + .map { File(repoRootFile, it) } + .filter(File::exists) + .map { it.relativeTo(repoRootFile).path } } + private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { - val protoBinaryFile = File("$testFileExemptiontextProto.pb") - val builder = TestFileExemptions.getDefaultInstance().newBuilderForType() - - // This cast is type-safe since proto guarantees type consistency from mergeFrom(), - // and this method is bounded by the generic type T. - @Suppress("UNCHECKED_CAST") - val protoObj: TestFileExemptions = - FileInputStream(protoBinaryFile).use { - builder.mergeFrom(it) - }.build() as TestFileExemptions - return protoObj + return File("$testFileExemptiontextProto.pb").inputStream().use { stream -> + TestFileExemptions.newBuilder().also { builder -> + builder.mergeFrom(stream) + }.build() + } } } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 5b6a8a62047..6a89e9db798 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -37,7 +37,7 @@ class CoverageRunnerTest { } @Test - fun testCoverageRunner_emptyDirectory_throwsException() { + fun testRunWithCoverageAsync_emptyDirectory_throwsException() { val exception = assertThrows() { runBlocking { coverageRunner.runWithCoverageAsync(bazelTestTarget).await() @@ -48,7 +48,7 @@ class CoverageRunnerTest { } @Test - fun testCoverageRunner_invalidTestTarget_throwsException() { + fun testRunWithCoverageAsync_invalidTestTarget_throwsException() { testBazelWorkspace.initEmptyWorkspace() val exception = assertThrows() { @@ -62,7 +62,7 @@ class CoverageRunnerTest { } @Test - fun testCoverageRunner_validSampleTestTarget_returnsCoverageData() { + fun testRunWithCoverageAsync_validSampleTestTarget_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = From d9ad634dadf957520b466769a0b1d5711782cee1 Mon Sep 17 00:00:00 2001 From: Rd Date: Sat, 22 Jun 2024 20:16:44 +0530 Subject: [PATCH 060/105] Returning the coverageDataList as immutable list --- .../android/scripts/coverage/RunCoverage.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) 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 07d2319ef5d..7d625c843b6 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -70,15 +70,18 @@ class RunCoverage( * prints a message indicating no coverage analysis is performed. Otherwise, initializes * a Bazel client, finds potential test file paths, retrieves Bazel targets, and initiates * coverage analysis for each test target found. + * + * @return a list of lists containing coverage data for each requested test target, if + * the file is exempted from having a test file, an empty list is returned */ - fun execute(): MutableList> { + fun execute(): List> { var coverageDataList = mutableListOf>() val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() if (filePath in testFileExemptionList) { println("This file is exempted from having a test file. Hence No coverage!") - return mutableListOf() + return emptyList() } val testFilePaths = findTestFile(repoRoot, filePath) @@ -92,11 +95,16 @@ class RunCoverage( testTarget.removeSuffix(".kt"), commandExecutor, scriptBgDispatcher - ).runCoverage()!! - coverageDataList.add(coverageData) + ).runCoverage() + + if (coverageData != null) { + coverageDataList.add(coverageData) + } else { + println("Coverage data for $testTarget is null") + } } println("Coverage Data List: $coverageDataList") - return coverageDataList + return coverageDataList.toList() } private fun findTestFile(repoRoot: String, filePath: String): List { From ac4c82b49138d5238d6ec9538e96f229a20e412f Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 23 Jun 2024 08:05:54 +0530 Subject: [PATCH 061/105] Fix Lint Checks --- .../java/org/oppia/android/scripts/coverage/RunCoverage.kt | 2 -- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) 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 7d625c843b6..4ca3cd4beaf 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -6,7 +6,6 @@ import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.proto.TestFileExemptions import java.io.File -import java.io.FileInputStream import java.util.concurrent.TimeUnit /** @@ -132,7 +131,6 @@ class RunCoverage( .map { it.relativeTo(repoRootFile).path } } - private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { return File("$testFileExemptiontextProto.pb").inputStream().use { stream -> TestFileExemptions.newBuilder().also { builder -> diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 617a4b3ac7c..a213f71f473 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -2,7 +2,6 @@ package org.oppia.android.scripts.coverage import com.google.common.truth.Truth.assertThat import org.junit.After -import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule import org.junit.Test @@ -11,7 +10,6 @@ import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.testing.TestBazelWorkspace import java.io.ByteArrayOutputStream -import java.io.File import java.io.PrintStream import java.util.concurrent.TimeUnit @@ -401,7 +399,8 @@ class RunCoverageTest { "LH:3", "LF:4", "end_of_record" - ),listOf( + ), + listOf( "SF:app/main/java/com/example/TwoSum.kt", "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", "FN:3,com/example/TwoSum:: ()V", From 6eb90c7accce5e17527f20bf7e7574afe040b31e Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 23 Jun 2024 20:02:53 +0530 Subject: [PATCH 062/105] Fixed Multi Level Source and Test File coverage execution by adding the instrumentation filter --- .../android/scripts/common/BazelClient.kt | 3 +- .../scripts/testing/TestBazelWorkspaceTest.kt | 156 ++++++++++++++++++ 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 62ce53bfb82..2b3878d44ff 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -144,7 +144,8 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: fun runCoverageForTestTarget(bazelTestTarget: String): List? { val coverageCommandOutputLines = executeBazelCommand( "coverage", - bazelTestTarget + bazelTestTarget, + "--instrumentation_filter=//" ) return parseCoverageDataFilePath(coverageCommandOutputLines)?.let { path -> File(path).readLines() diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index 4c81c768db6..c373969951b 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -353,6 +353,162 @@ class TestBazelWorkspaceTest { ) } + @Test + fun testAddMultiLevelSourceAndTestFileWithContent_createsSourceAndTestFiles() { + val testBazelWorkspace = TestBazelWorkspace(tempFolder) + val sourceContent = + """ + fun main() { + println("Hello, World!") + } + """ + + val testContentShared = + """ + import org.junit.Test + import kotlin.test.assertEquals + + class MainTest { + + @Test + fun testMain() { + assertEquals(1, 1) + } + } + """ + + val testContentLocal = + """ + import org.junit.Test + import kotlin.test.assertEquals + + class MainTestLocal { + + @Test + fun testMain() { + assertEquals(1, 2) + } + } + """ + + testBazelWorkspace.addMultiLevelSourceAndTestFileWithContent( + filename = "Main", + sourceContent = sourceContent, + testContentShared = testContentShared, + testContentLocal = testContentLocal, + subpackage = "coverage" + ) + + val sourceFile = File(tempFolder.root, "coverage/main/java/com/example/Main.kt") + val testFileShared = File(tempFolder.root, "coverage/sharedTest/java/com/example/MainTest.kt") + val testFileLocal = File(tempFolder.root, "coverage/test/java/com/example/MainLocalTest.kt") + + assertThat(sourceFile.exists()).isTrue() + assertThat(sourceFile.readText()).isEqualTo(sourceContent) + + assertThat(testFileShared.exists()).isTrue() + assertThat(testFileShared.readText()).isEqualTo(testContentShared) + + assertThat(testFileLocal.exists()).isTrue() + assertThat(testFileLocal.readText()).isEqualTo(testContentLocal) + } + + @Test + fun testAddMultiLevelSourceAndTestFileWithContent_updatesBuildFiles() { + val testBazelWorkspace = TestBazelWorkspace(tempFolder) + val sourceContent = + """ + fun main() { + println("Hello, World!") + } + """ + + val testContentShared = + """ + import org.junit.Test + import kotlin.test.assertEquals + + class MainTest { + + @Test + fun testMain() { + assertEquals(1, 1) + } + } + """ + + val testContentLocal = + """ + import org.junit.Test + import kotlin.test.assertEquals + + class MainTestLocal { + + @Test + fun testMain() { + assertEquals(1, 2) + } + } + """ + + testBazelWorkspace.addMultiLevelSourceAndTestFileWithContent( + filename = "Main", + sourceContent = sourceContent, + testContentShared = testContentShared, + testContentLocal = testContentLocal, + subpackage = "coverage" + ) + + val sourceBuildFile = File(tempFolder.root, "coverage/main/java/com/example/BUILD.bazel") + val testBuildFileShared = File(tempFolder.root, "coverage/sharedTest/java/com/example/BUILD.bazel") + val testBuildFileLocal = File(tempFolder.root, "coverage/test/java/com/example/BUILD.bazel") + + assertThat(sourceBuildFile.exists()).isTrue() + assertThat(sourceBuildFile.readText()).contains( + """ + kt_jvm_library( + name = "main", + srcs = ["Main.kt"], + visibility = ["//visibility:public"] + ) + """.trimIndent() + ) + + assertThat(testBuildFileShared.exists()).isTrue() + assertThat(testBuildFileShared.readText()).contains( + """ + load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") + kt_jvm_test( + name = "MainTest", + srcs = ["MainTest.kt"], + deps = [ + "//coverage/main/java/com/example:main", + "@maven//:junit_junit", + ], + visibility = ["//visibility:public"], + test_class = "com.example.MainTest", + ) + """.trimIndent() + ) + + assertThat(testBuildFileLocal.exists()).isTrue() + assertThat(testBuildFileLocal.readText()).contains( + """ + load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") + kt_jvm_test( + name = "MainLocalTest", + srcs = ["MainLocalTest.kt"], + deps = [ + "//coverage/main/java/com/example:main", + "@maven//:junit_junit", + ], + visibility = ["//visibility:public"], + test_class = "com.example.MainLocalTest", + ) + """.trimIndent() + ) + } + @Test fun testAddSourceContentAndBuildFile_createsSourceFileAndBuildFile() { val testBazelWorkspace = TestBazelWorkspace(tempFolder) From 68c714b7dff803b5a667d1984e411d60c3c35434 Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 23 Jun 2024 20:10:33 +0530 Subject: [PATCH 063/105] Fix Lint Check --- .../scripts/testing/TestBazelWorkspaceTest.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index c373969951b..b52113e817d 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -459,9 +459,15 @@ class TestBazelWorkspaceTest { subpackage = "coverage" ) - val sourceBuildFile = File(tempFolder.root, "coverage/main/java/com/example/BUILD.bazel") - val testBuildFileShared = File(tempFolder.root, "coverage/sharedTest/java/com/example/BUILD.bazel") - val testBuildFileLocal = File(tempFolder.root, "coverage/test/java/com/example/BUILD.bazel") + val sourceBuildFile = File( + tempFolder.root, "coverage/main/java/com/example/BUILD.bazel" + ) + val testBuildFileShared = File( + tempFolder.root, "coverage/sharedTest/java/com/example/BUILD.bazel" + ) + val testBuildFileLocal = File( + tempFolder.root, "coverage/test/java/com/example/BUILD.bazel" + ) assertThat(sourceBuildFile.exists()).isTrue() assertThat(sourceBuildFile.readText()).contains( From e0be83a2fa9d7258a4ac146e1f1fc6655076a64f Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 23 Jun 2024 20:50:55 +0530 Subject: [PATCH 064/105] Removed RunCoverageForTestTarget as it is redundant --- scripts/BUILD.bazel | 9 - .../android/scripts/coverage/BUILD.bazel | 15 +- .../android/scripts/coverage/RunCoverage.kt | 17 +- .../coverage/RunCoverageForTestTarget.kt | 86 ---------- .../android/scripts/coverage/BUILD.bazel | 12 -- .../coverage/RunCoverageForTestTargetTest.kt | 154 ------------------ 6 files changed, 9 insertions(+), 284 deletions(-) delete mode 100644 scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt delete mode 100644 scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index a895764d5f2..2fba670d34e 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -237,15 +237,6 @@ kt_jvm_binary( ], ) -kt_jvm_binary( - name = "run_coverage_for_test_target", - testonly = True, - main_class = "org.oppia.android.scripts.coverage.RunCoverageForTestTargetKt", - runtime_deps = [ - "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", - ], -) - kt_jvm_binary( name = "run_coverage", testonly = True, diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 9a484e0bc35..4d3594ea482 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -11,23 +11,10 @@ kt_jvm_library( "RunCoverage.kt", ], visibility = ["//scripts:oppia_script_binary_visibility"], - deps = [ - "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", - "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", - "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", - ], -) - -kt_jvm_library( - name = "run_coverage_for_test_target_lib", - testonly = True, - srcs = [ - "RunCoverageForTestTarget.kt", - ], - visibility = ["//scripts:oppia_script_binary_visibility"], deps = [ "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", + "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", ], ) 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 4ca3cd4beaf..06eb98e5b6c 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -1,5 +1,6 @@ package org.oppia.android.scripts.coverage +import kotlinx.coroutines.runBlocking import org.oppia.android.scripts.common.BazelClient import org.oppia.android.scripts.common.CommandExecutor import org.oppia.android.scripts.common.CommandExecutorImpl @@ -85,16 +86,15 @@ class RunCoverage( val testFilePaths = findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) - println("Test file paths: $testFilePaths") - println("Test targets: $testTargets") for (testTarget in testTargets) { - val coverageData = RunCoverageForTestTarget( - rootDirectory, - testTarget.removeSuffix(".kt"), - commandExecutor, - scriptBgDispatcher - ).runCoverage() + val coverageData = runBlocking { + val result = + CoverageRunner(rootDirectory, scriptBgDispatcher, commandExecutor) + .runWithCoverageAsync(testTarget.removeSuffix(".kt")) + .await() + result + } if (coverageData != null) { coverageDataList.add(coverageData) @@ -102,7 +102,6 @@ class RunCoverage( println("Coverage data for $testTarget is null") } } - println("Coverage Data List: $coverageDataList") return coverageDataList.toList() } diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt deleted file mode 100644 index 6875bd9141f..00000000000 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ /dev/null @@ -1,86 +0,0 @@ -package org.oppia.android.scripts.coverage - -import kotlinx.coroutines.runBlocking -import org.oppia.android.scripts.common.CommandExecutor -import org.oppia.android.scripts.common.CommandExecutorImpl -import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import java.io.File -import java.util.concurrent.TimeUnit - -/** - * Entry point function for running coverage analysis for a single test target. - * - * Usage: - * bazel run //scripts:run_coverage_for_test_target -- - * - * Arguments: - * - path_to_root: directory path to the root of the Oppia Android repository - * - test_targetname: bazel target name of the test - * - * Example: - * bazel run //scripts:run_coverage_for_test_target -- $(pwd) - * //utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest - * Example with custom process timeout: - * bazel run //scripts:run_coverage_for_test_target -- $(pwd) - * //utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest processTimeout=10 - * - */ -fun main(vararg args: String) { - val repoRoot = File(args[0]).absoluteFile.normalize() - val targetPath = args[1] - - ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> - val processTimeout: Long = args.find { it.startsWith("processTimeout=") } - ?.substringAfter("=") - ?.toLongOrNull() ?: 5 - - val commandExecutor: CommandExecutor = CommandExecutorImpl( - scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES - ) - - RunCoverageForTestTarget( - repoRoot, - targetPath, - commandExecutor, - scriptBgDispatcher - ).runCoverage() - } -} - -/** - * Class responsible for analyzing target files for coverage and generating reports. - * - * @param repoRoot the root directory of the repository - * @param targetPath Bazel test target to analyze coverage - * @param commandExecutor executes the specified command in the specified working directory - * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command - */ -class RunCoverageForTestTarget( - private val repoRoot: File, - private val targetPath: String, - private val commandExecutor: CommandExecutor, - private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher -) { - - /** - * Analyzes target file for coverage, generates chosen reports accordingly. - */ - fun runCoverage(): List? { - return runWithCoverageAnalysis() - } - - /** - * Runs coverage analysis on the specified target file asynchronously. - * - * @return the generated coverage data - */ - fun runWithCoverageAnalysis(): List? { - return runBlocking { - val result = - CoverageRunner(repoRoot, scriptBgDispatcher, commandExecutor) - .runWithCoverageAsync(targetPath) - .await() - result - } - } -} diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel index 49226a9e4f7..6c200e83d8a 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel @@ -16,18 +16,6 @@ kt_jvm_test( ], ) -kt_jvm_test( - name = "RunCoverageForTestTargetTest", - srcs = ["RunCoverageForTestTargetTest.kt"], - deps = [ - "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", - "//scripts/src/java/org/oppia/android/scripts/testing:test_bazel_workspace", - "//testing:assertion_helpers", - "//third_party:com_google_truth_truth", - "//third_party:org_jetbrains_kotlin_kotlin-test-junit", - ], -) - kt_jvm_test( name = "RunCoverageTest", srcs = ["RunCoverageTest.kt"], diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt deleted file mode 100644 index 27b4e20bf08..00000000000 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ /dev/null @@ -1,154 +0,0 @@ -package org.oppia.android.scripts.coverage - -import com.google.common.truth.Truth.assertThat -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder -import org.oppia.android.scripts.common.CommandExecutorImpl -import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.scripts.testing.TestBazelWorkspace -import org.oppia.android.testing.assertThrows -import java.util.concurrent.TimeUnit - -/** Tests for [RunCoverageForTestTarget]. */ -class RunCoverageForTestTargetTest { - @field:[Rule JvmField] val tempFolder = TemporaryFolder() - - private val scriptBgDispatcher by lazy { ScriptBackgroundCoroutineDispatcher() } - private val commandExecutor by lazy { CommandExecutorImpl(scriptBgDispatcher) } - private val longCommandExecutor by lazy { initializeCommandExecutorWithLongProcessWaitTime() } - - private lateinit var testBazelWorkspace: TestBazelWorkspace - private lateinit var bazelTestTarget: String - - @Before - fun setUp() { - bazelTestTarget = "//:testTarget" - testBazelWorkspace = TestBazelWorkspace(tempFolder) - } - - @After - fun tearDown() { - scriptBgDispatcher.close() - } - - @Test - fun testRunCoverageForTestTarget_emptyDirectory_throwsException() { - val exception = assertThrows() { - RunCoverageForTestTarget( - tempFolder.root, - bazelTestTarget, - commandExecutor, - scriptBgDispatcher - ).runCoverage() - } - - assertThat(exception).hasMessageThat().contains("not invoked from within a workspace") - } - - @Test - fun testRunCoverageForTestTarget_invalidTestTarget_throwsException() { - testBazelWorkspace.initEmptyWorkspace() - - val exception = assertThrows() { - RunCoverageForTestTarget( - tempFolder.root, - bazelTestTarget, - commandExecutor, - scriptBgDispatcher - ).runCoverage() - } - - assertThat(exception).hasMessageThat().contains("Expected non-zero exit code") - assertThat(exception).hasMessageThat().contains("no such package") - } - - @Test - fun testRunCoverageForTestTarget_validSampleTestTarget_returnsCoverageDataPath() { - testBazelWorkspace.initEmptyWorkspace() - - val sourceContent = - """ - package com.example - - class TwoSum { - - companion object { - fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { - "Both numbers are zero" - } else { - a + b - } - } - } - } - """.trimIndent() - - val testContent = - """ - package com.example - - import org.junit.Assert.assertEquals - import org.junit.Test - - class TwoSumTest { - - @Test - fun testSumNumbers() { - assertEquals(TwoSum.sumNumbers(0, 1), 1) - assertEquals(TwoSum.sumNumbers(3, 4), 7) - assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") - } - } - """.trimIndent() - - testBazelWorkspace.addSourceAndTestFileWithContent( - filename = "TwoSum", - sourceContent = sourceContent, - testContent = testContent, - sourceSubpackage = "coverage/main/java/com/example", - testSubpackage = "coverage/test/java/com/example" - ) - - val result = RunCoverageForTestTarget( - tempFolder.root, - "//coverage/test/java/com/example:TwoSumTest", - longCommandExecutor, - scriptBgDispatcher - ).runCoverage() - - val expectedResult = listOf( - "SF:coverage/main/java/com/example/TwoSum.kt", - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FN:3,com/example/TwoSum:: ()V", - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FNDA:0,com/example/TwoSum:: ()V", - "FNF:2", - "FNH:1", - "BRDA:7,0,0,1", - "BRDA:7,0,1,1", - "BRDA:7,0,2,1", - "BRDA:7,0,3,1", - "BRF:4", - "BRH:4", - "DA:3,0", - "DA:7,1", - "DA:8,1", - "DA:10,1", - "LH:3", - "LF:4", - "end_of_record" - ) - - assertThat(result).isEqualTo(expectedResult) - } - - private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { - return CommandExecutorImpl( - scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES - ) - } -} From c834aa77f3e6e71b3f15dcf7d606a2f889b4271b Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 23 Jun 2024 22:11:11 +0530 Subject: [PATCH 065/105] Removed the RunCoverageForTestTarget as the functionality will be re-introduced through RunCoverage.kt script --- scripts/BUILD.bazel | 9 -- .../android/scripts/coverage/BUILD.bazel | 15 -- .../coverage/RunCoverageForTestTarget.kt | 86 ---------- .../coverage/RunCoverageForTestTargetTest.kt | 153 ------------------ 4 files changed, 263 deletions(-) delete mode 100644 scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt delete mode 100644 scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 23587533fa0..689cf6e53d2 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -237,15 +237,6 @@ kt_jvm_binary( ], ) -kt_jvm_binary( - name = "run_coverage_for_test_target", - testonly = True, - main_class = "org.oppia.android.scripts.coverage.RunCoverageForTestTargetKt", - runtime_deps = [ - "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", - ], -) - # Note that this is intentionally not test-only since it's used by the app build pipeline. Also, # this apparently needs to be a java_binary to set up runfiles correctly when executed within a # Starlark rule as a tool. diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 53f09dbb98c..4c7ab41a5fa 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -4,20 +4,6 @@ Libraries corresponding to developer scripts that obtain coverage data for test load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") -kt_jvm_library( - name = "run_coverage_for_test_target_lib", - testonly = True, - srcs = [ - "RunCoverageForTestTarget.kt", - ], - visibility = ["//scripts:oppia_script_binary_visibility"], - deps = [ - "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", - "//scripts/src/java/org/oppia/android/scripts/common:git_client", - "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", - ], -) - kt_jvm_library( name = "coverage_runner", testonly = True, @@ -27,6 +13,5 @@ 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/common:git_client", ], ) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt deleted file mode 100644 index 6875bd9141f..00000000000 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverageForTestTarget.kt +++ /dev/null @@ -1,86 +0,0 @@ -package org.oppia.android.scripts.coverage - -import kotlinx.coroutines.runBlocking -import org.oppia.android.scripts.common.CommandExecutor -import org.oppia.android.scripts.common.CommandExecutorImpl -import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import java.io.File -import java.util.concurrent.TimeUnit - -/** - * Entry point function for running coverage analysis for a single test target. - * - * Usage: - * bazel run //scripts:run_coverage_for_test_target -- - * - * Arguments: - * - path_to_root: directory path to the root of the Oppia Android repository - * - test_targetname: bazel target name of the test - * - * Example: - * bazel run //scripts:run_coverage_for_test_target -- $(pwd) - * //utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest - * Example with custom process timeout: - * bazel run //scripts:run_coverage_for_test_target -- $(pwd) - * //utility/src/test/java/org/oppia/android/util/parser/math:MathModelTest processTimeout=10 - * - */ -fun main(vararg args: String) { - val repoRoot = File(args[0]).absoluteFile.normalize() - val targetPath = args[1] - - ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> - val processTimeout: Long = args.find { it.startsWith("processTimeout=") } - ?.substringAfter("=") - ?.toLongOrNull() ?: 5 - - val commandExecutor: CommandExecutor = CommandExecutorImpl( - scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES - ) - - RunCoverageForTestTarget( - repoRoot, - targetPath, - commandExecutor, - scriptBgDispatcher - ).runCoverage() - } -} - -/** - * Class responsible for analyzing target files for coverage and generating reports. - * - * @param repoRoot the root directory of the repository - * @param targetPath Bazel test target to analyze coverage - * @param commandExecutor executes the specified command in the specified working directory - * @param scriptBgDispatcher the [ScriptBackgroundCoroutineDispatcher] to be used for running the coverage command - */ -class RunCoverageForTestTarget( - private val repoRoot: File, - private val targetPath: String, - private val commandExecutor: CommandExecutor, - private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher -) { - - /** - * Analyzes target file for coverage, generates chosen reports accordingly. - */ - fun runCoverage(): List? { - return runWithCoverageAnalysis() - } - - /** - * Runs coverage analysis on the specified target file asynchronously. - * - * @return the generated coverage data - */ - fun runWithCoverageAnalysis(): List? { - return runBlocking { - val result = - CoverageRunner(repoRoot, scriptBgDispatcher, commandExecutor) - .runWithCoverageAsync(targetPath) - .await() - result - } - } -} diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt deleted file mode 100644 index f696a8f1059..00000000000 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageForTestTargetTest.kt +++ /dev/null @@ -1,153 +0,0 @@ -package org.oppia.android.scripts.coverage - -import com.google.common.truth.Truth.assertThat -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder -import org.oppia.android.scripts.common.CommandExecutorImpl -import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.scripts.testing.TestBazelWorkspace -import org.oppia.android.testing.assertThrows -import java.util.concurrent.TimeUnit - -/** Tests for [RunCoverageForTestTarget]. */ -class RunCoverageForTestTargetTest { - @field:[Rule JvmField] val tempFolder = TemporaryFolder() - - private val scriptBgDispatcher by lazy { ScriptBackgroundCoroutineDispatcher() } - private val commandExecutor by lazy { CommandExecutorImpl(scriptBgDispatcher) } - private val longCommandExecutor by lazy { initializeCommandExecutorWithLongProcessWaitTime() } - - private lateinit var testBazelWorkspace: TestBazelWorkspace - private lateinit var bazelTestTarget: String - - @Before - fun setUp() { - bazelTestTarget = "//:testTarget" - testBazelWorkspace = TestBazelWorkspace(tempFolder) - } - - @After - fun tearDown() { - scriptBgDispatcher.close() - } - - @Test - fun testRunCoverageForTestTarget_emptyDirectory_throwsException() { - val exception = assertThrows() { - RunCoverageForTestTarget( - tempFolder.root, - bazelTestTarget, - commandExecutor, - scriptBgDispatcher - ).runCoverage() - } - - assertThat(exception).hasMessageThat().contains("not invoked from within a workspace") - } - - @Test - fun testRunCoverageForTestTarget_invalidTestTarget_throwsException() { - testBazelWorkspace.initEmptyWorkspace() - - val exception = assertThrows() { - RunCoverageForTestTarget( - tempFolder.root, - bazelTestTarget, - commandExecutor, - scriptBgDispatcher - ).runCoverage() - } - - assertThat(exception).hasMessageThat().contains("Expected non-zero exit code") - assertThat(exception).hasMessageThat().contains("no such package") - } - - @Test - fun testRunCoverageForTestTarget_validSampleTestTarget_returnsCoverageDataPath() { - testBazelWorkspace.initEmptyWorkspace() - - val sourceContent = - """ - package com.example - - class TwoSum { - - companion object { - fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { - "Both numbers are zero" - } else { - a + b - } - } - } - } - """.trimIndent() - - val testContent = - """ - package com.example - - import org.junit.Assert.assertEquals - import org.junit.Test - - class TwoSumTest { - - @Test - fun testSumNumbers() { - assertEquals(TwoSum.sumNumbers(0, 1), 1) - assertEquals(TwoSum.sumNumbers(3, 4), 7) - assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") - } - } - """.trimIndent() - - testBazelWorkspace.addSourceAndTestFileWithContent( - filename = "TwoSum", - sourceContent = sourceContent, - testContent = testContent, - subpackage = "coverage" - ) - - val result = RunCoverageForTestTarget( - tempFolder.root, - "//coverage/test/java/com/example:test", - longCommandExecutor, - scriptBgDispatcher - ).runCoverage() - - val expectedResult = listOf( - "SF:coverage/main/java/com/example/TwoSum.kt", - "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FN:3,com/example/TwoSum:: ()V", - "FNDA:1,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", - "FNDA:0,com/example/TwoSum:: ()V", - "FNF:2", - "FNH:1", - "BRDA:7,0,0,1", - "BRDA:7,0,1,1", - "BRDA:7,0,2,1", - "BRDA:7,0,3,1", - "BRF:4", - "BRH:4", - "DA:3,0", - "DA:7,1", - "DA:8,1", - "DA:10,1", - "LH:3", - "LF:4", - "end_of_record" - ) - - assertThat(result).isEqualTo(expectedResult) - } - - private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { - return CommandExecutorImpl( - scriptBgDispatcher, processTimeout = 5, processTimeoutUnit = TimeUnit.MINUTES - ) - } -} From c654eed56f481ba8b709fd0ad2156b9534e54b56 Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 23 Jun 2024 22:51:32 +0530 Subject: [PATCH 066/105] Removed the RunCoverageForTestTarget Build inclusions --- .../org/oppia/android/scripts/coverage/BUILD.bazel | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel index cb20129dd61..f2e5c80564b 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel @@ -15,15 +15,3 @@ kt_jvm_test( "//third_party:org_jetbrains_kotlin_kotlin-test-junit", ], ) - -kt_jvm_test( - name = "RunCoverageForTestTargetTest", - srcs = ["RunCoverageForTestTargetTest.kt"], - deps = [ - "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_for_test_target_lib", - "//scripts/src/java/org/oppia/android/scripts/testing:test_bazel_workspace", - "//testing:assertion_helpers", - "//third_party:com_google_truth_truth", - "//third_party:org_jetbrains_kotlin_kotlin-test-junit", - ], -) From 03062585775ddb6d66d55827d4927035b61bc849 Mon Sep 17 00:00:00 2001 From: Rd Date: Sun, 23 Jun 2024 23:16:26 +0530 Subject: [PATCH 067/105] Refactor execute to use separate helper functions --- .../android/scripts/coverage/RunCoverage.kt | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) 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 06eb98e5b6c..be420c556c1 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -87,15 +87,8 @@ class RunCoverage( val testFilePaths = findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) - for (testTarget in testTargets) { - val coverageData = runBlocking { - val result = - CoverageRunner(rootDirectory, scriptBgDispatcher, commandExecutor) - .runWithCoverageAsync(testTarget.removeSuffix(".kt")) - .await() - result - } - + testTargets.forEach { testTarget -> + val coverageData = runCoverageForTarget(testTarget) if (coverageData != null) { coverageDataList.add(coverageData) } else { @@ -105,36 +98,44 @@ class RunCoverage( return coverageDataList.toList() } - private fun findTestFile(repoRoot: String, filePath: String): List { - val possibleTestFilePaths = when { - filePath.startsWith("scripts/") -> { - listOf(filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt")) - } - filePath.startsWith("app/") -> { - listOf( - filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt"), - filePath.replace("/main/", "/test/").replace(".kt", "Test.kt"), - filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") - ) - } - else -> { - listOf(filePath.replace("/main/", "/test/").replace(".kt", "Test.kt")) - } + private fun runCoverageForTarget(testTarget: String): List? { + return runBlocking { + CoverageRunner(rootDirectory, scriptBgDispatcher, commandExecutor) + .runWithCoverageAsync(testTarget.removeSuffix(".kt")) + .await() } - - val repoRootFile = File(repoRoot).absoluteFile - - return possibleTestFilePaths - .map { File(repoRootFile, it) } - .filter(File::exists) - .map { it.relativeTo(repoRootFile).path } } +} - private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { - return File("$testFileExemptiontextProto.pb").inputStream().use { stream -> - TestFileExemptions.newBuilder().also { builder -> - builder.mergeFrom(stream) - }.build() +private fun findTestFile(repoRoot: String, filePath: String): List { + val possibleTestFilePaths = when { + filePath.startsWith("scripts/") -> { + listOf(filePath.replace("/java/", "/javatests/").replace(".kt", "Test.kt")) } + filePath.startsWith("app/") -> { + listOf( + filePath.replace("/main/", "/sharedTest/").replace(".kt", "Test.kt"), + filePath.replace("/main/", "/test/").replace(".kt", "Test.kt"), + filePath.replace("/main/", "/test/").replace(".kt", "LocalTest.kt") + ) + } + else -> { + listOf(filePath.replace("/main/", "/test/").replace(".kt", "Test.kt")) + } + } + + val repoRootFile = File(repoRoot).absoluteFile + + return possibleTestFilePaths + .map { File(repoRootFile, it) } + .filter(File::exists) + .map { it.relativeTo(repoRootFile).path } +} + +private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { + return File("$testFileExemptiontextProto.pb").inputStream().use { stream -> + TestFileExemptions.newBuilder().also { builder -> + builder.mergeFrom(stream) + }.build() } } From 61796996352324361e595e2e59452aded4c82973 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 24 Jun 2024 00:10:28 +0530 Subject: [PATCH 068/105] Used mapNotNull to avoid mutability --- .../org/oppia/android/scripts/coverage/RunCoverage.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) 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 be420c556c1..e0dbe594bef 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -40,7 +40,7 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute() + println(RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute()) } } @@ -75,7 +75,6 @@ class RunCoverage( * the file is exempted from having a test file, an empty list is returned */ fun execute(): List> { - var coverageDataList = mutableListOf>() val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() @@ -87,15 +86,13 @@ class RunCoverage( val testFilePaths = findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) - testTargets.forEach { testTarget -> + return testTargets.mapNotNull { testTarget -> val coverageData = runCoverageForTarget(testTarget) - if (coverageData != null) { - coverageDataList.add(coverageData) - } else { + if (coverageData == null) { println("Coverage data for $testTarget is null") } + coverageData } - return coverageDataList.toList() } private fun runCoverageForTarget(testTarget: String): List? { From 83eb03580fc9fb8cd52f62705862b7e0d678a77c Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 24 Jun 2024 11:29:07 +0530 Subject: [PATCH 069/105] Updated with the revised proto structure and added docs --- .../android/scripts/proto/coverage.proto | 41 ++- .../scripts/coverage/CoverageRunnerTest.kt | 82 +++-- .../scripts/coverage/RunCoverageTest.kt | 338 ++++++++++-------- 3 files changed, 277 insertions(+), 184 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto b/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto index 97d0cd44710..133ef500947 100644 --- a/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto +++ b/scripts/src/java/org/oppia/android/scripts/proto/coverage.proto @@ -5,47 +5,80 @@ package proto; option java_package = "org.oppia.android.scripts.proto"; option java_multiple_files = true; +// Coverage Report that contains the bazel coverage data retrieved from the +// Bazel coverage execution. message CoverageReport { + // The test target for which the coverage report is generated. string bazel_test_target = 1; + // A list of files covered in this coverage report. repeated CoveredFile covered_file = 2; } +// Information about the single file that was covered during the tests. message CoveredFile { + // The relative path of the covered file. string file_path = 1; + // SHA-1 hash of the file content at the time of report (to guard against changes). string file_sha1_hash = 2; + // The lines of code covered in the report. repeated CoveredLine covered_line = 3; + // The total number of lines found in the covered file. int32 lines_found = 4; + // The total number of lines hit in the covered file. int32 lines_hit = 5; + // The functions covered in the report. Function coverage indicates which functions + // were executed during the tests and how many times each function was executed. repeated FunctionCoverage function_coverage = 6; + // The total number of functions found in the covered file. int32 functions_found = 7; + // The total number of functions hit in the covered file. int32 functions_hit = 8; + // The branches covered in the report. Branch coverage shows different code paths + // executed within conditional statements and how many times each was executed. repeated BranchCoverage branch_coverage = 9; + // The total number of branches found in the covered file. int32 branches_found = 10; + // The total number of branches hit in the covered file. int32 branches_hit = 11; } +// Information about a single line that was covered during the tests. message CoveredLine { + // The line number of the covered line. int32 line_number = 1; + // The coverage status of the covered line. Coverage coverage = 2; } +// Information about branch coverage for a specific line. message BranchCoverage { + // The line number of where the branch is located in the covered file. int32 line_number = 1; - optional int32 block_number = 2; - optional int32 branch_number = 3; - optional int32 hit_count = 4; + // Block number and branch number are gcc internal IDs for the branch. + int32 block_number = 2; + int32 branch_number = 3; + // The number of times the branch was executed. + int32 hit_count = 4; + // The coverage status of the covered line. Coverage coverage = 5; } message FunctionCoverage { + // The line number of where the function is located in the covered file. int32 line_number = 1; + // The name of the function in the covered file. string function_name = 2; - optional int32 execution_count = 3; + // The number of times the function is executed. + int32 execution_count = 3; + // The coverage status of the covered line. Coverage coverage = 4; } enum Coverage { + // Coverage status is unspecified. UNSPECIFIED = 0; + // The line, branch, or function is fully covered, ie. executed atleast once. FULL = 1; + // The line, branch, or function is not covered at all. NONE = 2; } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 3228de4c638..2118ff18d8e 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -9,13 +9,13 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.scripts.proto.BranchCoverage import org.oppia.android.scripts.proto.Coverage 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.FunctionCoverage +import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import java.util.concurrent.TimeUnit @@ -130,42 +130,54 @@ class CoverageRunnerTest { .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) .setLinesFound(4) .setLinesHit(3) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build()) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build()) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(Coverage.NONE).build() + ) .setFunctionsFound(2) .setFunctionsHit(1) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) .setBranchesFound(4) .setBranchesHit(4) .build() diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 35af2e58bd2..7dc9952c2dd 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -125,52 +125,64 @@ class RunCoverageTest { .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) .setLinesFound(4) .setLinesHit(3) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build()) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build()) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(Coverage.NONE).build() + ) .setFunctionsFound(2) .setFunctionsHit(1) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) .setBranchesFound(4) .setBranchesHit(4) .build() val expectedResult = listOf( CoverageReport.newBuilder() - .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .addCoveredFile(expectedCoveredFile) - .build() - ) + .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") + .addCoveredFile(expectedCoveredFile) + .build() + ) assertThat(result).isEqualTo(expectedResult) } @@ -187,7 +199,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -232,49 +244,61 @@ class RunCoverageTest { val expectedCoveredFile = CoveredFile.newBuilder() .setFilePath("scripts/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .setFileSha1Hash("1020b8f405555b3f4537fd07b912d3fb9ffa3354") .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) .setLinesFound(4) .setLinesHit(3) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build()) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build()) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(Coverage.NONE).build() + ) .setFunctionsFound(2) .setFunctionsHit(1) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) .setBranchesFound(4) .setBranchesHit(4) .build() @@ -353,42 +377,54 @@ class RunCoverageTest { .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) .setLinesFound(4) .setLinesHit(3) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build()) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build()) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(Coverage.NONE).build() + ) .setFunctionsFound(2) .setFunctionsHit(1) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) .setBranchesFound(4) .setBranchesHit(4) .build() @@ -485,51 +521,63 @@ class RunCoverageTest { .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) .setLinesFound(4) .setLinesHit(3) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build()) - .addFunctionCoverage(FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build()) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(7) + .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") + .setExecutionCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addFunctionCoverage( + FunctionCoverage.newBuilder() + .setLineNumber(3) + .setFunctionName("com/example/TwoSum:: ()V") + .setExecutionCount(0) + .setCoverage(Coverage.NONE).build() + ) .setFunctionsFound(2) .setFunctionsHit(1) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) - .addBranchCoverage(BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build()) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(0) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(1) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(2) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) + .addBranchCoverage( + BranchCoverage.newBuilder() + .setLineNumber(7) + .setBlockNumber(0) + .setBranchNumber(3) + .setHitCount(1) + .setCoverage(Coverage.FULL).build() + ) .setBranchesFound(4) .setBranchesHit(4) .build() val expectedResult = listOf( CoverageReport.newBuilder() - .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .addCoveredFile(expectedCoveredFile) - .build() + .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") + .addCoveredFile(expectedCoveredFile) + .build() ) assertThat(result).isEqualTo(expectedResult) From bc9a5c084cbcebb97ed449c624489215a14373e9 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 24 Jun 2024 12:13:06 +0530 Subject: [PATCH 070/105] Throw runtime exception when no coverage result is retrieved --- .../org/oppia/android/scripts/coverage/CoverageRunner.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) 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 baca8a8117b..63f9838f21e 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -39,14 +39,12 @@ class CoverageRunner( */ fun runWithCoverageAsync( bazelTestTarget: String - ): Deferred { + ): Deferred { return CoroutineScope(scriptBgDispatcher).async { val coverageResult = retrieveCoverageResult(bazelTestTarget) + ?: throw RuntimeException("Failed to retrieve coverage result for $bazelTestTarget") - val coverageReport = coverageResult?.let { - parseCoverageData(it, bazelTestTarget) - } - coverageReport + parseCoverageData(coverageResult, bazelTestTarget) } } From 7e105056226698c56c57561283a44d685bb97086 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 24 Jun 2024 16:13:24 +0530 Subject: [PATCH 071/105] Introduced Coverage Reporter script to generate HTML and MARKDOWN reports --- .../android/scripts/coverage/BUILD.bazel | 14 +++ .../scripts/coverage/CoverageReporter.kt | 86 +++++++++++++++++++ .../android/scripts/coverage/RunCoverage.kt | 28 +++++- 3 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index a1f6f4bf2d6..c638a9eb8e2 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -14,6 +14,7 @@ kt_jvm_library( deps = [ "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_runner", + "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_reporter", "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", ], ) @@ -30,3 +31,16 @@ kt_jvm_library( "//scripts/src/java/org/oppia/android/scripts/proto:coverage_java_proto", ], ) + +kt_jvm_library( + name = "coverage_reporter", + testonly = True, + srcs = [ + "CoverageReporter.kt", + ], + 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", + ], +) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt new file mode 100644 index 00000000000..23dbbb2fb26 --- /dev/null +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -0,0 +1,86 @@ +package org.oppia.android.scripts.coverage + +import org.oppia.android.scripts.proto.CoverageReport + +class CoverageReporter(private val coverageReportList: List) { + + fun generateRichTextReport(format: ReportFormat, computedCoverageRatio: Float): String { + return when (format) { + ReportFormat.MARKDOWN -> generateMarkdownReport(computedCoverageRatio) + ReportFormat.HTML -> generateHtmlReport() + } + } + + private fun generateMarkdownReport(computedCoverageRatio: Float): String { + val computedCoveragePercentage = "%.2f".format(computedCoverageRatio) + val totalFiles = coverageReportList.size + val filePath = coverageReportList.firstOrNull()?.getCoveredFile(0)?.filePath ?: "Unknown" + + val (totalLinesFound, totalLinesHit) = computeTotalsFor("lines") + val (totalFunctionsFound, totalFunctionsHit) = computeTotalsFor("functions") + val (totalBranchesFound, totalBranchesHit) = computeTotalsFor("branches") + + return """ + # Coverage Report + + **Total coverage:** + - **Files covered:** $totalFiles + - **Covered File:** $filePath + - **Coverage percentage:** $computedCoveragePercentage% covered + - **Line coverage:** $totalLinesFound covered / $totalLinesHit found + - **Function coverage:** $totalFunctionsHit covered / $totalFunctionsFound found + - **Branch coverage:** $totalBranchesFound covered / $totalBranchesHit found + + """.trimIndent() + } + + private fun computeTotalsFor(type: String): Pair { + var totalFound = 0 + var totalHit = 0 + + coverageReportList.forEach { coverageReport -> + coverageReport.coveredFileList.forEach { coveredFile -> + when (type) { + "lines" -> { + totalFound += coveredFile.linesFound + totalHit += coveredFile.linesHit + } + "functions" -> { + totalFound += coveredFile.functionsFound + totalHit += coveredFile.functionsHit + } + "branches" -> { + totalFound += coveredFile.branchesFound + totalHit += coveredFile.branchesHit + } + } + } + } + + return Pair(totalFound, totalHit) + } + + private fun generateHtmlReport(): String { + // Placeholder for HTML report generation + return "" + } + + fun computeCoverageRatio(): Float { + var totalFound = 0f + var totalHit = 0f + + coverageReportList.forEach { coverageReport -> + coverageReport.coveredFileList.forEach { coveredFile -> + totalFound += (coveredFile.linesFound + coveredFile.functionsFound + coveredFile.branchesFound).toFloat() + totalHit += (coveredFile.linesHit + coveredFile.functionsHit + coveredFile.branchesHit).toFloat() + } + } + + return if (totalFound > 0) (totalHit / totalFound * 100) else 0.0f + } +} + +enum class ReportFormat { + MARKDOWN, + HTML +} 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 f2101c6b60e..add9778896a 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -31,6 +31,11 @@ import java.util.concurrent.TimeUnit fun main(vararg args: String) { val repoRoot = args[0] val filePath = args[1] + val reportFormat = when (args.getOrNull(2)) { + "HTML" -> ReportFormat.HTML + "MARKDOWN", null -> ReportFormat.MARKDOWN // Default to MARKDOWN if not specified + else -> throw IllegalArgumentException("Unsupported report format: ${args[2]}") + } ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> val processTimeout: Long = args.find { it.startsWith("processTimeout=") } @@ -41,7 +46,7 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - println(RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute()) + RunCoverage(repoRoot, filePath, reportFormat, commandExecutor, scriptBgDispatcher).execute() } } @@ -56,6 +61,7 @@ fun main(vararg args: String) { class RunCoverage( private val repoRoot: String, private val filePath: String, + private val reportFormat: ReportFormat, private val commandExecutor: CommandExecutor, private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher ) { @@ -64,6 +70,12 @@ class RunCoverage( private val rootDirectory = File(repoRoot).absoluteFile private val testFileExemptionTextProto = "scripts/assets/test_file_exemptions" + companion object { + // The minimum coverage percentage threshold for coverage analysis, + // The script will fail if the file has less than the minimum specified coverage. + const val MIN_COVERAGE_PERCENTAGE = 20 + } + /** * Executes coverage analysis for the specified file. * @@ -75,7 +87,6 @@ class RunCoverage( * @return a list of lists containing coverage data for each requested test target, if * the file is exempted from having a test file, an empty list is returned */ - fun execute(): List { val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .getExemptedFilePathList() @@ -88,13 +99,24 @@ class RunCoverage( val testFilePaths = findTestFile(repoRoot, filePath) val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) - return testTargets.mapNotNull { testTarget -> + val coverageReports = testTargets.mapNotNull { testTarget -> val coverageData = runCoverageForTarget(testTarget) if (coverageData == null) { println("Coverage data for $testTarget is null") } coverageData } + + if (coverageReports.isNotEmpty()) { + val reporter = CoverageReporter(coverageReports) + val coverageRatio = reporter.computeCoverageRatio() + val generatedReport = reporter.generateRichTextReport(reportFormat, coverageRatio) + println("Generated report: $generatedReport") + } else { + println("No coverage reports generated.") + } + + return coverageReports } private fun runCoverageForTarget(testTarget: String): CoverageReport? { From 9bfeeff177d9c1e300d93f28b1c6171c3dfa4491 Mon Sep 17 00:00:00 2001 From: Rd Date: Mon, 24 Jun 2024 18:28:44 +0530 Subject: [PATCH 072/105] Saving the MARKDOWN reports --- .gitignore | 1 + .../scripts/coverage/CoverageReporter.kt | 20 ++++++++++++--- .../android/scripts/coverage/RunCoverage.kt | 25 +++++++++++++++---- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 531f05c8a20..224c3b3ef25 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ bazel-* .bazelproject .aswb *.pb +coverage_reports 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 23dbbb2fb26..63f6ae4de73 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -1,11 +1,17 @@ package org.oppia.android.scripts.coverage import org.oppia.android.scripts.proto.CoverageReport +import java.io.File -class CoverageReporter(private val coverageReportList: List) { +class CoverageReporter( + private val coverageReportList: List, + private val reportFormat: ReportFormat, + private val reportOutputPath: String +) { - fun generateRichTextReport(format: ReportFormat, computedCoverageRatio: Float): String { - return when (format) { + fun generateRichTextReport(computedCoverageRatio: Float): String { + println("output: $reportOutputPath") + return when (reportFormat) { ReportFormat.MARKDOWN -> generateMarkdownReport(computedCoverageRatio) ReportFormat.HTML -> generateHtmlReport() } @@ -20,7 +26,7 @@ class CoverageReporter(private val coverageReportList: List) { val (totalFunctionsFound, totalFunctionsHit) = computeTotalsFor("functions") val (totalBranchesFound, totalBranchesHit) = computeTotalsFor("branches") - return """ + val markdownReport = """ # Coverage Report **Total coverage:** @@ -32,6 +38,12 @@ class CoverageReporter(private val coverageReportList: List) { - **Branch coverage:** $totalBranchesFound covered / $totalBranchesHit found """.trimIndent() + + val outputFile = File(reportOutputPath) + outputFile.parentFile?.mkdirs() + outputFile.writeText(markdownReport) + + return reportOutputPath } private fun computeTotalsFor(type: String): Pair { 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 add9778896a..6ee036d0e24 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -19,10 +19,12 @@ import java.util.concurrent.TimeUnit * Arguments: * - path_to_root: directory path to the root of the Oppia Android repository. * - relative_path_to_file: the relative path to the file to analyse coverage + * - reportFormat: the format of the coverage report. Defaults to MARKDOWN if not specified. + * Available options: MARKDOWN, HTML. * * Example: * bazel run //scripts:run_coverage -- $(pwd) - * utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt + * utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt HTML * Example with custom process timeout: * bazel run //scripts:run_coverage -- $(pwd) * utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt processTimeout=10 @@ -33,10 +35,12 @@ fun main(vararg args: String) { val filePath = args[1] val reportFormat = when (args.getOrNull(2)) { "HTML" -> ReportFormat.HTML - "MARKDOWN", null -> ReportFormat.MARKDOWN // Default to MARKDOWN if not specified + "MARKDOWN", null -> ReportFormat.MARKDOWN else -> throw IllegalArgumentException("Unsupported report format: ${args[2]}") } + val reportOutputPath = getReportOutputPath(repoRoot, filePath, reportFormat) + ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> val processTimeout: Long = args.find { it.startsWith("processTimeout=") } ?.substringAfter("=") @@ -46,7 +50,7 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - RunCoverage(repoRoot, filePath, reportFormat, commandExecutor, scriptBgDispatcher).execute() + RunCoverage(repoRoot, filePath, reportFormat, reportOutputPath, commandExecutor, scriptBgDispatcher).execute() } } @@ -62,6 +66,7 @@ class RunCoverage( private val repoRoot: String, private val filePath: String, private val reportFormat: ReportFormat, + private val reportOutputPath: String, private val commandExecutor: CommandExecutor, private val scriptBgDispatcher: ScriptBackgroundCoroutineDispatcher ) { @@ -108,9 +113,9 @@ class RunCoverage( } if (coverageReports.isNotEmpty()) { - val reporter = CoverageReporter(coverageReports) + val reporter = CoverageReporter(coverageReports, reportFormat, reportOutputPath) val coverageRatio = reporter.computeCoverageRatio() - val generatedReport = reporter.generateRichTextReport(reportFormat, coverageRatio) + val generatedReport = reporter.generateRichTextReport(coverageRatio) println("Generated report: $generatedReport") } else { println("No coverage reports generated.") @@ -153,6 +158,16 @@ private fun findTestFile(repoRoot: String, filePath: String): List { .map { it.relativeTo(repoRootFile).path } } +private fun getReportOutputPath(repoRoot: String, filePath: String, reportFormat: ReportFormat): String { + println("Repo root: $repoRoot") + val fileWithoutExtension = filePath.substringBeforeLast(".") + val defaultFilename = when (reportFormat) { + ReportFormat.HTML -> "coverage.html" + ReportFormat.MARKDOWN -> "coverage.md" + } + return "$repoRoot/coverage_reports/$fileWithoutExtension/$defaultFilename" +} + private fun loadTestFileExemptionsProto(testFileExemptiontextProto: String): TestFileExemptions { return File("$testFileExemptiontextProto.pb").inputStream().use { stream -> TestFileExemptions.newBuilder().also { builder -> From 5441356204b8eb13f4d86a4c67de095aacdda6de Mon Sep 17 00:00:00 2001 From: Rd Date: Tue, 25 Jun 2024 09:34:39 +0530 Subject: [PATCH 073/105] Generate HTML reports - hardcoded messy implementation for base layout --- .../scripts/coverage/CoverageReporter.kt | 216 +++++++++++++++++- .../android/scripts/coverage/RunCoverage.kt | 2 +- 2 files changed, 215 insertions(+), 3 deletions(-) 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 63f6ae4de73..e865af2032c 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -1,9 +1,11 @@ package org.oppia.android.scripts.coverage import org.oppia.android.scripts.proto.CoverageReport +import org.oppia.android.scripts.proto.Coverage import java.io.File class CoverageReporter( + private val repoRoot: String, private val coverageReportList: List, private val reportFormat: ReportFormat, private val reportOutputPath: String @@ -11,6 +13,7 @@ class CoverageReporter( fun generateRichTextReport(computedCoverageRatio: Float): String { println("output: $reportOutputPath") + println("report format: $reportFormat") return when (reportFormat) { ReportFormat.MARKDOWN -> generateMarkdownReport(computedCoverageRatio) ReportFormat.HTML -> generateHtmlReport() @@ -72,11 +75,220 @@ class CoverageReporter( return Pair(totalFound, totalHit) } - private fun generateHtmlReport(): String { - // Placeholder for HTML report generation + fun generateHtmlReport(): String { + println("In HTML report generation") + + val coverageReport = coverageReportList.firstOrNull() ?: return "No coverage report found." + + val computedCoverageRatio = computeCoverageRatio() + + val computedCoveragePercentage = "%.2f".format(computedCoverageRatio) + val totalFiles = coverageReportList.size + val coveredFile = coverageReport.getCoveredFile(0) ?: return "No covered file found." + val filePath = coveredFile.filePath ?: "Unknown" + + val (totalLinesFound, totalLinesHit) = Pair(0,0) + val (totalFunctionsFound, totalFunctionsHit) = Pair(0,0) + val (totalBranchesFound, totalBranchesHit) = Pair(0,0) + + val lineCoverageColor = getColorBasedOnCoverage(totalLinesHit, totalLinesFound) + val functionCoverageColor = getColorBasedOnCoverage(totalFunctionsHit, totalFunctionsFound) + val branchCoverageColor = getColorBasedOnCoverage(totalBranchesHit, totalBranchesFound) + + var htmlContent = """ + + + + + + Coverage Report + + + +

Coverage Report

+
+

Total coverage:

+
    +
  • Files covered: $totalFiles
  • +
  • Covered File: $filePath
  • +
  • Coverage percentage: $computedCoveragePercentage% covered
  • +
  • Line coverage: $totalLinesHit covered / $totalLinesFound found
  • +
  • Function coverage: $totalFunctionsHit covered / $totalFunctionsFound found
  • +
  • Branch coverage: $totalBranchesHit covered / $totalBranchesFound found
  • +
+
+
+
+
Fully covered
+
+
+
+
Partially covered
+
+
+
+
Low coverage
+
+
+
+
+                
+ Line + Branch + Function + Code +
+ """.trimIndent() + + val fileContent = File(repoRoot, filePath).readLines() + + fileContent.forEachIndexed { index, line -> + val lineNumber = index + 1 + + val lineClass = getCumulativeCoverageClass() + + val branchCoverage = coveredFile.branchCoverageList.find { it.lineNumber == lineNumber } + val branchCoverageText = branchCoverage?.let { "${it.hitCount}" } ?: "" + + val functionCoverage = coveredFile.functionCoverageList.find { it.lineNumber == lineNumber } + val functionCoverageText = functionCoverage?.let { "${it.executionCount}" } ?: "" + + + htmlContent += """ +
+ ${lineNumber.toString().padStart(4, ' ')} + ${branchCoverageText} + ${functionCoverageText} + ${line} +
+ """.trimIndent() + } + + htmlContent += """ +
+ + + """.trimIndent() + + println("HtMl content: $htmlContent") + return "" } + + fun getColorBasedOnCoverage(hit: Int, found: Int): String { + val coveragePercentage = if (found == 0) 0 else (hit.toFloat() / found * 100).toInt() + return when { + coveragePercentage == 100 -> "#c8e6c9" + coveragePercentage >= 50 -> "#fff9c4" + else -> "#ffcdd2" + } + } + + fun getCumulativeCoverageClass(): String { + val isLineCovered = true + val isBranchCovered = false + val isFunctionCovered = true + + return when { + isLineCovered && isBranchCovered && isFunctionCovered -> "covered-line" + isLineCovered || isBranchCovered || isFunctionCovered -> "partially-covered-line" + else -> "not-covered-line" + } + } + fun computeCoverageRatio(): Float { var totalFound = 0f var totalHit = 0f 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 6ee036d0e24..c5222c79b32 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -113,7 +113,7 @@ class RunCoverage( } if (coverageReports.isNotEmpty()) { - val reporter = CoverageReporter(coverageReports, reportFormat, reportOutputPath) + val reporter = CoverageReporter(repoRoot, coverageReports, reportFormat, reportOutputPath) val coverageRatio = reporter.computeCoverageRatio() val generatedReport = reporter.generateRichTextReport(coverageRatio) println("Generated report: $generatedReport") From aed9857875ed0244c6248dfce325d0317e7be5a4 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 00:02:43 +0530 Subject: [PATCH 074/105] Generate HTML for just one target --- .../android/scripts/coverage/BUILD.bazel | 4 +- .../scripts/coverage/CoverageReporter.kt | 156 ++++-------------- .../android/scripts/coverage/RunCoverage.kt | 2 + 3 files changed, 37 insertions(+), 125 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index c638a9eb8e2..1b202135cae 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -13,9 +13,9 @@ 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/coverage:coverage_runner", - "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_reporter", "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", + ":coverage_runner", + ":coverage_reporter", ], ) 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 e865af2032c..6288acdea0a 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -36,7 +36,7 @@ class CoverageReporter( - **Files covered:** $totalFiles - **Covered File:** $filePath - **Coverage percentage:** $computedCoveragePercentage% covered - - **Line coverage:** $totalLinesFound covered / $totalLinesHit found + - **Line coverage:** $totalLinesHit covered / $totalLinesFound found - **Function coverage:** $totalFunctionsHit covered / $totalFunctionsFound found - **Branch coverage:** $totalBranchesFound covered / $totalBranchesHit found @@ -46,6 +46,8 @@ class CoverageReporter( outputFile.parentFile?.mkdirs() outputFile.writeText(markdownReport) + println("MARKDOWN: $markdownReport") + return reportOutputPath } @@ -75,12 +77,15 @@ class CoverageReporter( return Pair(totalFound, totalHit) } + //just line coverage fun generateHtmlReport(): String { +// val reportOutputPath = "path/to/your/report.html" // Replace with your desired output path + println("In HTML report generation") val coverageReport = coverageReportList.firstOrNull() ?: return "No coverage report found." - val computedCoverageRatio = computeCoverageRatio() + val computedCoverageRatio = computeCoverageRatio() // Implement this function val computedCoveragePercentage = "%.2f".format(computedCoverageRatio) val totalFiles = coverageReportList.size @@ -88,12 +93,8 @@ class CoverageReporter( val filePath = coveredFile.filePath ?: "Unknown" val (totalLinesFound, totalLinesHit) = Pair(0,0) - val (totalFunctionsFound, totalFunctionsHit) = Pair(0,0) - val (totalBranchesFound, totalBranchesHit) = Pair(0,0) - - val lineCoverageColor = getColorBasedOnCoverage(totalLinesHit, totalLinesFound) - val functionCoverageColor = getColorBasedOnCoverage(totalFunctionsHit, totalFunctionsFound) - val branchCoverageColor = getColorBasedOnCoverage(totalBranchesHit, totalBranchesFound) + val (totalFunctionsFound, totalFunctionsHit) = Pair(0, 0) + val (totalBranchesFound, totalBranchesHit) = Pair(0, 0) var htmlContent = """ @@ -108,6 +109,12 @@ class CoverageReporter( line-height: 1.6; padding: 20px; } + .covered-line, .not-covered-line, .uncovered-line { + display: inline-block; + width: auto; + padding: 2px 4px; + margin: 0; + } .covered-line { background-color: #c8e6c9; /* Light green */ } @@ -117,83 +124,13 @@ class CoverageReporter( .uncovered-line { background-color: #ffffff; /* White */ } - .partially-covered-line { - background-color: #fff9c4; /* Light yellow */ - } .coverage-summary { margin-bottom: 20px; - padding: 10px; - border: 1px solid #ddd; - background-color: #f9f9f9; - border-radius: 5px; - } - .coverage-summary h2 { - margin-top: 0; - } - .coverage-summary ul { - list-style-type: none; - padding-left: 0; - } - .coverage-summary li { - margin-bottom: 5px; - } - .coverage-summary .legend { - display: flex; - gap: 10px; - margin-top: 10px; - } - .legend-item { - display: flex; - align-items: center; - gap: 5px; - } - .legend-color { - width: 20px; - height: 20px; - border: 1px solid #ddd; - } - .legend-label { - font-size: 14px; } pre { white-space: pre-wrap; word-wrap: break-word; } - .line { - display: flex; - align-items: center; - border-bottom: 1px solid #ddd; - } - .line-number, .branch-coverage, .function-coverage { - width: 50px; - text-align: right; - padding-right: 10px; - margin-right: 10px; - border-right: 1px solid #ddd; - } - .code-block { - flex-grow: 1; - padding-left: 10px; - } - .header { - display: flex; - font-weight: bold; - background-color: #f1f1f1; - padding: 5px 0; - } - .header .line-number, .header .branch-coverage, .header .function-coverage, .header .code-block { - border-right: none; - text-align: center; - } - .coverage-summary li.line-coverage { - background-color: $lineCoverageColor; - } - .coverage-summary li.branch-coverage { - background-color: $branchCoverageColor; - } - .coverage-summary li.function-coverage { - background-color: $functionCoverageColor; - } @@ -204,56 +141,25 @@ class CoverageReporter(
  • Files covered: $totalFiles
  • Covered File: $filePath
  • Coverage percentage: $computedCoveragePercentage% covered
  • -
  • Line coverage: $totalLinesHit covered / $totalLinesFound found
  • -
  • Function coverage: $totalFunctionsHit covered / $totalFunctionsFound found
  • -
  • Branch coverage: $totalBranchesHit covered / $totalBranchesFound found
  • +
  • Line coverage: $totalLinesHit covered / $totalLinesFound found
  • +
  • Function coverage: $totalFunctionsHit covered / $totalFunctionsFound found
  • +
  • Branch coverage: $totalBranchesHit covered / $totalBranchesFound found
  • -
    -
    -
    -
    Fully covered
    -
    -
    -
    -
    Partially covered
    -
    -
    -
    -
    Low coverage
    -
    -
    -                
    - Line - Branch - Function - Code -
    """.trimIndent() - val fileContent = File(repoRoot, filePath).readLines() + val fileContent = File("/mnt/c/Users/Baskaran/AndroidStudioProjects/oppia-android", filePath).readLines() + val coverageMap = coveredFile.coveredLineList.associateBy { it.lineNumber } fileContent.forEachIndexed { index, line -> val lineNumber = index + 1 - - val lineClass = getCumulativeCoverageClass() - - val branchCoverage = coveredFile.branchCoverageList.find { it.lineNumber == lineNumber } - val branchCoverageText = branchCoverage?.let { "${it.hitCount}" } ?: "" - - val functionCoverage = coveredFile.functionCoverageList.find { it.lineNumber == lineNumber } - val functionCoverageText = functionCoverage?.let { "${it.executionCount}" } ?: "" - - - htmlContent += """ -
    - ${lineNumber.toString().padStart(4, ' ')} - ${branchCoverageText} - ${functionCoverageText} - ${line} -
    - """.trimIndent() + val lineClass = when (coverageMap[lineNumber]?.coverage) { + Coverage.FULL -> "covered-line" + Coverage.NONE -> "not-covered-line" + else -> "uncovered-line" + } + htmlContent += "
    ${lineNumber.toString().padStart(4, ' ')}: $line
    \n" } htmlContent += """ @@ -262,11 +168,15 @@ class CoverageReporter( """.trimIndent() - println("HtMl content: $htmlContent") + println("HTML content: $htmlContent") - return "" - } + val outputFile = File(reportOutputPath) + outputFile.parentFile.mkdirs() + outputFile.writeText(htmlContent) + return reportOutputPath +// return "" + } fun getColorBasedOnCoverage(hit: Int, found: Int): String { val coveragePercentage = if (found == 0) 0 else (hit.toFloat() / found * 100).toInt() 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 c5222c79b32..a53bafbc86c 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -112,6 +112,8 @@ class RunCoverage( coverageData } + println("Generated Coverage Reports proto: $coverageReports") + if (coverageReports.isNotEmpty()) { val reporter = CoverageReporter(repoRoot, coverageReports, reportFormat, reportOutputPath) val coverageRatio = reporter.computeCoverageRatio() From 1b9426d196a1d790fc31e70721be88c52506a0b1 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 06:33:47 +0530 Subject: [PATCH 075/105] Fix instrumentation and throw error on invalid path --- .../util/parser/math/MathModel/coverage.html | 115 ++++++++++++++++++ .../util/parser/math/MathModel/coverage.md | 9 ++ .../util/math/FloatExtensions/coverage.html | 95 +++++++++++++++ .../util/math/FloatExtensions/coverage.md | 9 ++ .../android/scripts/common/BazelClient.kt | 3 +- .../android/scripts/coverage/RunCoverage.kt | 6 +- .../scripts/coverage/RunCoverageTest.kt | 28 ++++- 7 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html create mode 100644 coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md create mode 100644 coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html create mode 100644 coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md diff --git a/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html b/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html new file mode 100644 index 00000000000..ad2b7a569ad --- /dev/null +++ b/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html @@ -0,0 +1,115 @@ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +

    Total coverage:

    +
      +
    • Files covered: 1
    • +
    • Covered File: utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt
    • +
    • Coverage percentage: 87.50% covered
    • +
    • Line coverage: 0 covered / 0 found
    • +
    • Function coverage: 0 covered / 0 found
    • +
    • Branch coverage: 0 covered / 0 found
    • +
    +
    +
    1: package org.oppia.android.util.parser.math
    +
    2:
    +
    3: import com.bumptech.glide.load.Key
    +
    4: import java.nio.ByteBuffer
    +
    5: import java.security.MessageDigest
    +
    6:
    +
    7: /**
    +
    8: * Represents a set of LaTeX that can be rendered as a single bitmap.
    +
    9: *
    +
    10: * @property rawLatex the LaTeX to render
    +
    11: * @property lineHeight the height (in pixels) of a text line (to help scale the LaTeX)
    +
    12: * @property useInlineRendering whether the LaTeX will be inlined with text
    +
    13: */
    +
    14: data class MathModel(
    +
    15: val rawLatex: String,
    +
    16: val lineHeight: Float,
    +
    17: val useInlineRendering: Boolean
    +
    18: ) {
    +
    19: /** Returns a Glide [Key] signature (see [MathModelSignature] for specifics). */
    +
    20: fun toKeySignature(): MathModelSignature =
    +
    21: MathModelSignature.createSignature(rawLatex, lineHeight, useInlineRendering)
    +
    22:
    +
    23: /**
    +
    24: * Glide [Key] that provides caching support by allowing individual renderable math scenarios to
    +
    25: * be comparable based on select parameters.
    +
    26: *
    +
    27: * @property rawLatex the raw LaTeX string used to render a cached bitmap
    +
    28: * @property lineHeightHundredX an [Int] representation of the 100x scaled line height from
    +
    29: * [MathModel] (this is used to preserve up to 2 digits of the height, but any past that will
    +
    30: * be truncated to reduce cache size for highly reusable cached renders)
    +
    31: * @property useInlineRendering whether the render is formatted to be displayed in-line with text
    +
    32: */
    +
    33: data class MathModelSignature(
    +
    34: val rawLatex: String,
    +
    35: val lineHeightHundredX: Int,
    +
    36: val useInlineRendering: Boolean
    +
    37: ) : Key {
    +
    38: // Impl reference: http://bumptech.github.io/glide/doc/caching.html#custom-cache-invalidation.
    +
    39:
    +
    40: override fun updateDiskCacheKey(messageDigest: MessageDigest) {
    +
    41: val rawLatexBytes = rawLatex.encodeToByteArray()
    +
    42: messageDigest.update(
    +
    43: ByteBuffer.allocate(rawLatexBytes.size + Int.SIZE_BYTES + 1).apply {
    +
    44: put(rawLatexBytes)
    +
    45: putInt(lineHeightHundredX)
    +
    46: put(if (useInlineRendering) 1 else 0)
    +
    47: }.array()
    +
    48: )
    +
    49: }
    +
    50:
    +
    51: internal companion object {
    +
    52: /** Returns a new [MathModelSignature] for the specified [MathModel] properties. */
    +
    53: internal fun createSignature(
    +
    54: rawLatex: String,
    +
    55: lineHeight: Float,
    +
    56: useInlineRendering: Boolean
    +
    57: ): MathModelSignature {
    +
    58: val lineHeightHundredX = (lineHeight * 100f).toInt()
    +
    59: return MathModelSignature(rawLatex, lineHeightHundredX, useInlineRendering)
    +
    60: }
    +
    61: }
    +
    62: }
    +
    63: }
    +
    + + \ No newline at end of file diff --git a/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md b/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md new file mode 100644 index 00000000000..160d8e46691 --- /dev/null +++ b/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md @@ -0,0 +1,9 @@ +# Coverage Report + +**Total coverage:** +- **Files covered:** 1 +- **Covered File:** utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt +- **Coverage percentage:** 87.50% covered +- **Line coverage:** 19 covered / 19 found +- **Function coverage:** 7 covered / 11 found +- **Branch coverage:** 2 covered / 2 found diff --git a/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html b/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html new file mode 100644 index 00000000000..fc271b6c116 --- /dev/null +++ b/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html @@ -0,0 +1,95 @@ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +

    Total coverage:

    +
      +
    • Files covered: 1
    • +
    • Covered File: utility/src/main/java/org/oppia/android/util/math/FloatExtensions.kt
    • +
    • Coverage percentage: 80.00% covered
    • +
    • Line coverage: 0 covered / 0 found
    • +
    • Function coverage: 0 covered / 0 found
    • +
    • Branch coverage: 0 covered / 0 found
    • +
    +
    +
    1: package org.oppia.android.util.math
    +
    2:
    +
    3: import kotlin.math.abs
    +
    4:
    +
    5: /**
    +
    6: * The error margin used for approximately [Float] equality checking, that is, the largest distance
    +
    7: * from any particular number before a new value will be considered unequal (i.e. all values between
    +
    8: * a float and (float-interval, float+interval) will be considered equal to the float).
    +
    9: *
    +
    10: * Note that the machine epsilon value from https://en.wikipedia.org/wiki/Machine_epsilon is defined
    +
    11: * defined as the smallest value that, when added to, or subtract from, 1, will result in a value
    +
    12: * that is exactly equal to 1. A larger value is picked here for more allowance in variance.
    +
    13: */
    +
    14: const val FLOAT_EQUALITY_EPSILON: Float = 1e-6f
    +
    15:
    +
    16: /**
    +
    17: * The error margin used for approximately [Double] equality checking.
    +
    18: *
    +
    19: * See [FLOAT_EQUALITY_EPSILON] for an explanation of this value.
    +
    20: */
    +
    21: const val DOUBLE_EQUALITY_EPSILON: Double = 1e-13
    +
    22:
    +
    23: /**
    +
    24: * Returns whether this float approximately equals another based on a consistent epsilon value
    +
    25: * ([FLOAT_EQUALITY_EPSILON]).
    +
    26: */
    +
    27: fun Float.isApproximatelyEqualTo(other: Float): Boolean {
    +
    28: return abs(this - other) < FLOAT_EQUALITY_EPSILON
    +
    29: }
    +
    30:
    +
    31: /**
    +
    32: * Returns whether this double approximately equals another based on a consistent epsilon value
    +
    33: * ([DOUBLE_EQUALITY_EPSILON]).
    +
    34: */
    +
    35: fun Double.isApproximatelyEqualTo(other: Double): Boolean {
    +
    36: return abs(this - other) < DOUBLE_EQUALITY_EPSILON
    +
    37: }
    +
    38:
    +
    39: /**
    +
    40: * Returns a string representation of this [Double] that keeps the double in pure decimal and never
    +
    41: * relies on scientific notation (unlike [Double.toString]).
    +
    42: */
    +
    43: fun Double.toPlainString(): String = toBigDecimal().toPlainString()
    +
    + + \ No newline at end of file diff --git a/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md b/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md new file mode 100644 index 00000000000..a0c06ee1b75 --- /dev/null +++ b/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md @@ -0,0 +1,9 @@ +# Coverage Report + +**Total coverage:** +- **Files covered:** 1 +- **Covered File:** utility/src/main/java/org/oppia/android/util/math/FloatExtensions.kt +- **Coverage percentage:** 80.00% covered +- **Line coverage:** 2 covered / 3 found +- **Function coverage:** 2 covered / 3 found +- **Branch coverage:** 4 covered / 4 found diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 2b3878d44ff..8942e9a664e 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -142,10 +142,11 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * or null if the coverage data file could not be parsed */ fun runCoverageForTestTarget(bazelTestTarget: String): List? { + val computeInstrumentation = bazelTestTarget.split("/").let{"//${it[2]}/..."} val coverageCommandOutputLines = executeBazelCommand( "coverage", bazelTestTarget, - "--instrumentation_filter=//" + "--instrumentation_filter=$computeInstrumentation" ) return parseCoverageDataFilePath(coverageCommandOutputLines)?.let { path -> File(path).readLines() 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 e0dbe594bef..1492f378c53 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -31,6 +31,10 @@ fun main(vararg args: String) { val repoRoot = args[0] val filePath = args[1] + if (!File(repoRoot, filePath).exists()) { + error("File doesn't exist.") + } + ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher -> val processTimeout: Long = args.find { it.startsWith("processTimeout=") } ?.substringAfter("=") @@ -79,7 +83,7 @@ class RunCoverage( .getExemptedFilePathList() if (filePath in testFileExemptionList) { - println("This file is exempted from having a test file. Hence No coverage!") + println("This file is exempted from having a test file; skipping coverage check.") return emptyList() } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index a213f71f473..c7a1ff93c0e 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -8,10 +8,12 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher +import org.oppia.android.testing.assertThrows import org.oppia.android.scripts.testing.TestBazelWorkspace import java.io.ByteArrayOutputStream import java.io.PrintStream import java.util.concurrent.TimeUnit +import java.io.File /** Tests for [RunCoverage]. */ class RunCoverageTest { @@ -40,6 +42,24 @@ class RunCoverageTest { scriptBgDispatcher.close() } + @Test + fun testRunCoverage_validFile_runsCoverage() { + testBazelWorkspace.initEmptyWorkspace() + val sampleFile = File(tempFolder.root.absolutePath, "file.kt") + sampleFile.createNewFile() + main(tempFolder.root.absolutePath, "file.kt") + } + + @Test + fun testRunCoverage_invalidFile_runsCoverage() { + testBazelWorkspace.initEmptyWorkspace() + val exception = assertThrows() { + main(tempFolder.root.absolutePath, "file.kt") + } + + assertThat(exception).hasMessageThat().contains("File doesn't exist") + } + @Test fun testRunCoverage_testFileExempted_noCoverage() { val exemptedFilePath = "app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt" @@ -56,7 +76,7 @@ class RunCoverageTest { } @Test - fun testRunCoverage_validSampleTestFile_returnsCoverageData() { + fun testRunCoverage_sampleTests_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -139,7 +159,7 @@ class RunCoverageTest { } @Test - fun testRunCoverage_validScriptPathSampleTestFile_returnsCoverageData() { + fun testRunCoverage_scriptTests_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -222,7 +242,7 @@ class RunCoverageTest { } @Test - fun testRunCoverage_validAppPathSampleTestFile_returnsCoverageData() { + fun testRunCoverage_appTests_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -305,7 +325,7 @@ class RunCoverageTest { } @Test - fun testRunCoverage_validMultiSampleTestFile_returnsCoverageData() { + fun testRunCoverage_sharedAndLocalTests_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = From 85b4bcdc78a534b658b18ab054b1a8bd0f7b622e Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 07:06:48 +0530 Subject: [PATCH 076/105] Throw error on missing test files --- .../android/scripts/coverage/RunCoverage.kt | 4 ++++ .../android/scripts/coverage/RunCoverageTest.kt | 16 ++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) 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 1492f378c53..7498aff5afe 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -88,6 +88,10 @@ class RunCoverage( } val testFilePaths = findTestFile(repoRoot, filePath) + if (testFilePaths.isEmpty()) { + error("No appropriate test file found for $filePath") + } + val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) return testTargets.mapNotNull { testTarget -> diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index c7a1ff93c0e..c05cb5ca4e7 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -43,21 +43,25 @@ class RunCoverageTest { } @Test - fun testRunCoverage_validFile_runsCoverage() { + fun testRunCoverage_invalidFile_throwsException() { testBazelWorkspace.initEmptyWorkspace() - val sampleFile = File(tempFolder.root.absolutePath, "file.kt") - sampleFile.createNewFile() - main(tempFolder.root.absolutePath, "file.kt") + val exception = assertThrows() { + main(tempFolder.root.absolutePath, "file.kt") + } + + assertThat(exception).hasMessageThat().contains("File doesn't exist") } @Test - fun testRunCoverage_invalidFile_runsCoverage() { + fun testRunCoverage_missingTestFileNOtExempted_throwsException() { testBazelWorkspace.initEmptyWorkspace() val exception = assertThrows() { + val sampleFile = File(tempFolder.root.absolutePath, "file.kt") + sampleFile.createNewFile() main(tempFolder.root.absolutePath, "file.kt") } - assertThat(exception).hasMessageThat().contains("File doesn't exist") + assertThat(exception).hasMessageThat().contains("No appropriate test file found") } @Test From 356e4fbef00f9d55b7168b0bffad0fdbed3ef055 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 07:22:22 +0530 Subject: [PATCH 077/105] Removed accidentally added coverage_reports folder --- .../util/parser/math/MathModel/coverage.html | 115 ------------------ .../util/parser/math/MathModel/coverage.md | 9 -- .../util/math/FloatExtensions/coverage.html | 95 --------------- .../util/math/FloatExtensions/coverage.md | 9 -- 4 files changed, 228 deletions(-) delete mode 100644 coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html delete mode 100644 coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md delete mode 100644 coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html delete mode 100644 coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md diff --git a/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html b/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html deleted file mode 100644 index ad2b7a569ad..00000000000 --- a/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - Coverage Report - - - -

    Coverage Report

    -
    -

    Total coverage:

    -
      -
    • Files covered: 1
    • -
    • Covered File: utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt
    • -
    • Coverage percentage: 87.50% covered
    • -
    • Line coverage: 0 covered / 0 found
    • -
    • Function coverage: 0 covered / 0 found
    • -
    • Branch coverage: 0 covered / 0 found
    • -
    -
    -
    1: package org.oppia.android.util.parser.math
    -
    2:
    -
    3: import com.bumptech.glide.load.Key
    -
    4: import java.nio.ByteBuffer
    -
    5: import java.security.MessageDigest
    -
    6:
    -
    7: /**
    -
    8: * Represents a set of LaTeX that can be rendered as a single bitmap.
    -
    9: *
    -
    10: * @property rawLatex the LaTeX to render
    -
    11: * @property lineHeight the height (in pixels) of a text line (to help scale the LaTeX)
    -
    12: * @property useInlineRendering whether the LaTeX will be inlined with text
    -
    13: */
    -
    14: data class MathModel(
    -
    15: val rawLatex: String,
    -
    16: val lineHeight: Float,
    -
    17: val useInlineRendering: Boolean
    -
    18: ) {
    -
    19: /** Returns a Glide [Key] signature (see [MathModelSignature] for specifics). */
    -
    20: fun toKeySignature(): MathModelSignature =
    -
    21: MathModelSignature.createSignature(rawLatex, lineHeight, useInlineRendering)
    -
    22:
    -
    23: /**
    -
    24: * Glide [Key] that provides caching support by allowing individual renderable math scenarios to
    -
    25: * be comparable based on select parameters.
    -
    26: *
    -
    27: * @property rawLatex the raw LaTeX string used to render a cached bitmap
    -
    28: * @property lineHeightHundredX an [Int] representation of the 100x scaled line height from
    -
    29: * [MathModel] (this is used to preserve up to 2 digits of the height, but any past that will
    -
    30: * be truncated to reduce cache size for highly reusable cached renders)
    -
    31: * @property useInlineRendering whether the render is formatted to be displayed in-line with text
    -
    32: */
    -
    33: data class MathModelSignature(
    -
    34: val rawLatex: String,
    -
    35: val lineHeightHundredX: Int,
    -
    36: val useInlineRendering: Boolean
    -
    37: ) : Key {
    -
    38: // Impl reference: http://bumptech.github.io/glide/doc/caching.html#custom-cache-invalidation.
    -
    39:
    -
    40: override fun updateDiskCacheKey(messageDigest: MessageDigest) {
    -
    41: val rawLatexBytes = rawLatex.encodeToByteArray()
    -
    42: messageDigest.update(
    -
    43: ByteBuffer.allocate(rawLatexBytes.size + Int.SIZE_BYTES + 1).apply {
    -
    44: put(rawLatexBytes)
    -
    45: putInt(lineHeightHundredX)
    -
    46: put(if (useInlineRendering) 1 else 0)
    -
    47: }.array()
    -
    48: )
    -
    49: }
    -
    50:
    -
    51: internal companion object {
    -
    52: /** Returns a new [MathModelSignature] for the specified [MathModel] properties. */
    -
    53: internal fun createSignature(
    -
    54: rawLatex: String,
    -
    55: lineHeight: Float,
    -
    56: useInlineRendering: Boolean
    -
    57: ): MathModelSignature {
    -
    58: val lineHeightHundredX = (lineHeight * 100f).toInt()
    -
    59: return MathModelSignature(rawLatex, lineHeightHundredX, useInlineRendering)
    -
    60: }
    -
    61: }
    -
    62: }
    -
    63: }
    -
    - - \ No newline at end of file diff --git a/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md b/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md deleted file mode 100644 index 160d8e46691..00000000000 --- a/coverage_reports/utility/src/main/java/org/oppia/android/util/parser/math/MathModel/coverage.md +++ /dev/null @@ -1,9 +0,0 @@ -# Coverage Report - -**Total coverage:** -- **Files covered:** 1 -- **Covered File:** utility/src/main/java/org/oppia/android/util/parser/math/MathModel.kt -- **Coverage percentage:** 87.50% covered -- **Line coverage:** 19 covered / 19 found -- **Function coverage:** 7 covered / 11 found -- **Branch coverage:** 2 covered / 2 found diff --git a/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html b/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html deleted file mode 100644 index fc271b6c116..00000000000 --- a/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - Coverage Report - - - -

    Coverage Report

    -
    -

    Total coverage:

    -
      -
    • Files covered: 1
    • -
    • Covered File: utility/src/main/java/org/oppia/android/util/math/FloatExtensions.kt
    • -
    • Coverage percentage: 80.00% covered
    • -
    • Line coverage: 0 covered / 0 found
    • -
    • Function coverage: 0 covered / 0 found
    • -
    • Branch coverage: 0 covered / 0 found
    • -
    -
    -
    1: package org.oppia.android.util.math
    -
    2:
    -
    3: import kotlin.math.abs
    -
    4:
    -
    5: /**
    -
    6: * The error margin used for approximately [Float] equality checking, that is, the largest distance
    -
    7: * from any particular number before a new value will be considered unequal (i.e. all values between
    -
    8: * a float and (float-interval, float+interval) will be considered equal to the float).
    -
    9: *
    -
    10: * Note that the machine epsilon value from https://en.wikipedia.org/wiki/Machine_epsilon is defined
    -
    11: * defined as the smallest value that, when added to, or subtract from, 1, will result in a value
    -
    12: * that is exactly equal to 1. A larger value is picked here for more allowance in variance.
    -
    13: */
    -
    14: const val FLOAT_EQUALITY_EPSILON: Float = 1e-6f
    -
    15:
    -
    16: /**
    -
    17: * The error margin used for approximately [Double] equality checking.
    -
    18: *
    -
    19: * See [FLOAT_EQUALITY_EPSILON] for an explanation of this value.
    -
    20: */
    -
    21: const val DOUBLE_EQUALITY_EPSILON: Double = 1e-13
    -
    22:
    -
    23: /**
    -
    24: * Returns whether this float approximately equals another based on a consistent epsilon value
    -
    25: * ([FLOAT_EQUALITY_EPSILON]).
    -
    26: */
    -
    27: fun Float.isApproximatelyEqualTo(other: Float): Boolean {
    -
    28: return abs(this - other) < FLOAT_EQUALITY_EPSILON
    -
    29: }
    -
    30:
    -
    31: /**
    -
    32: * Returns whether this double approximately equals another based on a consistent epsilon value
    -
    33: * ([DOUBLE_EQUALITY_EPSILON]).
    -
    34: */
    -
    35: fun Double.isApproximatelyEqualTo(other: Double): Boolean {
    -
    36: return abs(this - other) < DOUBLE_EQUALITY_EPSILON
    -
    37: }
    -
    38:
    -
    39: /**
    -
    40: * Returns a string representation of this [Double] that keeps the double in pure decimal and never
    -
    41: * relies on scientific notation (unlike [Double.toString]).
    -
    42: */
    -
    43: fun Double.toPlainString(): String = toBigDecimal().toPlainString()
    -
    - - \ No newline at end of file diff --git a/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md b/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md deleted file mode 100644 index a0c06ee1b75..00000000000 --- a/coverage_reports/utility/src/test/java/org/oppia/android/util/math/FloatExtensions/coverage.md +++ /dev/null @@ -1,9 +0,0 @@ -# Coverage Report - -**Total coverage:** -- **Files covered:** 1 -- **Covered File:** utility/src/main/java/org/oppia/android/util/math/FloatExtensions.kt -- **Coverage percentage:** 80.00% covered -- **Line coverage:** 2 covered / 3 found -- **Function coverage:** 2 covered / 3 found -- **Branch coverage:** 4 covered / 4 found From 8e07f507f11a8b4bc627c1447da1a564505c001d Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 08:43:45 +0530 Subject: [PATCH 078/105] Updated with upstream --- .../android/scripts/common/BazelClient.kt | 2 +- .../scripts/coverage/CoverageRunner.kt | 81 +++++++------------ .../scripts/coverage/RunCoverageTest.kt | 6 -- 3 files changed, 31 insertions(+), 58 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 8942e9a664e..8c3c546f026 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -142,7 +142,7 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * or null if the coverage data file could not be parsed */ fun runCoverageForTestTarget(bazelTestTarget: String): List? { - val computeInstrumentation = bazelTestTarget.split("/").let{"//${it[2]}/..."} + val computeInstrumentation = bazelTestTarget.split("/").let { "//${it[2]}/..." } val coverageCommandOutputLines = executeBazelCommand( "coverage", bazelTestTarget, 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 7bb600f120a..c6496c1acf3 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -41,7 +41,7 @@ class CoverageRunner( val coverageResult = retrieveCoverageResult(bazelTestTarget) ?: throw RuntimeException("Failed to retrieve coverage result for $bazelTestTarget") - parseCoverageData(coverageResult, bazelTestTarget) + parseCoverageData(coverageResult, bazelTestTarget) } } @@ -55,61 +55,40 @@ class CoverageRunner( coverageData: List, bazelTestTarget: String ): CoverageReport { - var filePath = "" - var linesFound = 0 - var linesHit = 0 - val coveredLines = mutableListOf() - - var parseFile = false val extractedFileName = "${extractTargetName(bazelTestTarget)}.kt" - coverageData.forEach { line -> - when { - // SF: - line.startsWith("SF:") -> { - val sourceFilePath = line.substringAfter("SF:") - if (sourceFilePath.substringAfterLast("/") == extractedFileName) { - filePath = line.substringAfter("SF:") - parseFile = true - } else { - parseFile = false - } - } - parseFile -> { - when { - // DA:, - line.startsWith("DA:") -> { - val parts = line.substringAfter("DA:").split(",") - val lineNumber = parts[0].toInt() - val hitCount = parts[1].toInt() - val coverage = - if (hitCount > 0) - Coverage.FULL - else - Coverage.NONE - coveredLines.add( - CoveredLine.newBuilder() - .setLineNumber(lineNumber) - .setCoverage(coverage) - .build() - ) - } - // LF: - line.startsWith("LF:") -> { - linesFound = line.substringAfter("LF:").toInt() - } - // LH: - line.startsWith("LH:") -> { - linesHit = line.substringAfter("LH:").toInt() - } - line.startsWith("end_of_record") -> { - parseFile = false - } - } - } + val sfStartIdx = coverageData.indexOfFirst { + it.startsWith("SF:") && it.substringAfter("SF:").substringAfterLast("/") == extractedFileName + } + if (sfStartIdx == -1) throw IllegalArgumentException("File not found") + val eofIdx = coverageData.subList(sfStartIdx, coverageData.size).indexOfFirst { + it.startsWith("end_of_record") + } + if (eofIdx == -1) throw IllegalArgumentException("End of record not found") + + val fileSpecificCovDatLines = coverageData.subList(sfStartIdx, sfStartIdx + eofIdx + 1) + + val coverageDataProps = fileSpecificCovDatLines.groupBy { line -> + line.substringBefore(":") + }.mapValues { (_, lines) -> + lines.map { line -> + line.substringAfter(":").split(",") } } + val filePath = coverageDataProps["SF"]?.firstOrNull()?.get(0) + ?: throw IllegalArgumentException("File path not found") + + val linesFound = coverageDataProps["LF"]?.singleOrNull()?.single()?.toInt() ?: 0 + val linesHit = coverageDataProps["LH"]?.singleOrNull()?.single()?.toInt() ?: 0 + + val coveredLines = coverageDataProps["DA"]?.map { (lineNumStr, hitCountStr) -> + CoveredLine.newBuilder().apply { + this.lineNumber = lineNumStr.toInt() + this.coverage = if (hitCountStr.toInt() > 0) Coverage.FULL else Coverage.NONE + }.build() + }.orEmpty() + val file = File(repoRoot, filePath) val fileSha1Hash = calculateSha1(file.absolutePath) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 3ada2af29d3..74e13cb47ea 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -8,16 +8,10 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -<<<<<<< HEAD -import org.oppia.android.scripts.proto.BranchCoverage import org.oppia.android.scripts.proto.Coverage 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.FunctionCoverage -======= import org.oppia.android.testing.assertThrows ->>>>>>> 356e4fbef00f9d55b7168b0bffad0fdbed3ef055 import org.oppia.android.scripts.testing.TestBazelWorkspace import java.io.ByteArrayOutputStream import java.io.PrintStream From 9734a8464671671afb807f2758211ef9fd8413f6 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 08:48:32 +0530 Subject: [PATCH 079/105] Lint fix and Fix failing Test --- .../java/org/oppia/android/scripts/common/BazelClient.kt | 2 +- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt index 8942e9a664e..8c3c546f026 100644 --- a/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt +++ b/scripts/src/java/org/oppia/android/scripts/common/BazelClient.kt @@ -142,7 +142,7 @@ class BazelClient(private val rootDirectory: File, private val commandExecutor: * or null if the coverage data file could not be parsed */ fun runCoverageForTestTarget(bazelTestTarget: String): List? { - val computeInstrumentation = bazelTestTarget.split("/").let{"//${it[2]}/..."} + val computeInstrumentation = bazelTestTarget.split("/").let { "//${it[2]}/..." } val coverageCommandOutputLines = executeBazelCommand( "coverage", bazelTestTarget, diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index c05cb5ca4e7..092b75fae87 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -8,12 +8,12 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.testing.assertThrows import org.oppia.android.scripts.testing.TestBazelWorkspace +import org.oppia.android.testing.assertThrows import java.io.ByteArrayOutputStream +import java.io.File import java.io.PrintStream import java.util.concurrent.TimeUnit -import java.io.File /** Tests for [RunCoverage]. */ class RunCoverageTest { @@ -76,7 +76,7 @@ class RunCoverageTest { ).execute() assertThat(outContent.toString()) - .isEqualTo("This file is exempted from having a test file. Hence No coverage!\n") + .isEqualTo("This file is exempted from having a test file; skipping coverage check.\n") } @Test From 7a020a1dbc7e752f5f2e604e0a86ab018e2ff9c0 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 09:23:07 +0530 Subject: [PATCH 080/105] Update the test file exemption list retrieval --- .../java/org/oppia/android/scripts/coverage/RunCoverage.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 7498aff5afe..10a6539fd2e 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -80,7 +80,9 @@ class RunCoverage( */ fun execute(): List> { val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) - .getExemptedFilePathList() + .testFileExemptionList + .filter { it.testFileNotRequired } + .map { it.exemptedFilePath } if (filePath in testFileExemptionList) { println("This file is exempted from having a test file; skipping coverage check.") From c123365f0d15cb810e045f65cd5d8c8d79cd999b Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 10:54:14 +0530 Subject: [PATCH 081/105] Updated tests with the proto structure, multi test cases are still failing --- .../scripts/coverage/CoverageRunner.kt | 6 +- .../android/scripts/coverage/RunCoverage.kt | 3 +- .../scripts/coverage/RunCoverageTest.kt | 289 +++--------------- 3 files changed, 41 insertions(+), 257 deletions(-) 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 c6496c1acf3..4b4de1ececa 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -39,9 +39,9 @@ class CoverageRunner( ): Deferred { return CoroutineScope(scriptBgDispatcher).async { val coverageResult = retrieveCoverageResult(bazelTestTarget) - ?: throw RuntimeException("Failed to retrieve coverage result for $bazelTestTarget") + ?: error("Failed to retrieve coverage result for $bazelTestTarget") - parseCoverageData(coverageResult, bazelTestTarget) + coverageDataFileLines(coverageResult, bazelTestTarget) } } @@ -51,7 +51,7 @@ class CoverageRunner( return bazelClient.runCoverageForTestTarget(bazelTestTarget) } - private fun parseCoverageData( + private fun coverageDataFileLines( coverageData: List, bazelTestTarget: String ): CoverageReport { 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 7bdab86e8cd..c94995e714e 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -45,7 +45,7 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - println(RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute()) + RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute() } } @@ -79,7 +79,6 @@ class RunCoverage( * @return a list of lists containing coverage data for each requested test target, if * the file is exempted from having a test file, an empty list is returned */ - fun execute(): List { val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .testFileExemptionList diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index b51c3f077e4..03340bb3463 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -138,71 +138,17 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedCoveredFile = CoveredFile.newBuilder() - .setFilePath("coverage/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) - .setLinesFound(4) - .setLinesHit(3) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build() - ) - .setFunctionsFound(2) - .setFunctionsHit(1) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .setBranchesFound(4) - .setBranchesHit(4) - .build() - val expectedResult = listOf( CoverageReport.newBuilder() .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .addCoveredFile(expectedCoveredFile) + .setFilePath("coverage/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .setLinesFound(4) + .setLinesHit(3) .build() ) @@ -264,71 +210,17 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedCoveredFile = CoveredFile.newBuilder() - .setFilePath("scripts/java/com/example/TwoSum.kt") - .setFileSha1Hash("1020b8f405555b3f4537fd07b912d3fb9ffa3354") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) - .setLinesFound(4) - .setLinesHit(3) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build() - ) - .setFunctionsFound(2) - .setFunctionsHit(1) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .setBranchesFound(4) - .setBranchesHit(4) - .build() - val expectedResult = listOf( CoverageReport.newBuilder() .setBazelTestTarget("//scripts/javatests/com/example:TwoSumTest") - .addCoveredFile(expectedCoveredFile) + .setFilePath("scripts/java/com/example/TwoSum.kt") + .setFileSha1Hash("1020b8f405555b3f4537fd07b912d3fb9ffa3354") + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .setLinesFound(4) + .setLinesHit(3) .build() ) @@ -390,71 +282,17 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedCoveredFile = CoveredFile.newBuilder() - .setFilePath("coverage/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) - .setLinesFound(4) - .setLinesHit(3) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build() - ) - .setFunctionsFound(2) - .setFunctionsHit(1) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .setBranchesFound(4) - .setBranchesHit(4) - .build() - val expectedResult = listOf( CoverageReport.newBuilder() - .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .addCoveredFile(expectedCoveredFile) + .setBazelTestTarget("//app/test/java/com/example:TwoSumTest") + .setFilePath("app/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .setLinesFound(4) + .setLinesHit(3) .build() ) @@ -534,75 +372,22 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedCoveredFile = CoveredFile.newBuilder() - .setFilePath("coverage/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) - .setLinesFound(4) - .setLinesHit(3) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build() - ) - .setFunctionsFound(2) - .setFunctionsHit(1) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .setBranchesFound(4) - .setBranchesHit(4) - .build() - - val expectedResult = listOf( + /*val expectedResult = listOf( CoverageReport.newBuilder() - .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .addCoveredFile(expectedCoveredFile) + .setBazelTestTarget("//app/test/java/com/example:TwoSumTest") + .setFilePath("app/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) + .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .setLinesFound(4) + .setLinesHit(3) .build() ) - assertThat(result).isEqualTo(expectedResult) + assertThat(result).isEqualTo(expectedResult)*/ + println("Result: $result") } private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { From d6c1f33f303df068b6cea1d7e0ced3d541c57bb6 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 11:56:32 +0530 Subject: [PATCH 082/105] Changed mutable lists to lists --- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 092b75fae87..953d6194d14 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -134,7 +134,7 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedResultList = mutableListOf( + val expectedResultList = listOf( listOf( "SF:coverage/main/java/com/example/TwoSum.kt", "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", @@ -217,7 +217,7 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedResultList = mutableListOf( + val expectedResultList = listOf( listOf( "SF:scripts/java/com/example/TwoSum.kt", "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", @@ -300,7 +300,7 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedResultList = mutableListOf( + val expectedResultList = listOf( listOf( "SF:app/main/java/com/example/TwoSum.kt", "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", @@ -401,7 +401,7 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val expectedResultList = mutableListOf( + val expectedResultList = listOf( listOf( "SF:app/main/java/com/example/TwoSum.kt", "FN:7,com/example/TwoSum${'$'}Companion::sumNumbers (II)Ljava/lang/Object;", From 3b6b0495b08a56bd8701eeaf3117b196abfd929a Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 11:58:37 +0530 Subject: [PATCH 083/105] Removed print statement and refactored same package deps --- scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel | 2 +- .../src/java/org/oppia/android/scripts/coverage/RunCoverage.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 4d3594ea482..5ba446fae49 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -13,8 +13,8 @@ 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/coverage:coverage_runner", "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", + "//:coverage_runner", ], ) 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 10a6539fd2e..9729b65d99d 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -44,7 +44,7 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - println(RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute()) + RunCoverage(repoRoot, filePath, commandExecutor, scriptBgDispatcher).execute() } } From d88edf632698c919f0043f6e177201b022a1b706 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 12:07:26 +0530 Subject: [PATCH 084/105] Fixed improper dep assignment --- scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index 5ba446fae49..b18167d8252 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -14,7 +14,7 @@ kt_jvm_library( deps = [ "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", - "//:coverage_runner", + ":coverage_runner", ], ) From 7a837ea17ce1c211993974e49584c32f020234c3 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 12:29:13 +0530 Subject: [PATCH 085/105] Refactor runCoverageForTarget to return non-nullable CoverageReport --- .../org/oppia/android/scripts/coverage/RunCoverage.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 c94995e714e..4530ae56b8b 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -98,15 +98,11 @@ class RunCoverage( val testTargets = bazelClient.retrieveBazelTargets(testFilePaths) return testTargets.mapNotNull { testTarget -> - val coverageData = runCoverageForTarget(testTarget) - if (coverageData == null) { - println("Coverage data for $testTarget is null") - } - coverageData + runCoverageForTarget(testTarget) } } - private fun runCoverageForTarget(testTarget: String): CoverageReport? { + private fun runCoverageForTarget(testTarget: String): CoverageReport { return runBlocking { CoverageRunner(rootDirectory, scriptBgDispatcher, commandExecutor) .runWithCoverageAsync(testTarget.removeSuffix(".kt")) From cba081503b3cbaeeab725cfa97c9c8e2102cca05 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 13:16:49 +0530 Subject: [PATCH 086/105] Fix tests in CoverageRunner and Lint checks --- .../scripts/coverage/CoverageRunnerTest.kt | 98 ++++-------- .../scripts/coverage/RunCoverageTest.kt | 141 +++++++++++++++--- 2 files changed, 153 insertions(+), 86 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 2118ff18d8e..80b0b6e0e6f 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -121,71 +121,39 @@ class CoverageRunnerTest { ).await() } - val expectedCoveredFile = CoveredFile.newBuilder() - .setFilePath("coverage/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) - .setLinesFound(4) - .setLinesHit(3) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(7) - .setFunctionName("com/example/TwoSum\$Companion::sumNumbers (II)Ljava/lang/Object;") - .setExecutionCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addFunctionCoverage( - FunctionCoverage.newBuilder() - .setLineNumber(3) - .setFunctionName("com/example/TwoSum:: ()V") - .setExecutionCount(0) - .setCoverage(Coverage.NONE).build() - ) - .setFunctionsFound(2) - .setFunctionsHit(1) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(0) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(1) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(2) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .addBranchCoverage( - BranchCoverage.newBuilder() - .setLineNumber(7) - .setBlockNumber(0) - .setBranchNumber(3) - .setHitCount(1) - .setCoverage(Coverage.FULL).build() - ) - .setBranchesFound(4) - .setBranchesHit(4) - .build() - - val expectedResult = CoverageReport.newBuilder() - .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .addCoveredFile(expectedCoveredFile) - .build() + val expectedResult = listOf( + CoverageReport.newBuilder() + .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") + .setFilePath("coverage/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) + .setLinesFound(4) + .setLinesHit(3) + .build() + ) assertThat(result).isEqualTo(expectedResult) } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 0b9b70f8f04..fc150e599a8 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -11,7 +11,6 @@ import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher import org.oppia.android.scripts.proto.Coverage import org.oppia.android.scripts.proto.CoverageReport import org.oppia.android.scripts.proto.CoveredLine -import org.oppia.android.testing.assertThrows import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import java.io.ByteArrayOutputStream @@ -143,10 +142,30 @@ class RunCoverageTest { .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") .setFilePath("coverage/main/java/com/example/TwoSum.kt") .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10). + setCoverage(Coverage.FULL) + .build() + ) .setLinesFound(4) .setLinesHit(3) .build() @@ -215,10 +234,30 @@ class RunCoverageTest { .setBazelTestTarget("//scripts/javatests/com/example:TwoSumTest") .setFilePath("scripts/java/com/example/TwoSum.kt") .setFileSha1Hash("1020b8f405555b3f4537fd07b912d3fb9ffa3354") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) .setLinesFound(4) .setLinesHit(3) .build() @@ -287,10 +326,30 @@ class RunCoverageTest { .setBazelTestTarget("//app/test/java/com/example:TwoSumTest") .setFilePath("app/main/java/com/example/TwoSum.kt") .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) .setLinesFound(4) .setLinesHit(3) .build() @@ -377,10 +436,30 @@ class RunCoverageTest { .setBazelTestTarget("//app/sharedTest/java/com/example:TwoSumTest") .setFilePath("app/main/java/com/example/TwoSum.kt") .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) .setLinesFound(4) .setLinesHit(3) .build(), @@ -388,10 +467,30 @@ class RunCoverageTest { .setBazelTestTarget("//app/test/java/com/example:TwoSumLocalTest") .setFilePath("app/main/java/com/example/TwoSum.kt") .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(3).setCoverage(Coverage.NONE).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(7).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(8).setCoverage(Coverage.FULL).build()) - .addCoveredLine(CoveredLine.newBuilder().setLineNumber(10).setCoverage(Coverage.FULL).build()) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) .setLinesFound(4) .setLinesHit(3) .build() From f6b46201922b96f46c855e0d3e1ab49af2a987df Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 13:30:27 +0530 Subject: [PATCH 087/105] Fix Lint checks --- .../org/oppia/android/scripts/coverage/CoverageRunnerTest.kt | 3 --- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 80b0b6e0e6f..4c57ee641c8 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -9,12 +9,9 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.scripts.proto.BranchCoverage import org.oppia.android.scripts.proto.Coverage 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.FunctionCoverage import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import java.util.concurrent.TimeUnit diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index fc150e599a8..a9391cc79c7 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -162,8 +162,8 @@ class RunCoverageTest { ) .addCoveredLine( CoveredLine.newBuilder() - .setLineNumber(10). - setCoverage(Coverage.FULL) + .setLineNumber(10) + .setCoverage(Coverage.FULL) .build() ) .setLinesFound(4) From cf405c617f04fd2b1ce539fcdeb04d6e166d4e33 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 16:08:39 +0530 Subject: [PATCH 088/105] Added tests for local and sharedTests separately --- .../scripts/coverage/CoverageRunner.kt | 2 +- .../scripts/testing/TestBazelWorkspace.kt | 4 +- .../android/scripts/common/BazelClientTest.kt | 1 + .../scripts/coverage/CoverageRunnerTest.kt | 1 + .../scripts/coverage/RunCoverageTest.kt | 189 ++++++++++++++++++ .../scripts/testing/TestBazelWorkspaceTest.kt | 2 + 6 files changed, 196 insertions(+), 3 deletions(-) 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 4b4de1ececa..189f72a4463 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -105,7 +105,7 @@ class CoverageRunner( private fun extractTargetName(bazelTestTarget: String): String { val targetName = bazelTestTarget.substringAfterLast(":").trim() - return targetName.removeSuffix("Test").removeSuffix("LocalTest") + return targetName.removeSuffix("LocalTest").removeSuffix("Test") } private fun calculateSha1(filePath: String): String { diff --git a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt index 2e4f1b20c0f..d9ba7d2fd70 100644 --- a/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt +++ b/scripts/src/java/org/oppia/android/scripts/testing/TestBazelWorkspace.kt @@ -62,6 +62,7 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { */ fun addSourceAndTestFileWithContent( filename: String, + testFilename: String, sourceContent: String, testContent: String, sourceSubpackage: String, @@ -73,10 +74,9 @@ class TestBazelWorkspace(private val temporaryRootFolder: TemporaryFolder) { sourceSubpackage ) - val testFileName = "${filename}Test" addTestContentAndBuildFile( filename, - testFileName, + testFilename, testContent, sourceSubpackage, testSubpackage diff --git a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt index db725861d16..ae4b2deee6f 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/common/BazelClientTest.kt @@ -422,6 +422,7 @@ class BazelClientTest { testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", + testFilename = "TwoSumTest", sourceContent = sourceContent, testContent = testContent, sourceSubpackage = "coverage/main/java/com/example", diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 4c57ee641c8..561c8ce27ab 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -106,6 +106,7 @@ class CoverageRunnerTest { testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", + testFilename = "TwoSumTest", sourceContent = sourceContent, testContent = testContent, sourceSubpackage = "coverage/main/java/com/example", diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index a9391cc79c7..768db36ce81 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -124,6 +124,7 @@ class RunCoverageTest { testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", + testFilename = "TwoSumTest", sourceContent = sourceContent, testContent = testContent, sourceSubpackage = "coverage/main/java/com/example", @@ -216,6 +217,7 @@ class RunCoverageTest { testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", + testFilename = "TwoSumTest", sourceContent = sourceContent, testContent = testContent, sourceSubpackage = "scripts/java/com/example", @@ -308,6 +310,7 @@ class RunCoverageTest { testBazelWorkspace.addSourceAndTestFileWithContent( filename = "TwoSum", + testFilename = "TwoSumTest", sourceContent = sourceContent, testContent = testContent, sourceSubpackage = "app/main/java/com/example", @@ -358,6 +361,192 @@ class RunCoverageTest { assertThat(result).isEqualTo(expectedResult) } + @Test + fun testRunCoverage_localTests_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumLocalTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumLocalTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "app/main/java/com/example", + testSubpackage = "app/test/java/com/example" + ) + + val result = RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val expectedResult = listOf( + CoverageReport.newBuilder() + .setBazelTestTarget("//app/test/java/com/example:TwoSumLocalTest") + .setFilePath("app/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) + .setLinesFound(4) + .setLinesHit(3) + .build() + ) + + assertThat(result).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_sharedTests_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "app/main/java/com/example", + testSubpackage = "app/sharedTest/java/com/example" + ) + + val result = RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val expectedResult = listOf( + CoverageReport.newBuilder() + .setBazelTestTarget("//app/sharedTest/java/com/example:TwoSumTest") + .setFilePath("app/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) + .setLinesFound(4) + .setLinesHit(3) + .build() + ) + + assertThat(result).isEqualTo(expectedResult) + } + @Test fun testRunCoverage_sharedAndLocalTests_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index b52113e817d..8724c719522 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -280,6 +280,7 @@ class TestBazelWorkspaceTest { testBazelWorkspace.addSourceAndTestFileWithContent( "Main", + "MainTest" sourceContent, testContent, sourceSubpackage = "coverage/main/java/com/example", @@ -315,6 +316,7 @@ class TestBazelWorkspaceTest { testBazelWorkspace.addSourceAndTestFileWithContent( "Main", + "MainTest", sourceContent, testContent, sourceSubpackage = "coverage/main/java/com/example", From 88f286b4c270b03d3b24032904e40358ffc11494 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 16:18:54 +0530 Subject: [PATCH 089/105] Fix Lint check, missed separator --- .../org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index 8724c719522..aeab27fe8d3 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -280,7 +280,7 @@ class TestBazelWorkspaceTest { testBazelWorkspace.addSourceAndTestFileWithContent( "Main", - "MainTest" + "MainTest", sourceContent, testContent, sourceSubpackage = "coverage/main/java/com/example", From 32d9ae4c9d9f94c01498439de17a19803b79d0e3 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 16:48:50 +0530 Subject: [PATCH 090/105] Fix Coverage Runner Test --- .../scripts/coverage/CoverageRunnerTest.kt | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 561c8ce27ab..7d795703912 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -119,39 +119,37 @@ class CoverageRunnerTest { ).await() } - val expectedResult = listOf( - CoverageReport.newBuilder() - .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .setFilePath("coverage/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build() - ) + val expectedResult = CoverageReport.newBuilder() + .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") + .setFilePath("coverage/main/java/com/example/TwoSum.kt") + .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(3) + .setCoverage(Coverage.NONE) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(7) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(8) + .setCoverage(Coverage.FULL) + .build() + ) + .addCoveredLine( + CoveredLine.newBuilder() + .setLineNumber(10) + .setCoverage(Coverage.FULL) + .build() + ) + .setLinesFound(4) + .setLinesHit(3) + .build() assertThat(result).isEqualTo(expectedResult) } From a17377a634df8b4efde072ab9986c28033fdf5b6 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 18:08:43 +0530 Subject: [PATCH 091/105] Cleaned the md report generation to just hold line coverage data --- .../scripts/coverage/CoverageReporter.kt | 105 ++++-------------- .../android/scripts/coverage/RunCoverage.kt | 2 +- 2 files changed, 24 insertions(+), 83 deletions(-) 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 6288acdea0a..dddba8525fb 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -21,64 +21,34 @@ class CoverageReporter( } private fun generateMarkdownReport(computedCoverageRatio: Float): String { - val computedCoveragePercentage = "%.2f".format(computedCoverageRatio) - val totalFiles = coverageReportList.size - val filePath = coverageReportList.firstOrNull()?.getCoveredFile(0)?.filePath ?: "Unknown" + val computedCoveragePercentage = computedCoverageRatio * 100 + val formattedCoveragePercentage = "%.2f".format(computedCoveragePercentage) + val filePath = coverageReportList.firstOrNull()?.filePath ?: "Unknown" - val (totalLinesFound, totalLinesHit) = computeTotalsFor("lines") - val (totalFunctionsFound, totalFunctionsHit) = computeTotalsFor("functions") - val (totalBranchesFound, totalBranchesHit) = computeTotalsFor("branches") + val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0 + val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 val markdownReport = """ - # Coverage Report - - **Total coverage:** - - **Files covered:** $totalFiles - - **Covered File:** $filePath - - **Coverage percentage:** $computedCoveragePercentage% covered - - **Line coverage:** $totalLinesHit covered / $totalLinesFound found - - **Function coverage:** $totalFunctionsHit covered / $totalFunctionsFound found - - **Branch coverage:** $totalBranchesFound covered / $totalBranchesHit found + ## Coverage Report - """.trimIndent() + - **Covered File:** $filePath + - **Coverage percentage:** $formattedCoveragePercentage% covered + - **Line coverage:** $totalLinesHit / $totalLinesFound lines covered + """.trimIndent() - val outputFile = File(reportOutputPath) - outputFile.parentFile?.mkdirs() - outputFile.writeText(markdownReport) + File(reportOutputPath).apply { + parentFile?.mkdirs() + writeText(markdownReport) + } - println("MARKDOWN: $markdownReport") + println("\n$markdownReport") return reportOutputPath } - private fun computeTotalsFor(type: String): Pair { - var totalFound = 0 - var totalHit = 0 - - coverageReportList.forEach { coverageReport -> - coverageReport.coveredFileList.forEach { coveredFile -> - when (type) { - "lines" -> { - totalFound += coveredFile.linesFound - totalHit += coveredFile.linesHit - } - "functions" -> { - totalFound += coveredFile.functionsFound - totalHit += coveredFile.functionsHit - } - "branches" -> { - totalFound += coveredFile.branchesFound - totalHit += coveredFile.branchesHit - } - } - } - } - - return Pair(totalFound, totalHit) - } - //just line coverage fun generateHtmlReport(): String { + /* // val reportOutputPath = "path/to/your/report.html" // Replace with your desired output path println("In HTML report generation") @@ -93,8 +63,6 @@ class CoverageReporter( val filePath = coveredFile.filePath ?: "Unknown" val (totalLinesFound, totalLinesHit) = Pair(0,0) - val (totalFunctionsFound, totalFunctionsHit) = Pair(0, 0) - val (totalBranchesFound, totalBranchesHit) = Pair(0, 0) var htmlContent = """ @@ -142,8 +110,6 @@ class CoverageReporter(
  • Covered File: $filePath
  • Coverage percentage: $computedCoveragePercentage% covered
  • Line coverage: $totalLinesHit covered / $totalLinesFound found
  • -
  • Function coverage: $totalFunctionsHit covered / $totalFunctionsFound found
  • -
  • Branch coverage: $totalBranchesHit covered / $totalBranchesFound found
  • @@ -175,42 +141,17 @@ class CoverageReporter(
         outputFile.writeText(htmlContent)
     
         return reportOutputPath
    -//    return ""
    -  }
    -
    -  fun getColorBasedOnCoverage(hit: Int, found: Int): String {
    -    val coveragePercentage = if (found == 0) 0 else (hit.toFloat() / found * 100).toInt()
    -    return when {
    -      coveragePercentage == 100 -> "#c8e6c9"
    -      coveragePercentage >= 50 -> "#fff9c4"
    -      else -> "#ffcdd2"
    -    }
    -  }
    -
    -  fun getCumulativeCoverageClass(): String {
    -    val isLineCovered = true
    -    val isBranchCovered = false
    -    val isFunctionCovered = true
    -
    -    return when {
    -      isLineCovered && isBranchCovered && isFunctionCovered -> "covered-line"
    -      isLineCovered || isBranchCovered || isFunctionCovered -> "partially-covered-line"
    -      else -> "not-covered-line"
    -    }
    +  */
    +    return ""
       }
     
       fun computeCoverageRatio(): Float {
    -    var totalFound = 0f
    -    var totalHit = 0f
    -
    -    coverageReportList.forEach { coverageReport ->
    -      coverageReport.coveredFileList.forEach { coveredFile ->
    -        totalFound += (coveredFile.linesFound + coveredFile.functionsFound + coveredFile.branchesFound).toFloat()
    -        totalHit += (coveredFile.linesHit + coveredFile.functionsHit + coveredFile.branchesHit).toFloat()
    -      }
    +    val report = coverageReportList.getOrNull(0)
    +    return if (report != null && report.linesFound != 0) {
    +      report.linesHit.toFloat() / report.linesFound.toFloat()
    +    } else {
    +      0f
         }
    -
    -    return if (totalFound > 0) (totalHit / totalFound * 100) else 0.0f
       }
     }
     
    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 41b1a748476..4fe3eb8ba53 100644
    --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt
    +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt
    @@ -124,7 +124,7 @@ class RunCoverage(
           val reporter = CoverageReporter(repoRoot, coverageReports, reportFormat, reportOutputPath)
           val coverageRatio = reporter.computeCoverageRatio()
           val generatedReport = reporter.generateRichTextReport(coverageRatio)
    -      println("Generated report: $generatedReport")
    +      println("\nGenerated report at: $generatedReport\n")
         } else {
           println("No coverage reports generated.")
         }
    
    From 12eecfe40ffec265c26ad167170ee934430c3bbe Mon Sep 17 00:00:00 2001
    From: Rd 
    Date: Wed, 26 Jun 2024 20:00:18 +0530
    Subject: [PATCH 092/105] Cleaned the html report generation to just hold line
     coverage data
    
    ---
     .../scripts/coverage/CoverageReporter.kt      | 192 +++++++++++-------
     .../scripts/coverage/CoverageRunner.kt        |   7 +-
     2 files changed, 120 insertions(+), 79 deletions(-)
    
    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 dddba8525fb..bdc72c47790 100644
    --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt
    +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt
    @@ -16,7 +16,7 @@ class CoverageReporter(
         println("report format: $reportFormat")
         return when (reportFormat) {
           ReportFormat.MARKDOWN -> generateMarkdownReport(computedCoverageRatio)
    -      ReportFormat.HTML -> generateHtmlReport()
    +      ReportFormat.HTML -> generateHtmlReport(computedCoverageRatio)
         }
       }
     
    @@ -47,102 +47,140 @@ class CoverageReporter(
       }
     
     
    -  fun generateHtmlReport(): String {
    -  /*
    -//    val reportOutputPath = "path/to/your/report.html"  // Replace with your desired output path
    -
    -    println("In HTML report generation")
    -
    -    val coverageReport = coverageReportList.firstOrNull() ?: return "No coverage report found."
    -
    -    val computedCoverageRatio = computeCoverageRatio() // Implement this function
    -
    -    val computedCoveragePercentage = "%.2f".format(computedCoverageRatio)
    -    val totalFiles = coverageReportList.size
    -    val coveredFile = coverageReport.getCoveredFile(0) ?: return "No covered file found."
    -    val filePath = coveredFile.filePath ?: "Unknown"
    +  fun generateHtmlReport(computedCoverageRatio: Float): String {
    +    val computedCoveragePercentage = "%.2f".format(computedCoverageRatio).toFloat()
    +    val filePath = coverageReportList.firstOrNull()?.filePath ?: "Unknown"
     
    -    val (totalLinesFound, totalLinesHit) = Pair(0,0)
    +    val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0
    +    val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0
     
         var htmlContent = """
    -        
    -        
    -        
    -            
    -            
    -            Coverage Report
    -            
    -        
    -        
    -            

    Coverage Report

    -
    -

    Total coverage:

    -
      -
    • Files covered: $totalFiles
    • -
    • Covered File: $filePath
    • -
    • Coverage percentage: $computedCoveragePercentage% covered
    • -
    • Line coverage: $totalLinesHit covered / $totalLinesFound found
    • -
    -
    -
    +    
    +    
    +    
    +      
    +      
    +      Coverage Report
    +      
    +    
    +    
    +      

    Coverage Report

    +
    +
      +
    • Covered File: $filePath
    • +
    • Coverage percentage: ${computedCoveragePercentage * 100}% covered
    • +
    • Line coverage: $totalLinesHit covered / $totalLinesFound found
    • +
    +
    + + + + + + + + """.trimIndent() - val fileContent = File("/mnt/c/Users/Baskaran/AndroidStudioProjects/oppia-android", filePath).readLines() - val coverageMap = coveredFile.coveredLineList.associateBy { it.lineNumber } + val fileContent = File(repoRoot, filePath).readLines() + val coverageMap = coverageReportList.firstOrNull()?.coveredLineList?.associateBy { it.lineNumber } fileContent.forEachIndexed { index, line -> val lineNumber = index + 1 - val lineClass = when (coverageMap[lineNumber]?.coverage) { + val lineClass = when (coverageMap?.get(lineNumber)?.coverage) { Coverage.FULL -> "covered-line" Coverage.NONE -> "not-covered-line" else -> "uncovered-line" } - htmlContent += "
    ${lineNumber.toString().padStart(4, ' ')}: $line
    \n" + htmlContent += """ + + + + + """.trimIndent() } htmlContent += """ - - - + +
    Line NoSource Code
    ${lineNumber.toString().padStart(4, ' ')}$line
    + + """.trimIndent() - println("HTML content: $htmlContent") + println(htmlContent) - val outputFile = File(reportOutputPath) - outputFile.parentFile.mkdirs() - outputFile.writeText(htmlContent) + File(reportOutputPath).apply { + parentFile?.mkdirs() + writeText(htmlContent) + } return reportOutputPath - */ - return "" } fun computeCoverageRatio(): Float { 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 189f72a4463..92e095e5a18 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -60,7 +60,7 @@ class CoverageRunner( val sfStartIdx = coverageData.indexOfFirst { it.startsWith("SF:") && it.substringAfter("SF:").substringAfterLast("/") == extractedFileName } - if (sfStartIdx == -1) throw IllegalArgumentException("File not found") + if (sfStartIdx == -1) throw IllegalArgumentException("File not found, bazel: $bazelTestTarget coverage data: $coverageData, extracted: $extractedFileName") val eofIdx = coverageData.subList(sfStartIdx, coverageData.size).indexOfFirst { it.startsWith("end_of_record") } @@ -104,7 +104,10 @@ class CoverageRunner( } private fun extractTargetName(bazelTestTarget: String): String { - val targetName = bazelTestTarget.substringAfterLast(":").trim() + val targetName = bazelTestTarget + .substringAfterLast("/") + .substringAfterLast(":") + .trim() return targetName.removeSuffix("LocalTest").removeSuffix("Test") } From 9b28dcaf13c158c8871c73cdb5499d5e6d35841f Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 20:17:06 +0530 Subject: [PATCH 093/105] Code cleanup - refactored redundant code --- .../scripts/coverage/CoverageReporter.kt | 39 ++++++++----------- .../android/scripts/coverage/RunCoverage.kt | 15 ++----- 2 files changed, 19 insertions(+), 35 deletions(-) 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 bdc72c47790..c1a7b2087a9 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -10,24 +10,24 @@ class CoverageReporter( private val reportFormat: ReportFormat, private val reportOutputPath: String ) { + val computedCoverageRatio = computeCoverageRatio() + val formattedCoveragePercentage = "%.2f".format(computedCoverageRatio * 100) - fun generateRichTextReport(computedCoverageRatio: Float): String { + val filePath = coverageReportList.firstOrNull()?.filePath ?: "Unknown" + + val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0 + val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 + + fun generateRichTextReport(): Pair { println("output: $reportOutputPath") println("report format: $reportFormat") return when (reportFormat) { - ReportFormat.MARKDOWN -> generateMarkdownReport(computedCoverageRatio) - ReportFormat.HTML -> generateHtmlReport(computedCoverageRatio) + ReportFormat.MARKDOWN -> generateMarkdownReport() + ReportFormat.HTML -> generateHtmlReport() } } - private fun generateMarkdownReport(computedCoverageRatio: Float): String { - val computedCoveragePercentage = computedCoverageRatio * 100 - val formattedCoveragePercentage = "%.2f".format(computedCoveragePercentage) - val filePath = coverageReportList.firstOrNull()?.filePath ?: "Unknown" - - val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0 - val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 - + private fun generateMarkdownReport(): Pair { val markdownReport = """ ## Coverage Report @@ -43,17 +43,10 @@ class CoverageReporter( println("\n$markdownReport") - return reportOutputPath + return Pair(computedCoverageRatio, reportOutputPath) } - - fun generateHtmlReport(computedCoverageRatio: Float): String { - val computedCoveragePercentage = "%.2f".format(computedCoverageRatio).toFloat() - val filePath = coverageReportList.firstOrNull()?.filePath ?: "Unknown" - - val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0 - val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 - + fun generateHtmlReport(): Pair { var htmlContent = """ @@ -134,7 +127,7 @@ class CoverageReporter(
    • Covered File: $filePath
    • -
    • Coverage percentage: ${computedCoveragePercentage * 100}% covered
    • +
    • Coverage percentage: $formattedCoveragePercentage% covered
    • Line coverage: $totalLinesHit covered / $totalLinesFound found
    @@ -180,10 +173,10 @@ class CoverageReporter( writeText(htmlContent) } - return reportOutputPath + return Pair(computedCoverageRatio, reportOutputPath) } - fun computeCoverageRatio(): Float { + private fun computeCoverageRatio(): Float { val report = coverageReportList.getOrNull(0) return if (report != null && report.linesFound != 0) { report.linesHit.toFloat() / report.linesFound.toFloat() 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 4fe3eb8ba53..d510c546f7a 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -79,12 +79,6 @@ class RunCoverage( private val rootDirectory = File(repoRoot).absoluteFile private val testFileExemptionTextProto = "scripts/assets/test_file_exemptions" - companion object { - // The minimum coverage percentage threshold for coverage analysis, - // The script will fail if the file has less than the minimum specified coverage. - const val MIN_COVERAGE_PERCENTAGE = 20 - } - /** * Executes coverage analysis for the specified file. * @@ -118,13 +112,11 @@ class RunCoverage( runCoverageForTarget(testTarget) } - println("Generated Coverage Reports proto: $coverageReports") - if (coverageReports.isNotEmpty()) { val reporter = CoverageReporter(repoRoot, coverageReports, reportFormat, reportOutputPath) - val coverageRatio = reporter.computeCoverageRatio() - val generatedReport = reporter.generateRichTextReport(coverageRatio) - println("\nGenerated report at: $generatedReport\n") + val (computedCoverageRatio, reportOutputPath) = reporter.generateRichTextReport() + println("\nComputed Coverage Ratio is: $computedCoverageRatio") + println("\nGenerated report at: $reportOutputPath\n") } else { println("No coverage reports generated.") } @@ -167,7 +159,6 @@ private fun findTestFile(repoRoot: String, filePath: String): List { } private fun getReportOutputPath(repoRoot: String, filePath: String, reportFormat: ReportFormat): String { - println("Repo root: $repoRoot") val fileWithoutExtension = filePath.substringBeforeLast(".") val defaultFilename = when (reportFormat) { ReportFormat.HTML -> "coverage.html" From a0bc41c4f53687cea066153fa069b491c923c18a Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 21:46:01 +0530 Subject: [PATCH 094/105] Resolved conflicting overloads --- .../scripts/testing/TestBazelWorkspaceTest.kt | 162 ------------------ 1 file changed, 162 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt index 9f0fc3e08df..aeab27fe8d3 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/testing/TestBazelWorkspaceTest.kt @@ -517,168 +517,6 @@ class TestBazelWorkspaceTest { ) } - @Test - fun testAddMultiLevelSourceAndTestFileWithContent_createsSourceAndTestFiles() { - val testBazelWorkspace = TestBazelWorkspace(tempFolder) - val sourceContent = - """ - fun main() { - println("Hello, World!") - } - """ - - val testContentShared = - """ - import org.junit.Test - import kotlin.test.assertEquals - - class MainTest { - - @Test - fun testMain() { - assertEquals(1, 1) - } - } - """ - - val testContentLocal = - """ - import org.junit.Test - import kotlin.test.assertEquals - - class MainTestLocal { - - @Test - fun testMain() { - assertEquals(1, 2) - } - } - """ - - testBazelWorkspace.addMultiLevelSourceAndTestFileWithContent( - filename = "Main", - sourceContent = sourceContent, - testContentShared = testContentShared, - testContentLocal = testContentLocal, - subpackage = "coverage" - ) - - val sourceFile = File(tempFolder.root, "coverage/main/java/com/example/Main.kt") - val testFileShared = File(tempFolder.root, "coverage/sharedTest/java/com/example/MainTest.kt") - val testFileLocal = File(tempFolder.root, "coverage/test/java/com/example/MainLocalTest.kt") - - assertThat(sourceFile.exists()).isTrue() - assertThat(sourceFile.readText()).isEqualTo(sourceContent) - - assertThat(testFileShared.exists()).isTrue() - assertThat(testFileShared.readText()).isEqualTo(testContentShared) - - assertThat(testFileLocal.exists()).isTrue() - assertThat(testFileLocal.readText()).isEqualTo(testContentLocal) - } - - @Test - fun testAddMultiLevelSourceAndTestFileWithContent_updatesBuildFiles() { - val testBazelWorkspace = TestBazelWorkspace(tempFolder) - val sourceContent = - """ - fun main() { - println("Hello, World!") - } - """ - - val testContentShared = - """ - import org.junit.Test - import kotlin.test.assertEquals - - class MainTest { - - @Test - fun testMain() { - assertEquals(1, 1) - } - } - """ - - val testContentLocal = - """ - import org.junit.Test - import kotlin.test.assertEquals - - class MainTestLocal { - - @Test - fun testMain() { - assertEquals(1, 2) - } - } - """ - - testBazelWorkspace.addMultiLevelSourceAndTestFileWithContent( - filename = "Main", - sourceContent = sourceContent, - testContentShared = testContentShared, - testContentLocal = testContentLocal, - subpackage = "coverage" - ) - - val sourceBuildFile = File( - tempFolder.root, "coverage/main/java/com/example/BUILD.bazel" - ) - val testBuildFileShared = File( - tempFolder.root, "coverage/sharedTest/java/com/example/BUILD.bazel" - ) - val testBuildFileLocal = File( - tempFolder.root, "coverage/test/java/com/example/BUILD.bazel" - ) - - assertThat(sourceBuildFile.exists()).isTrue() - assertThat(sourceBuildFile.readText()).contains( - """ - kt_jvm_library( - name = "main", - srcs = ["Main.kt"], - visibility = ["//visibility:public"] - ) - """.trimIndent() - ) - - assertThat(testBuildFileShared.exists()).isTrue() - assertThat(testBuildFileShared.readText()).contains( - """ - load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") - kt_jvm_test( - name = "MainTest", - srcs = ["MainTest.kt"], - deps = [ - "//coverage/main/java/com/example:main", - "@maven//:junit_junit", - ], - visibility = ["//visibility:public"], - test_class = "com.example.MainTest", - ) - """.trimIndent() - ) - - assertThat(testBuildFileLocal.exists()).isTrue() - assertThat(testBuildFileLocal.readText()).contains( - """ - load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") - kt_jvm_test( - name = "MainLocalTest", - srcs = ["MainLocalTest.kt"], - deps = [ - "//coverage/main/java/com/example:main", - "@maven//:junit_junit", - ], - visibility = ["//visibility:public"], - test_class = "com.example.MainLocalTest", - ) - """.trimIndent() - ) - } - @Test fun testAddSourceContentAndBuildFile_createsSourceFileAndBuildFile() { val testBazelWorkspace = TestBazelWorkspace(tempFolder) From 01e0ad9efdf7ff15e19655d85e292a73c8f8a8b9 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 05:59:55 +0530 Subject: [PATCH 095/105] Added tests for CoverageReporter utility --- .../android/scripts/coverage/BUILD.bazel | 3 +- .../scripts/coverage/CoverageReporter.kt | 22 +- .../android/scripts/coverage/RunCoverage.kt | 22 +- .../android/scripts/coverage/BUILD.bazel | 21 +- .../scripts/coverage/CoverageReporterTest.kt | 257 ++++++++++++++++++ 5 files changed, 292 insertions(+), 33 deletions(-) create mode 100644 scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt diff --git a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel index ed3f76d6305..246ff4403e4 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/java/org/oppia/android/scripts/coverage/BUILD.bazel @@ -12,11 +12,10 @@ kt_jvm_library( ], visibility = ["//scripts:oppia_script_binary_visibility"], deps = [ + ":coverage_reporter", ":coverage_runner", "//scripts/src/java/org/oppia/android/scripts/common:bazel_client", "//scripts/src/java/org/oppia/android/scripts/proto:script_exemptions_java_proto", - ":coverage_runner", - ":coverage_reporter", ], ) 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 c1a7b2087a9..a172f8a599d 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -8,7 +8,6 @@ class CoverageReporter( private val repoRoot: String, private val coverageReportList: List, private val reportFormat: ReportFormat, - private val reportOutputPath: String ) { val computedCoverageRatio = computeCoverageRatio() val formattedCoveragePercentage = "%.2f".format(computedCoverageRatio * 100) @@ -19,7 +18,6 @@ class CoverageReporter( val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 fun generateRichTextReport(): Pair { - println("output: $reportOutputPath") println("report format: $reportFormat") return when (reportFormat) { ReportFormat.MARKDOWN -> generateMarkdownReport() @@ -28,7 +26,7 @@ class CoverageReporter( } private fun generateMarkdownReport(): Pair { - val markdownReport = """ + val markdownContent = """ ## Coverage Report - **Covered File:** $filePath @@ -36,14 +34,9 @@ class CoverageReporter( - **Line coverage:** $totalLinesHit / $totalLinesFound lines covered """.trimIndent() - File(reportOutputPath).apply { - parentFile?.mkdirs() - writeText(markdownReport) - } - - println("\n$markdownReport") + println("\n$markdownContent") - return Pair(computedCoverageRatio, reportOutputPath) + return Pair(computedCoverageRatio, markdownContent) } fun generateHtmlReport(): Pair { @@ -166,14 +159,7 @@ class CoverageReporter( """.trimIndent() - println(htmlContent) - - File(reportOutputPath).apply { - parentFile?.mkdirs() - writeText(htmlContent) - } - - return Pair(computedCoverageRatio, reportOutputPath) + return Pair(computedCoverageRatio, htmlContent) } private fun computeCoverageRatio(): Float { 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 a5418a8e457..4d3b48cf786 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -112,14 +112,20 @@ class RunCoverage( runCoverageForTarget(testTarget) } - if (coverageReports.isNotEmpty()) { - val reporter = CoverageReporter(repoRoot, coverageReports, reportFormat, reportOutputPath) - val (computedCoverageRatio, reportOutputPath) = reporter.generateRichTextReport() - println("\nComputed Coverage Ratio is: $computedCoverageRatio") - println("\nGenerated report at: $reportOutputPath\n") - } else { - println("No coverage reports generated.") - } + coverageReports.takeIf { it.isNotEmpty() }?.run { + val reporter = CoverageReporter(repoRoot, this, reportFormat) + val (computedCoverageRatio, reportText) = reporter.generateRichTextReport() + + File(reportOutputPath).apply { + parentFile?.mkdirs() + writeText(reportText) + } + + if (File(reportOutputPath).exists()) { + println("\nComputed Coverage Ratio is: $computedCoverageRatio") + println("\nGenerated report at: $reportOutputPath\n") + } + } ?: println("No coverage reports generated.") return coverageReports } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel index 6c200e83d8a..d67bf159ebe 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/BUILD.bazel @@ -4,6 +4,19 @@ Tests corresponding to developer scripts that help with obtaining coverage data load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") +kt_jvm_test( + name = "RunCoverageTest", + srcs = ["RunCoverageTest.kt"], + deps = [ + "//scripts:test_file_check_assets", + "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_lib", + "//scripts/src/java/org/oppia/android/scripts/testing:test_bazel_workspace", + "//testing:assertion_helpers", + "//third_party:com_google_truth_truth", + "//third_party:org_jetbrains_kotlin_kotlin-test-junit", + ], +) + kt_jvm_test( name = "CoverageRunnerTest", srcs = ["CoverageRunnerTest.kt"], @@ -17,12 +30,10 @@ kt_jvm_test( ) kt_jvm_test( - name = "RunCoverageTest", - srcs = ["RunCoverageTest.kt"], + name = "CoverageReporterTest", + srcs = ["CoverageReporterTest.kt"], deps = [ - "//scripts:test_file_check_assets", - "//scripts/src/java/org/oppia/android/scripts/coverage:run_coverage_lib", - "//scripts/src/java/org/oppia/android/scripts/testing:test_bazel_workspace", + "//scripts/src/java/org/oppia/android/scripts/coverage:coverage_reporter", "//testing:assertion_helpers", "//third_party:com_google_truth_truth", "//third_party:org_jetbrains_kotlin_kotlin-test-junit", diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt new file mode 100644 index 00000000000..6aa60142ed3 --- /dev/null +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt @@ -0,0 +1,257 @@ +package org.oppia.android.scripts.coverage + +import com.google.common.truth.Truth.assertThat +import org.junit.* +import org.junit.rules.TemporaryFolder +import org.oppia.android.scripts.proto.CoverageReport +import java.io.File + +class CoverageReporterTest { + @field:[Rule JvmField] val tempFolder = TemporaryFolder() + + private lateinit var reporter: CoverageReporter + private lateinit var validCoverageReport: CoverageReport + private val emptyCoverageReportList = listOf() + + @Before + fun setUp() { + validCoverageReport = CoverageReport.newBuilder() + .setFilePath("SampleFile.kt") + .setLinesFound(10) + .setLinesHit(8) + .build() + } + + @Test + fun testCoverageReporter_initializationWithValidData_initializesCorrectly() { + val expectedTotalLinesFound = 10 + val expectedTotalLinesHit = 8 + val expectedFilePath = "SampleFile.kt" + val expectedFormattedCoveragePercentage = "80.00" + reporter = CoverageReporter( + tempFolder.root.absolutePath, + listOf(validCoverageReport), + ReportFormat.MARKDOWN + ) + assertThat(expectedFilePath).isEqualTo(reporter.filePath) + assertThat(expectedTotalLinesFound).isEqualTo(reporter.totalLinesFound) + assertThat(expectedTotalLinesHit).isEqualTo(reporter.totalLinesHit) + assertThat(expectedFormattedCoveragePercentage).isEqualTo(reporter.formattedCoveragePercentage) + } + + @Test + fun testCoverageReporter_initializationWithEmptyCoverageReportList_initializesWithDefaults() { + val expectedTotalLinesFound = 0 + val expectedTotalLinesHit = 0 + val expectedFormattedCoveragePercentage = "0.00" + val unknownFilePath = "Unknown" + reporter = CoverageReporter( + tempFolder.root.absolutePath, + emptyCoverageReportList, + ReportFormat.MARKDOWN + ) + assertThat(unknownFilePath).isEqualTo(reporter.filePath) + assertThat(expectedTotalLinesFound).isEqualTo(reporter.totalLinesFound) + assertThat(expectedTotalLinesHit).isEqualTo(reporter.totalLinesHit) + assertThat(expectedFormattedCoveragePercentage).isEqualTo(reporter.formattedCoveragePercentage) + } + + @Test + fun testCoverageReporter_generateMarkdownReportWithValidData_generatesCorrectCoverageRatio() { + reporter = CoverageReporter( + tempFolder.root.absolutePath, + listOf(validCoverageReport), + ReportFormat.MARKDOWN + ) + val expectedCoverageRatio = 0.8F + val (coverageRatio, _) = reporter.generateRichTextReport() + assertThat(expectedCoverageRatio).isEqualTo(coverageRatio) + } + + @Test + fun testCoverageReporter_generateMarkdownReportWithNoLinesFound_generatesCorrectCoverageRatio() { + val expectedZeroCoverageRatio = 0F + // to check divided by zero error doesn't occur + val report = validCoverageReport.toBuilder().setLinesFound(0).build() + reporter = CoverageReporter( + tempFolder.root.absolutePath, + listOf(report), + ReportFormat.MARKDOWN + ) + val (coverageRatio, _) = reporter.generateRichTextReport() + assertThat(expectedZeroCoverageRatio).isEqualTo(coverageRatio) + } + + @Test + fun testCoverageReporter_markdownReportText_check() { + reporter = CoverageReporter( + tempFolder.root.absolutePath, + listOf(validCoverageReport), + ReportFormat.MARKDOWN + ) + val (_, reportText) = reporter.generateRichTextReport() + + val expectedMarkdown = """ + ## Coverage Report + + - **Covered File:** SampleFile.kt + - **Coverage percentage:** 80.00% covered + - **Line coverage:** 8 / 10 lines covered + """.trimIndent() + + assertThat(reportText).isEqualTo(expectedMarkdown) + } + + @Test + fun testCoverageReporter_htmlReportText_check() { + val sourceFile = tempFolder.newFile("SampleFile.kt") + sourceFile.writeText(""" + fun main() { + println("Hello, World!") + val x = 10 + val y = 20 + val sum = x + y + println("Sum: 30") + for (i in 1..10) { + println(i) + } + } + """.trimIndent()) + + reporter = CoverageReporter( + tempFolder.root.absolutePath, + listOf(validCoverageReport), + ReportFormat.HTML + ) + val (_, reportText) = reporter.generateHtmlReport() + + val expectedHTML = """ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +
      +
    • Covered File: SampleFile.kt
    • +
    • Coverage percentage: 80.00% covered
    • +
    • Line coverage: 8 covered / 10 found
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1 fun main() {
    2 println("Hello, World!")
    3 val x = 10
    4 val y = 20
    5 val sum = x + y
    6 println("Sum: 30")
    7 for (i in 1..10) {
    8 println(i)
    9 }
    10}
    + + + """.trimIndent() + + assertThat(reportText).isEqualTo(expectedHTML) + } +} From 6416569286191f1e4ae9a4e8659c9e0daeec76bb Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 06:06:33 +0530 Subject: [PATCH 096/105] Renamed test case names to be more crisp and clear --- .../android/scripts/coverage/CoverageReporterTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt index 6aa60142ed3..e7e4a075416 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt @@ -23,7 +23,7 @@ class CoverageReporterTest { } @Test - fun testCoverageReporter_initializationWithValidData_initializesCorrectly() { + fun testCoverageReporter_validData_initializesCorrectly() { val expectedTotalLinesFound = 10 val expectedTotalLinesHit = 8 val expectedFilePath = "SampleFile.kt" @@ -40,7 +40,7 @@ class CoverageReporterTest { } @Test - fun testCoverageReporter_initializationWithEmptyCoverageReportList_initializesWithDefaults() { + fun testCoverageReporter_emptyCoverageReportList_initializesWithDefaults() { val expectedTotalLinesFound = 0 val expectedTotalLinesHit = 0 val expectedFormattedCoveragePercentage = "0.00" @@ -57,7 +57,7 @@ class CoverageReporterTest { } @Test - fun testCoverageReporter_generateMarkdownReportWithValidData_generatesCorrectCoverageRatio() { + fun testCoverageReporter_validData_generatesCorrectCoverageRatio() { reporter = CoverageReporter( tempFolder.root.absolutePath, listOf(validCoverageReport), @@ -69,7 +69,7 @@ class CoverageReporterTest { } @Test - fun testCoverageReporter_generateMarkdownReportWithNoLinesFound_generatesCorrectCoverageRatio() { + fun testCoverageReporter_noLinesFound_generatesZeroCoverageRatio() { val expectedZeroCoverageRatio = 0F // to check divided by zero error doesn't occur val report = validCoverageReport.toBuilder().setLinesFound(0).build() From 3bf991948da340a77dea80655b34b2ed146662e4 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 09:21:20 +0530 Subject: [PATCH 097/105] Added tests for RunCoverage to check md and html reports --- .../android/scripts/coverage/RunCoverage.kt | 7 +- .../scripts/coverage/RunCoverageTest.kt | 1638 ++++++++++++++--- 2 files changed, 1392 insertions(+), 253 deletions(-) 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 4d3b48cf786..df5e9a23195 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -90,15 +90,14 @@ class RunCoverage( * @return a list of lists containing coverage data for each requested test target, if * the file is exempted from having a test file, an empty list is returned */ - fun execute(): List { + fun execute(): String { val testFileExemptionList = loadTestFileExemptionsProto(testFileExemptionTextProto) .testFileExemptionList .filter { it.testFileNotRequired } .map { it.exemptedFilePath } if (filePath in testFileExemptionList) { - println("This file is exempted from having a test file; skipping coverage check.") - return emptyList() + return "This file is exempted from having a test file; skipping coverage check." } val testFilePaths = findTestFile(repoRoot, filePath) @@ -127,7 +126,7 @@ class RunCoverage( } } ?: println("No coverage reports generated.") - return coverageReports + return reportOutputPath } private fun runCoverageForTarget(testTarget: String): CoverageReport { diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 8c03e97a5c4..083d09148a2 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -31,10 +31,14 @@ class RunCoverageTest { private lateinit var testBazelWorkspace: TestBazelWorkspace private lateinit var sampleFilePath: String + private lateinit var sampleMDOutputPath: String + private lateinit var sampleHTMLOutputPath: String @Before fun setUp() { sampleFilePath = "/path/to/Sample.kt" + sampleMDOutputPath = "${tempFolder.root}/coverage_reports/report.md" + sampleHTMLOutputPath = "${tempFolder.root}/coverage_reports/report.html" testBazelWorkspace = TestBazelWorkspace(tempFolder) System.setOut(PrintStream(outContent)) } @@ -71,19 +75,20 @@ class RunCoverageTest { fun testRunCoverage_testFileExempted_noCoverage() { val exemptedFilePath = "app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt" - RunCoverage( + val result = RunCoverage( "${tempFolder.root}", exemptedFilePath, + ReportFormat.MARKDOWN, + sampleMDOutputPath, commandExecutor, scriptBgDispatcher ).execute() - assertThat(outContent.toString()) - .isEqualTo("This file is exempted from having a test file; skipping coverage check.\n") + assertThat(result).isEqualTo("This file is exempted from having a test file; skipping coverage check.") } @Test - fun testRunCoverage_sampleTests_returnsCoverageData() { + fun testRunCoverage_sampleTestsDefaultFormat_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -131,52 +136,99 @@ class RunCoverageTest { testSubpackage = "coverage/test/java/com/example" ) - val result = RunCoverage( + main( "${tempFolder.root}", "coverage/main/java/com/example/TwoSum.kt", + ) + + val outputReportText = File( + "${tempFolder.root}/coverage_reports/coverage/main/java/com/example/TwoSum/coverage.md" + ).readText() + + val expectedResult = """ + ## Coverage Report + + - **Covered File:** coverage/main/java/com/example/TwoSum.kt + - **Coverage percentage:** 75.00% covered + - **Line coverage:** 3 / 4 lines covered + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_sampleTestsMarkdownFormat_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" + ) + + RunCoverage( + "${tempFolder.root}", + "coverage/main/java/com/example/TwoSum.kt", + ReportFormat.MARKDOWN, + sampleMDOutputPath, longCommandExecutor, scriptBgDispatcher ).execute() - val expectedResult = listOf( - CoverageReport.newBuilder() - .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") - .setFilePath("coverage/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build() - ) + val outputReportText = File(sampleMDOutputPath).readText() - assertThat(result).isEqualTo(expectedResult) + val expectedResult = """ + ## Coverage Report + + - **Covered File:** coverage/main/java/com/example/TwoSum.kt + - **Coverage percentage:** 75.00% covered + - **Line coverage:** 3 / 4 lines covered + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) } @Test - fun testRunCoverage_scriptTests_returnsCoverageData() { + fun testRunCoverage_scriptTestsMarkdownFormat_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -224,52 +276,30 @@ class RunCoverageTest { testSubpackage = "scripts/javatests/com/example" ) - val result = RunCoverage( + RunCoverage( "${tempFolder.root}", + sampleMDOutputPath, + ReportFormat.MARKDOWN, "scripts/java/com/example/TwoSum.kt", longCommandExecutor, scriptBgDispatcher ).execute() - val expectedResult = listOf( - CoverageReport.newBuilder() - .setBazelTestTarget("//scripts/javatests/com/example:TwoSumTest") - .setFilePath("scripts/java/com/example/TwoSum.kt") - .setFileSha1Hash("1020b8f405555b3f4537fd07b912d3fb9ffa3354") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build() - ) + val outputReportText = File(sampleMDOutputPath).readText() + + val expectedResult = """ + ## Coverage Report + + - **Covered File:** scripts/java/com/example/TwoSum.kt + - **Coverage percentage:** 75.00% covered + - **Line coverage:** 3 / 4 lines covered + """.trimIndent() - assertThat(result).isEqualTo(expectedResult) + assertThat(outputReportText).isEqualTo(expectedResult) } @Test - fun testRunCoverage_appTests_returnsCoverageData() { + fun testRunCoverage_appTestsMarkdownFormat_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -317,52 +347,30 @@ class RunCoverageTest { testSubpackage = "app/test/java/com/example" ) - val result = RunCoverage( + RunCoverage( "${tempFolder.root}", "app/main/java/com/example/TwoSum.kt", + ReportFormat.MARKDOWN, + sampleMDOutputPath, longCommandExecutor, scriptBgDispatcher ).execute() - val expectedResult = listOf( - CoverageReport.newBuilder() - .setBazelTestTarget("//app/test/java/com/example:TwoSumTest") - .setFilePath("app/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build() - ) + val outputReportText = File(sampleMDOutputPath).readText() + + val expectedResult = """ + ## Coverage Report + + - **Covered File:** app/main/java/com/example/TwoSum.kt + - **Coverage percentage:** 75.00% covered + - **Line coverage:** 3 / 4 lines covered + """.trimIndent() - assertThat(result).isEqualTo(expectedResult) + assertThat(outputReportText).isEqualTo(expectedResult) } @Test - fun testRunCoverage_localTests_returnsCoverageData() { + fun testRunCoverage_localTestsMarkdownFormat_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -410,52 +418,30 @@ class RunCoverageTest { testSubpackage = "app/test/java/com/example" ) - val result = RunCoverage( + RunCoverage( "${tempFolder.root}", "app/main/java/com/example/TwoSum.kt", + ReportFormat.MARKDOWN, + sampleMDOutputPath, longCommandExecutor, scriptBgDispatcher ).execute() - val expectedResult = listOf( - CoverageReport.newBuilder() - .setBazelTestTarget("//app/test/java/com/example:TwoSumLocalTest") - .setFilePath("app/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build() - ) + val outputReportText = File(sampleMDOutputPath).readText() - assertThat(result).isEqualTo(expectedResult) + val expectedResult = """ + ## Coverage Report + + - **Covered File:** app/main/java/com/example/TwoSum.kt + - **Coverage percentage:** 75.00% covered + - **Line coverage:** 3 / 4 lines covered + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) } @Test - fun testRunCoverage_sharedTests_returnsCoverageData() { + fun testRunCoverage_sharedTestsMarkdownFormat_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -503,52 +489,30 @@ class RunCoverageTest { testSubpackage = "app/sharedTest/java/com/example" ) - val result = RunCoverage( + RunCoverage( "${tempFolder.root}", "app/main/java/com/example/TwoSum.kt", + ReportFormat.MARKDOWN, + sampleMDOutputPath, longCommandExecutor, scriptBgDispatcher ).execute() - val expectedResult = listOf( - CoverageReport.newBuilder() - .setBazelTestTarget("//app/sharedTest/java/com/example:TwoSumTest") - .setFilePath("app/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build() - ) + val outputReportText = File(sampleMDOutputPath).readText() + + val expectedResult = """ + ## Coverage Report + + - **Covered File:** app/main/java/com/example/TwoSum.kt + - **Coverage percentage:** 75.00% covered + - **Line coverage:** 3 / 4 lines covered + """.trimIndent() - assertThat(result).isEqualTo(expectedResult) + assertThat(outputReportText).isEqualTo(expectedResult) } @Test - fun testRunCoverage_sharedAndLocalTests_returnsCoverageData() { + fun testRunCoverage_sharedAndLocalTestsMarkdownFormat_returnsCoverageData() { testBazelWorkspace.initEmptyWorkspace() val sourceContent = @@ -613,79 +577,1255 @@ class RunCoverageTest { subpackage = "app" ) - val result = RunCoverage( + RunCoverage( "${tempFolder.root}", "app/main/java/com/example/TwoSum.kt", + ReportFormat.MARKDOWN, + sampleMDOutputPath, + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val outputReportText = File(sampleMDOutputPath).readText() + + val expectedResult = """ + ## Coverage Report + + - **Covered File:** app/main/java/com/example/TwoSum.kt + - **Coverage percentage:** 75.00% covered + - **Line coverage:** 3 / 4 lines covered + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_sampleTestsHTMLFormat_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "coverage/main/java/com/example", + testSubpackage = "coverage/test/java/com/example" + ) + + RunCoverage( + "${tempFolder.root}", + "coverage/main/java/com/example/TwoSum.kt", + ReportFormat.HTML, + sampleHTMLOutputPath, longCommandExecutor, scriptBgDispatcher ).execute() - val expectedResult = listOf( - CoverageReport.newBuilder() - .setBazelTestTarget("//app/sharedTest/java/com/example:TwoSumTest") - .setFilePath("app/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build(), - CoverageReport.newBuilder() - .setBazelTestTarget("//app/test/java/com/example:TwoSumLocalTest") - .setFilePath("app/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(3) - .setCoverage(Coverage.NONE) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(7) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(8) - .setCoverage(Coverage.FULL) - .build() - ) - .addCoveredLine( - CoveredLine.newBuilder() - .setLineNumber(10) - .setCoverage(Coverage.FULL) - .build() - ) - .setLinesFound(4) - .setLinesHit(3) - .build() + val outputReportText = File(sampleHTMLOutputPath).readText() + + val expectedResult = """ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +
      +
    • Covered File: coverage/main/java/com/example/TwoSum.kt
    • +
    • Coverage percentage: 75.00% covered
    • +
    • Line coverage: 3 covered / 4 found
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1package com.example
    2
    3class TwoSum {
    4
    5 companion object {
    6 fun sumNumbers(a: Int, b: Int): Any {
    7 return if (a ==0 && b == 0) {
    8 "Both numbers are zero"
    9 } else {
    10 a + b
    11 }
    12 }
    13 }
    14}
    + + + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_scriptTestsHTMLFormat_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a == 0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "scripts/java/com/example", + testSubpackage = "scripts/javatests/com/example" ) - assertThat(result).isEqualTo(expectedResult) + RunCoverage( + "${tempFolder.root}", + sampleMDOutputPath, + ReportFormat.HTML, + "scripts/java/com/example/TwoSum.kt", + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val outputReportText = File(sampleMDOutputPath).readText() + + val expectedResult = """ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +
      +
    • Covered File: scripts/java/com/example/TwoSum.kt
    • +
    • Coverage percentage: 75.00% covered
    • +
    • Line coverage: 3 covered / 4 found
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1package com.example
    2
    3class TwoSum {
    4
    5 companion object {
    6 fun sumNumbers(a: Int, b: Int): Any {
    7 return if (a ==0 && b == 0) {
    8 "Both numbers are zero"
    9 } else {
    10 a + b
    11 }
    12 }
    13 }
    14}
    + + + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_appTestsHTMLFormat_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "app/main/java/com/example", + testSubpackage = "app/test/java/com/example" + ) + + RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + ReportFormat.HTML, + sampleHTMLOutputPath, + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val outputReportText = File(sampleHTMLOutputPath).readText() + + val expectedResult = """ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +
      +
    • Covered File: app/main/java/com/example/TwoSum.kt
    • +
    • Coverage percentage: 75.00% covered
    • +
    • Line coverage: 3 covered / 4 found
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1package com.example
    2
    3class TwoSum {
    4
    5 companion object {
    6 fun sumNumbers(a: Int, b: Int): Any {
    7 return if (a ==0 && b == 0) {
    8 "Both numbers are zero"
    9 } else {
    10 a + b
    11 }
    12 }
    13 }
    14}
    + + + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_localTestsHTMLFormat_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumLocalTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumLocalTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "app/main/java/com/example", + testSubpackage = "app/test/java/com/example" + ) + + RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + ReportFormat.HTML, + sampleHTMLOutputPath, + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val outputReportText = File(sampleHTMLOutputPath).readText() + + val expectedResult = """ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +
      +
    • Covered File: app/main/java/com/example/TwoSum.kt
    • +
    • Coverage percentage: 75.00% covered
    • +
    • Line coverage: 3 covered / 4 found
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1package com.example
    2
    3class TwoSum {
    4
    5 companion object {
    6 fun sumNumbers(a: Int, b: Int): Any {
    7 return if (a ==0 && b == 0) {
    8 "Both numbers are zero"
    9 } else {
    10 a + b
    11 }
    12 }
    13 }
    14}
    + + + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_sharedTestsHTMLFormat_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContent = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addSourceAndTestFileWithContent( + filename = "TwoSum", + testFilename = "TwoSumTest", + sourceContent = sourceContent, + testContent = testContent, + sourceSubpackage = "app/main/java/com/example", + testSubpackage = "app/sharedTest/java/com/example" + ) + + RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + ReportFormat.HTML, + sampleHTMLOutputPath, + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val outputReportText = File(sampleHTMLOutputPath).readText() + + val expectedResult = """ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +
      +
    • Covered File: app/main/java/com/example/TwoSum.kt
    • +
    • Coverage percentage: 75.00% covered
    • +
    • Line coverage: 3 covered / 4 found
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1package com.example
    2
    3class TwoSum {
    4
    5 companion object {
    6 fun sumNumbers(a: Int, b: Int): Any {
    7 return if (a ==0 && b == 0) {
    8 "Both numbers are zero"
    9 } else {
    10 a + b
    11 }
    12 }
    13 }
    14}
    + + + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) + } + + @Test + fun testRunCoverage_sharedAndLocalTestsHTMLFormat_returnsCoverageData() { + testBazelWorkspace.initEmptyWorkspace() + + val sourceContent = + """ + package com.example + + class TwoSum { + + companion object { + fun sumNumbers(a: Int, b: Int): Any { + return if (a ==0 && b == 0) { + "Both numbers are zero" + } else { + a + b + } + } + } + } + """.trimIndent() + + val testContentShared = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + val testContentLocal = + """ + package com.example + + import org.junit.Assert.assertEquals + import org.junit.Test + + class TwoSumLocalTest { + + @Test + fun testSumNumbers() { + assertEquals(TwoSum.sumNumbers(0, 1), 1) + assertEquals(TwoSum.sumNumbers(3, 4), 7) + assertEquals(TwoSum.sumNumbers(0, 0), "Both numbers are zero") + } + } + """.trimIndent() + + testBazelWorkspace.addMultiLevelSourceAndTestFileWithContent( + filename = "TwoSum", + sourceContent = sourceContent, + testContentShared = testContentShared, + testContentLocal = testContentLocal, + subpackage = "app" + ) + + RunCoverage( + "${tempFolder.root}", + "app/main/java/com/example/TwoSum.kt", + ReportFormat.HTML, + sampleHTMLOutputPath, + longCommandExecutor, + scriptBgDispatcher + ).execute() + + val outputReportText = File(sampleHTMLOutputPath).readText() + + val expectedResult = """ + + + + + + Coverage Report + + + +

    Coverage Report

    +
    +
      +
    • Covered File: app/main/java/com/example/TwoSum.kt
    • +
    • Coverage percentage: 75.00% covered
    • +
    • Line coverage: 3 covered / 4 found
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1package com.example
    2
    3class TwoSum {
    4
    5 companion object {
    6 fun sumNumbers(a: Int, b: Int): Any {
    7 return if (a ==0 && b == 0) {
    8 "Both numbers are zero"
    9 } else {
    10 a + b
    11 }
    12 }
    13 }
    14}
    + + + """.trimIndent() + + assertThat(outputReportText).isEqualTo(expectedResult) } private fun initializeCommandExecutorWithLongProcessWaitTime(): CommandExecutorImpl { From e1e2db3e51784e8569fc6f37bf99c70961327563 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 09:46:16 +0530 Subject: [PATCH 098/105] Fix Lint checks and added kdocs --- .../scripts/coverage/CoverageReporter.kt | 34 ++++++--- .../scripts/coverage/CoverageRunner.kt | 2 +- .../android/scripts/coverage/RunCoverage.kt | 15 +++- .../scripts/coverage/CoverageReporterTest.kt | 23 +++--- .../scripts/coverage/RunCoverageTest.kt | 72 +++++++++++-------- 5 files changed, 96 insertions(+), 50 deletions(-) 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 a172f8a599d..ed52ca98a86 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -1,9 +1,16 @@ package org.oppia.android.scripts.coverage -import org.oppia.android.scripts.proto.CoverageReport import org.oppia.android.scripts.proto.Coverage +import org.oppia.android.scripts.proto.CoverageReport import java.io.File +/** + * Class responsible for generating rich text coverage report. + * + * @param repoRoot the root directory of the repository + * @param coverageReportList the list of coverage data proto + * @param reportFormat the format in which the report will be generated + */ class CoverageReporter( private val repoRoot: String, private val coverageReportList: List, @@ -17,6 +24,13 @@ class CoverageReporter( val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0 val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 + /** + * Generates a rich text report for the analysed coverage data based on the specified format. + * It supports Markdown and HTML formats. + * + * @return a pair where the first value is the computed coverage ratio represented in [0, 1] + * and the second value is the generated report text + */ fun generateRichTextReport(): Pair { println("report format: $reportFormat") return when (reportFormat) { @@ -26,21 +40,23 @@ class CoverageReporter( } private fun generateMarkdownReport(): Pair { - val markdownContent = """ + val markdownContent = + """ ## Coverage Report - **Covered File:** $filePath - **Coverage percentage:** $formattedCoveragePercentage% covered - **Line coverage:** $totalLinesHit / $totalLinesFound lines covered - """.trimIndent() + """.trimIndent() println("\n$markdownContent") return Pair(computedCoverageRatio, markdownContent) } - fun generateHtmlReport(): Pair { - var htmlContent = """ + private fun generateHtmlReport(): Pair { + var htmlContent = + """ @@ -132,10 +148,11 @@ class CoverageReporter( - """.trimIndent() + """.trimIndent() val fileContent = File(repoRoot, filePath).readLines() - val coverageMap = coverageReportList.firstOrNull()?.coveredLineList?.associateBy { it.lineNumber } + val coverageMap = coverageReportList + .firstOrNull()?.coveredLineList?.associateBy { it.lineNumber } fileContent.forEachIndexed { index, line -> val lineNumber = index + 1 @@ -149,7 +166,7 @@ class CoverageReporter( ${lineNumber.toString().padStart(4, ' ')} $line - """.trimIndent() + """.trimIndent() } htmlContent += """ @@ -172,6 +189,7 @@ class CoverageReporter( } } +/** Represents the different types of formats available to generate code coverage reports. */ enum class ReportFormat { MARKDOWN, HTML 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 92e095e5a18..e1ff9cdb221 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageRunner.kt @@ -60,7 +60,7 @@ class CoverageRunner( val sfStartIdx = coverageData.indexOfFirst { it.startsWith("SF:") && it.substringAfter("SF:").substringAfterLast("/") == extractedFileName } - if (sfStartIdx == -1) throw IllegalArgumentException("File not found, bazel: $bazelTestTarget coverage data: $coverageData, extracted: $extractedFileName") + if (sfStartIdx == -1) throw IllegalArgumentException("File not found") val eofIdx = coverageData.subList(sfStartIdx, coverageData.size).indexOfFirst { it.startsWith("end_of_record") } 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 df5e9a23195..bf1ad4ae0c3 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -54,7 +54,14 @@ fun main(vararg args: String) { scriptBgDispatcher, processTimeout = processTimeout, processTimeoutUnit = TimeUnit.MINUTES ) - RunCoverage(repoRoot, filePath, reportFormat, reportOutputPath, commandExecutor, scriptBgDispatcher).execute() + RunCoverage( + repoRoot, + filePath, + reportFormat, + reportOutputPath, + commandExecutor, + scriptBgDispatcher + ).execute() } } @@ -163,7 +170,11 @@ private fun findTestFile(repoRoot: String, filePath: String): List { .map { it.relativeTo(repoRootFile).path } } -private fun getReportOutputPath(repoRoot: String, filePath: String, reportFormat: ReportFormat): String { +private fun getReportOutputPath( + repoRoot: String, + filePath: String, + reportFormat: ReportFormat +): String { val fileWithoutExtension = filePath.substringBeforeLast(".") val defaultFilename = when (reportFormat) { ReportFormat.HTML -> "coverage.html" diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt index e7e4a075416..f3820d88f60 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt @@ -1,10 +1,11 @@ package org.oppia.android.scripts.coverage import com.google.common.truth.Truth.assertThat -import org.junit.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.proto.CoverageReport -import java.io.File class CoverageReporterTest { @field:[Rule JvmField] val tempFolder = TemporaryFolder() @@ -91,13 +92,14 @@ class CoverageReporterTest { ) val (_, reportText) = reporter.generateRichTextReport() - val expectedMarkdown = """ + val expectedMarkdown = + """ ## Coverage Report - **Covered File:** SampleFile.kt - **Coverage percentage:** 80.00% covered - **Line coverage:** 8 / 10 lines covered - """.trimIndent() + """.trimIndent() assertThat(reportText).isEqualTo(expectedMarkdown) } @@ -105,7 +107,8 @@ class CoverageReporterTest { @Test fun testCoverageReporter_htmlReportText_check() { val sourceFile = tempFolder.newFile("SampleFile.kt") - sourceFile.writeText(""" + sourceFile.writeText( + """ fun main() { println("Hello, World!") val x = 10 @@ -116,16 +119,18 @@ class CoverageReporterTest { println(i) } } - """.trimIndent()) + """.trimIndent() + ) reporter = CoverageReporter( tempFolder.root.absolutePath, listOf(validCoverageReport), ReportFormat.HTML ) - val (_, reportText) = reporter.generateHtmlReport() + val (_, reportText) = reporter.generateRichTextReport() - val expectedHTML = """ + val expectedHTML = + """ @@ -250,7 +255,7 @@ class CoverageReporterTest { - """.trimIndent() + """.trimIndent() assertThat(reportText).isEqualTo(expectedHTML) } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 083d09148a2..ac20d2b52b8 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -8,9 +8,6 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.scripts.proto.Coverage -import org.oppia.android.scripts.proto.CoverageReport -import org.oppia.android.scripts.proto.CoveredLine import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import java.io.ByteArrayOutputStream @@ -84,7 +81,9 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - assertThat(result).isEqualTo("This file is exempted from having a test file; skipping coverage check.") + assertThat(result).isEqualTo( + "This file is exempted from having a test file; skipping coverage check." + ) } @Test @@ -145,13 +144,14 @@ class RunCoverageTest { "${tempFolder.root}/coverage_reports/coverage/main/java/com/example/TwoSum/coverage.md" ).readText() - val expectedResult = """ + val expectedResult = + """ ## Coverage Report - **Covered File:** coverage/main/java/com/example/TwoSum.kt - **Coverage percentage:** 75.00% covered - **Line coverage:** 3 / 4 lines covered - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -216,13 +216,14 @@ class RunCoverageTest { val outputReportText = File(sampleMDOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ ## Coverage Report - **Covered File:** coverage/main/java/com/example/TwoSum.kt - **Coverage percentage:** 75.00% covered - **Line coverage:** 3 / 4 lines covered - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -287,13 +288,14 @@ class RunCoverageTest { val outputReportText = File(sampleMDOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ ## Coverage Report - **Covered File:** scripts/java/com/example/TwoSum.kt - **Coverage percentage:** 75.00% covered - **Line coverage:** 3 / 4 lines covered - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -358,13 +360,14 @@ class RunCoverageTest { val outputReportText = File(sampleMDOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ ## Coverage Report - **Covered File:** app/main/java/com/example/TwoSum.kt - **Coverage percentage:** 75.00% covered - **Line coverage:** 3 / 4 lines covered - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -429,13 +432,14 @@ class RunCoverageTest { val outputReportText = File(sampleMDOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ ## Coverage Report - **Covered File:** app/main/java/com/example/TwoSum.kt - **Coverage percentage:** 75.00% covered - **Line coverage:** 3 / 4 lines covered - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -500,13 +504,14 @@ class RunCoverageTest { val outputReportText = File(sampleMDOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ ## Coverage Report - **Covered File:** app/main/java/com/example/TwoSum.kt - **Coverage percentage:** 75.00% covered - **Line coverage:** 3 / 4 lines covered - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -588,13 +593,14 @@ class RunCoverageTest { val outputReportText = File(sampleMDOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ ## Coverage Report - **Covered File:** app/main/java/com/example/TwoSum.kt - **Coverage percentage:** 75.00% covered - **Line coverage:** 3 / 4 lines covered - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -659,7 +665,8 @@ class RunCoverageTest { val outputReportText = File(sampleHTMLOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ @@ -796,7 +803,7 @@ class RunCoverageTest { - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -861,7 +868,8 @@ class RunCoverageTest { val outputReportText = File(sampleMDOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ @@ -998,7 +1006,7 @@ class RunCoverageTest { - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -1063,7 +1071,8 @@ class RunCoverageTest { val outputReportText = File(sampleHTMLOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ @@ -1200,7 +1209,7 @@ class RunCoverageTest { - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -1265,7 +1274,8 @@ class RunCoverageTest { val outputReportText = File(sampleHTMLOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ @@ -1402,7 +1412,7 @@ class RunCoverageTest { - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -1467,7 +1477,8 @@ class RunCoverageTest { val outputReportText = File(sampleHTMLOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ @@ -1604,7 +1615,7 @@ class RunCoverageTest { - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } @@ -1686,7 +1697,8 @@ class RunCoverageTest { val outputReportText = File(sampleHTMLOutputPath).readText() - val expectedResult = """ + val expectedResult = + """ @@ -1823,7 +1835,7 @@ class RunCoverageTest { - """.trimIndent() + """.trimIndent() assertThat(outputReportText).isEqualTo(expectedResult) } From 821725f39e5a0734aa06fa9d1422a292e341daf3 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 10:24:48 +0530 Subject: [PATCH 099/105] Fixed failing tests and fixed kdoc checks --- .../scripts/coverage/CoverageReporter.kt | 12 ++++--- .../scripts/coverage/CoverageReporterTest.kt | 34 ------------------- .../scripts/coverage/RunCoverageTest.kt | 8 ++--- 3 files changed, 11 insertions(+), 43 deletions(-) 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 ed52ca98a86..acfe6eaa584 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -16,13 +16,13 @@ class CoverageReporter( private val coverageReportList: List, private val reportFormat: ReportFormat, ) { - val computedCoverageRatio = computeCoverageRatio() - val formattedCoveragePercentage = "%.2f".format(computedCoverageRatio * 100) + private val computedCoverageRatio = computeCoverageRatio() + private val formattedCoveragePercentage = "%.2f".format(computedCoverageRatio * 100) - val filePath = coverageReportList.firstOrNull()?.filePath ?: "Unknown" + private val filePath = coverageReportList.firstOrNull()?.filePath ?: "Unknown" - val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0 - val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 + private val totalLinesFound = coverageReportList.getOrNull(0)?.linesFound ?: 0 + private val totalLinesHit = coverageReportList.getOrNull(0)?.linesHit ?: 0 /** * Generates a rich text report for the analysed coverage data based on the specified format. @@ -191,6 +191,8 @@ class CoverageReporter( /** 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. */ MARKDOWN, + /** Indicates that the report should be formatted in .html format. */ HTML } diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt index f3820d88f60..39a3490da66 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt @@ -23,40 +23,6 @@ class CoverageReporterTest { .build() } - @Test - fun testCoverageReporter_validData_initializesCorrectly() { - val expectedTotalLinesFound = 10 - val expectedTotalLinesHit = 8 - val expectedFilePath = "SampleFile.kt" - val expectedFormattedCoveragePercentage = "80.00" - reporter = CoverageReporter( - tempFolder.root.absolutePath, - listOf(validCoverageReport), - ReportFormat.MARKDOWN - ) - assertThat(expectedFilePath).isEqualTo(reporter.filePath) - assertThat(expectedTotalLinesFound).isEqualTo(reporter.totalLinesFound) - assertThat(expectedTotalLinesHit).isEqualTo(reporter.totalLinesHit) - assertThat(expectedFormattedCoveragePercentage).isEqualTo(reporter.formattedCoveragePercentage) - } - - @Test - fun testCoverageReporter_emptyCoverageReportList_initializesWithDefaults() { - val expectedTotalLinesFound = 0 - val expectedTotalLinesHit = 0 - val expectedFormattedCoveragePercentage = "0.00" - val unknownFilePath = "Unknown" - reporter = CoverageReporter( - tempFolder.root.absolutePath, - emptyCoverageReportList, - ReportFormat.MARKDOWN - ) - assertThat(unknownFilePath).isEqualTo(reporter.filePath) - assertThat(expectedTotalLinesFound).isEqualTo(reporter.totalLinesFound) - assertThat(expectedTotalLinesHit).isEqualTo(reporter.totalLinesHit) - assertThat(expectedFormattedCoveragePercentage).isEqualTo(reporter.formattedCoveragePercentage) - } - @Test fun testCoverageReporter_validData_generatesCorrectCoverageRatio() { reporter = CoverageReporter( diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index ac20d2b52b8..4821acbab5a 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -279,9 +279,9 @@ class RunCoverageTest { RunCoverage( "${tempFolder.root}", - sampleMDOutputPath, - ReportFormat.MARKDOWN, "scripts/java/com/example/TwoSum.kt", + ReportFormat.MARKDOWN, + sampleMDOutputPath, longCommandExecutor, scriptBgDispatcher ).execute() @@ -859,9 +859,9 @@ class RunCoverageTest { RunCoverage( "${tempFolder.root}", - sampleMDOutputPath, - ReportFormat.HTML, "scripts/java/com/example/TwoSum.kt", + ReportFormat.HTML, + sampleHTMLOutputPath, longCommandExecutor, scriptBgDispatcher ).execute() From 2b97b513a82395b87f8819afa2b5d44c5c07fd64 Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 11:05:07 +0530 Subject: [PATCH 100/105] Fix test cases that failed due to wrong output path --- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 4821acbab5a..7bc3995a586 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -866,7 +866,7 @@ class RunCoverageTest { scriptBgDispatcher ).execute() - val outputReportText = File(sampleMDOutputPath).readText() + val outputReportText = File(sampleHTMLOutputPath).readText() val expectedResult = """ From d6fb59999567c2070249597134d748e5fe96762d Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 11:42:49 +0530 Subject: [PATCH 101/105] Fix test case that had mis-matched outputs --- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 7bc3995a586..a114232bfd3 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -980,7 +980,7 @@ class RunCoverageTest { fun sumNumbers(a: Int, b: Int): Any { 7 - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { 8 "Both numbers are zero" From 032abcda4fb2dbab59c346cdb59c208140827e2a Mon Sep 17 00:00:00 2001 From: Rd Date: Thu, 27 Jun 2024 14:48:44 +0530 Subject: [PATCH 102/105] Fix Lint checks on unused imports --- .../org/oppia/android/scripts/coverage/RunCoverageTest.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 3bb5e7d655d..a114232bfd3 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -8,9 +8,6 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import org.oppia.android.scripts.common.CommandExecutorImpl import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher -import org.oppia.android.scripts.proto.Coverage -import org.oppia.android.scripts.proto.CoverageReport -import org.oppia.android.scripts.proto.CoveredLine import org.oppia.android.scripts.testing.TestBazelWorkspace import org.oppia.android.testing.assertThrows import java.io.ByteArrayOutputStream From f080cba95c010f4aca017b3ae2367b3e5a30ee7e Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 28 Jun 2024 08:25:58 +0530 Subject: [PATCH 103/105] Refactor to ignore case formats and updated the html styling with tests --- .../scripts/coverage/CoverageReporter.kt | 78 +++-- .../android/scripts/coverage/RunCoverage.kt | 10 +- .../scripts/coverage/CoverageReporterTest.kt | 270 ++++++++++-------- .../scripts/coverage/CoverageRunnerTest.kt | 2 +- .../scripts/coverage/RunCoverageTest.kt | 32 +-- 5 files changed, 235 insertions(+), 157 deletions(-) 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 acfe6eaa584..70c0cf9baab 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/CoverageReporter.kt @@ -76,14 +76,18 @@ class CoverageReporter( } th, td { padding: 8px; + margin-left: 20px; text-align: left; border-bottom: 1px solid #fdfdfd; } .line-number-col { - width: 5%; + width: 2%; + } + .line-number-row { + border-right: 1px dashed #000000 } .source-code-col { - width: 95%; + width: 98%; } .covered-line, .not-covered-line, .uncovered-line { white-space: pre-wrap; @@ -100,26 +104,52 @@ class CoverageReporter( background-color: #ffcdd2; /* Light red */ } .uncovered-line { - background-color: #fafafa; /* Half white */ + background-color: #f1f1f1; /* light gray */ } .coverage-summary { - margin-bottom: 20px; + margin-bottom: 20px; } h2 { - text-align: center; + text-align: center; } ul { - list-style-type: none; - padding: 0; - text-align: center; + list-style-type: none; + padding: 0; + text-align: center; } .summary-box { - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 8px; - padding: 10px; - margin-bottom: 20px; - text-align: center; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 8px; + padding: 10px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ } @media screen and (max-width: 768px) { body { @@ -134,11 +164,19 @@ class CoverageReporter(

    Coverage Report

    -
      -
    • Covered File: $filePath
    • -
    • Coverage percentage: $formattedCoveragePercentage% covered
    • -
    • Line coverage: $totalLinesHit covered / $totalLinesFound found
    • -
    +
    + Covered File: $filePath
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: $formattedCoveragePercentage%
    +
    Line coverage: $totalLinesHit / $totalLinesFound covered
    +
    @@ -163,7 +201,7 @@ class CoverageReporter( } htmlContent += """ - + """.trimIndent() 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 bf1ad4ae0c3..8aa7c5ba83e 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -33,12 +33,14 @@ import java.util.concurrent.TimeUnit fun main(vararg args: String) { val repoRoot = args[0] val filePath = args[1] - val reportFormat = when (args.getOrNull(2)) { - "HTML" -> ReportFormat.HTML - "MARKDOWN", null -> ReportFormat.MARKDOWN - else -> throw IllegalArgumentException("Unsupported report format: ${args[2]}") + val format = args.getOrNull(2) + val reportFormat = when { + format.equals("HTML", ignoreCase = true) -> ReportFormat.HTML + format.equals("MARKDOWN", ignoreCase = true) || format == null -> ReportFormat.MARKDOWN + else -> throw IllegalArgumentException("Unsupported report format: $format") } + val reportOutputPath = getReportOutputPath(repoRoot, filePath, reportFormat) if (!File(repoRoot, filePath).exists()) { diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt index 39a3490da66..67db3ebb1a4 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageReporterTest.kt @@ -50,7 +50,7 @@ class CoverageReporterTest { } @Test - fun testCoverageReporter_markdownReportText_check() { + fun testCoverageReporter_generateMarkdownReport_hasCorrectContentAndFormatting() { reporter = CoverageReporter( tempFolder.root.absolutePath, listOf(validCoverageReport), @@ -71,7 +71,7 @@ class CoverageReporterTest { } @Test - fun testCoverageReporter_htmlReportText_check() { + fun testCoverageReporter_generateHTMLReport_hasCorrectContentAndFormatting() { val sourceFile = tempFolder.newFile("SampleFile.kt") sourceFile.writeText( """ @@ -97,130 +97,168 @@ class CoverageReporterTest { val expectedHTML = """ - - - - - - Coverage Report - - - -

    Coverage Report

    -
    -
      -
    • Covered File: SampleFile.kt
    • -
    • Coverage percentage: 80.00% covered
    • -
    • Line coverage: 8 covered / 10 found
    • -
    -
    -
    ${lineNumber.toString().padStart(4, ' ')}${lineNumber.toString().padStart(4, ' ')} $line
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Line NoSource Code
    1 fun main() {
    2 println("Hello, World!")
    3 val x = 10
    4 val y = 20
    5 val sum = x + y
    6 println("Sum: 30")
    7 for (i in 1..10) {
    8 println(i)
    9 }
    10}
    - - + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ + } + @media screen and (max-width: 768px) { + body { + padding: 10px; + } + table { + width: auto; + } + } + + + +

    Coverage Report

    +
    +
    + Covered File: SampleFile.kt
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: 80.00%
    +
    Line coverage: 8 / 10 covered
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Line NoSource Code
    1 fun main() {
    2 println("Hello, World!")
    3 val x = 10
    4 val y = 20
    5 val sum = x + y
    6 println("Sum: 30")
    7 for (i in 1..10) {
    8 println(i)
    9 }
    10}
    + + """.trimIndent() assertThat(reportText).isEqualTo(expectedHTML) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 7d795703912..82d81424bbb 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -76,7 +76,7 @@ class CoverageRunnerTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index a114232bfd3..9e5b8b9d04f 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -98,7 +98,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -168,7 +168,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -312,7 +312,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -384,7 +384,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -456,7 +456,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -528,7 +528,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -617,7 +617,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -777,7 +777,7 @@ class RunCoverageTest { fun sumNumbers(a: Int, b: Int): Any { 7 - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { 8 "Both numbers are zero" @@ -1023,7 +1023,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -1183,7 +1183,7 @@ class RunCoverageTest { fun sumNumbers(a: Int, b: Int): Any { 7 - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { 8 "Both numbers are zero" @@ -1226,7 +1226,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -1386,7 +1386,7 @@ class RunCoverageTest { fun sumNumbers(a: Int, b: Int): Any { 7 - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { 8 "Both numbers are zero" @@ -1429,7 +1429,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -1589,7 +1589,7 @@ class RunCoverageTest { fun sumNumbers(a: Int, b: Int): Any { 7 - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { 8 "Both numbers are zero" @@ -1632,7 +1632,7 @@ class RunCoverageTest { companion object { fun sumNumbers(a: Int, b: Int): Any { - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { "Both numbers are zero" } else { a + b @@ -1809,7 +1809,7 @@ class RunCoverageTest { fun sumNumbers(a: Int, b: Int): Any { 7 - return if (a ==0 && b == 0) { + return if (a == 0 && b == 0) { 8 "Both numbers are zero" From a2273ec4eb7574872d534f7fe03dca3acae05b7a Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 28 Jun 2024 08:52:04 +0530 Subject: [PATCH 104/105] Updated RunCoverageTest with update to html stylings --- .../android/scripts/coverage/RunCoverage.kt | 1 - .../scripts/coverage/RunCoverageTest.kt | 624 ++++++++++++------ 2 files changed, 426 insertions(+), 199 deletions(-) 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 8aa7c5ba83e..bf65548aecc 100644 --- a/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt +++ b/scripts/src/java/org/oppia/android/scripts/coverage/RunCoverage.kt @@ -40,7 +40,6 @@ fun main(vararg args: String) { else -> throw IllegalArgumentException("Unsupported report format: $format") } - val reportOutputPath = getReportOutputPath(repoRoot, filePath, reportFormat) if (!File(repoRoot, filePath).exists()) { diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt index 9e5b8b9d04f..b00415fcc31 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/RunCoverageTest.kt @@ -686,14 +686,18 @@ class RunCoverageTest { } th, td { padding: 8px; + margin-left: 20px; text-align: left; border-bottom: 1px solid #fdfdfd; } .line-number-col { - width: 5%; + width: 2%; + } + .line-number-row { + border-right: 1px dashed #000000 } .source-code-col { - width: 95%; + width: 98%; } .covered-line, .not-covered-line, .uncovered-line { white-space: pre-wrap; @@ -710,26 +714,52 @@ class RunCoverageTest { background-color: #ffcdd2; /* Light red */ } .uncovered-line { - background-color: #fafafa; /* Half white */ + background-color: #f1f1f1; /* light gray */ } .coverage-summary { - margin-bottom: 20px; + margin-bottom: 20px; } h2 { - text-align: center; + text-align: center; } ul { - list-style-type: none; - padding: 0; - text-align: center; + list-style-type: none; + padding: 0; + text-align: center; } .summary-box { - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 8px; - padding: 10px; - margin-bottom: 20px; - text-align: center; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 8px; + padding: 10px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ } @media screen and (max-width: 768px) { body { @@ -744,11 +774,19 @@ class RunCoverageTest {

    Coverage Report

    -
      -
    • Covered File: coverage/main/java/com/example/TwoSum.kt
    • -
    • Coverage percentage: 75.00% covered
    • -
    • Line coverage: 3 covered / 4 found
    • -
    +
    + Covered File: coverage/main/java/com/example/TwoSum.kt
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: 75.00%
    +
    Line coverage: 3 / 4 covered
    +
    @@ -758,46 +796,46 @@ class RunCoverageTest { - + - + - + - + - + - + - + - + - + - + - + - + - + - +
    1 1 package com.example
    2 2
    3 3 class TwoSum {
    4 4
    5 5 companion object {
    6 6 fun sumNumbers(a: Int, b: Int): Any {
    7 7 return if (a == 0 && b == 0) {
    8 8 "Both numbers are zero"
    9 9 } else {
    10 10 a + b
    11 11 }
    12 12 }
    13 13 }
    14 14 }
    @@ -889,14 +927,18 @@ class RunCoverageTest { } th, td { padding: 8px; + margin-left: 20px; text-align: left; border-bottom: 1px solid #fdfdfd; } .line-number-col { - width: 5%; + width: 2%; + } + .line-number-row { + border-right: 1px dashed #000000 } .source-code-col { - width: 95%; + width: 98%; } .covered-line, .not-covered-line, .uncovered-line { white-space: pre-wrap; @@ -913,26 +955,52 @@ class RunCoverageTest { background-color: #ffcdd2; /* Light red */ } .uncovered-line { - background-color: #fafafa; /* Half white */ + background-color: #f1f1f1; /* light gray */ } .coverage-summary { - margin-bottom: 20px; + margin-bottom: 20px; } h2 { - text-align: center; + text-align: center; } ul { - list-style-type: none; - padding: 0; - text-align: center; + list-style-type: none; + padding: 0; + text-align: center; } .summary-box { - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 8px; - padding: 10px; - margin-bottom: 20px; - text-align: center; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 8px; + padding: 10px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ } @media screen and (max-width: 768px) { body { @@ -947,11 +1015,19 @@ class RunCoverageTest {

    Coverage Report

    -
      -
    • Covered File: scripts/java/com/example/TwoSum.kt
    • -
    • Coverage percentage: 75.00% covered
    • -
    • Line coverage: 3 covered / 4 found
    • -
    +
    + Covered File: scripts/java/com/example/TwoSum.kt
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: 75.00%
    +
    Line coverage: 3 / 4 covered
    +
    @@ -961,46 +1037,46 @@ class RunCoverageTest { - + - + - + - + - + - + - + - + - + - + - + - + - + - +
    1 1 package com.example
    2 2
    3 3 class TwoSum {
    4 4
    5 5 companion object {
    6 6 fun sumNumbers(a: Int, b: Int): Any {
    7 7 return if (a == 0 && b == 0) {
    8 8 "Both numbers are zero"
    9 9 } else {
    10 10 a + b
    11 11 }
    12 12 }
    13 13 }
    14 14 }
    @@ -1092,14 +1168,18 @@ class RunCoverageTest { } th, td { padding: 8px; + margin-left: 20px; text-align: left; border-bottom: 1px solid #fdfdfd; } .line-number-col { - width: 5%; + width: 2%; + } + .line-number-row { + border-right: 1px dashed #000000 } .source-code-col { - width: 95%; + width: 98%; } .covered-line, .not-covered-line, .uncovered-line { white-space: pre-wrap; @@ -1116,26 +1196,52 @@ class RunCoverageTest { background-color: #ffcdd2; /* Light red */ } .uncovered-line { - background-color: #fafafa; /* Half white */ + background-color: #f1f1f1; /* light gray */ } .coverage-summary { - margin-bottom: 20px; + margin-bottom: 20px; } h2 { - text-align: center; + text-align: center; } ul { - list-style-type: none; - padding: 0; - text-align: center; + list-style-type: none; + padding: 0; + text-align: center; } .summary-box { - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 8px; - padding: 10px; - margin-bottom: 20px; - text-align: center; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 8px; + padding: 10px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ } @media screen and (max-width: 768px) { body { @@ -1150,11 +1256,19 @@ class RunCoverageTest {

    Coverage Report

    -
      -
    • Covered File: app/main/java/com/example/TwoSum.kt
    • -
    • Coverage percentage: 75.00% covered
    • -
    • Line coverage: 3 covered / 4 found
    • -
    +
    + Covered File: app/main/java/com/example/TwoSum.kt
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: 75.00%
    +
    Line coverage: 3 / 4 covered
    +
    @@ -1164,46 +1278,46 @@ class RunCoverageTest { - + - + - + - + - + - + - + - + - + - + - + - + - + - +
    1 1 package com.example
    2 2
    3 3 class TwoSum {
    4 4
    5 5 companion object {
    6 6 fun sumNumbers(a: Int, b: Int): Any {
    7 7 return if (a == 0 && b == 0) {
    8 8 "Both numbers are zero"
    9 9 } else {
    10 10 a + b
    11 11 }
    12 12 }
    13 13 }
    14 14 }
    @@ -1295,14 +1409,18 @@ class RunCoverageTest { } th, td { padding: 8px; + margin-left: 20px; text-align: left; border-bottom: 1px solid #fdfdfd; } .line-number-col { - width: 5%; + width: 2%; + } + .line-number-row { + border-right: 1px dashed #000000 } .source-code-col { - width: 95%; + width: 98%; } .covered-line, .not-covered-line, .uncovered-line { white-space: pre-wrap; @@ -1319,26 +1437,52 @@ class RunCoverageTest { background-color: #ffcdd2; /* Light red */ } .uncovered-line { - background-color: #fafafa; /* Half white */ + background-color: #f1f1f1; /* light gray */ } .coverage-summary { - margin-bottom: 20px; + margin-bottom: 20px; } h2 { - text-align: center; + text-align: center; } ul { - list-style-type: none; - padding: 0; - text-align: center; + list-style-type: none; + padding: 0; + text-align: center; } .summary-box { - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 8px; - padding: 10px; - margin-bottom: 20px; - text-align: center; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 8px; + padding: 10px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ } @media screen and (max-width: 768px) { body { @@ -1353,11 +1497,19 @@ class RunCoverageTest {

    Coverage Report

    -
      -
    • Covered File: app/main/java/com/example/TwoSum.kt
    • -
    • Coverage percentage: 75.00% covered
    • -
    • Line coverage: 3 covered / 4 found
    • -
    +
    + Covered File: app/main/java/com/example/TwoSum.kt
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: 75.00%
    +
    Line coverage: 3 / 4 covered
    +
    @@ -1367,46 +1519,46 @@ class RunCoverageTest { - + - + - + - + - + - + - + - + - + - + - + - + - + - +
    1 1 package com.example
    2 2
    3 3 class TwoSum {
    4 4
    5 5 companion object {
    6 6 fun sumNumbers(a: Int, b: Int): Any {
    7 7 return if (a == 0 && b == 0) {
    8 8 "Both numbers are zero"
    9 9 } else {
    10 10 a + b
    11 11 }
    12 12 }
    13 13 }
    14 14 }
    @@ -1498,14 +1650,18 @@ class RunCoverageTest { } th, td { padding: 8px; + margin-left: 20px; text-align: left; border-bottom: 1px solid #fdfdfd; } .line-number-col { - width: 5%; + width: 2%; + } + .line-number-row { + border-right: 1px dashed #000000 } .source-code-col { - width: 95%; + width: 98%; } .covered-line, .not-covered-line, .uncovered-line { white-space: pre-wrap; @@ -1522,26 +1678,52 @@ class RunCoverageTest { background-color: #ffcdd2; /* Light red */ } .uncovered-line { - background-color: #fafafa; /* Half white */ + background-color: #f1f1f1; /* light gray */ } .coverage-summary { - margin-bottom: 20px; + margin-bottom: 20px; } h2 { - text-align: center; + text-align: center; } ul { - list-style-type: none; - padding: 0; - text-align: center; + list-style-type: none; + padding: 0; + text-align: center; } .summary-box { - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 8px; - padding: 10px; - margin-bottom: 20px; - text-align: center; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 8px; + padding: 10px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ } @media screen and (max-width: 768px) { body { @@ -1556,11 +1738,19 @@ class RunCoverageTest {

    Coverage Report

    -
      -
    • Covered File: app/main/java/com/example/TwoSum.kt
    • -
    • Coverage percentage: 75.00% covered
    • -
    • Line coverage: 3 covered / 4 found
    • -
    +
    + Covered File: app/main/java/com/example/TwoSum.kt
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: 75.00%
    +
    Line coverage: 3 / 4 covered
    +
    @@ -1570,46 +1760,46 @@ class RunCoverageTest { - + - + - + - + - + - + - + - + - + - + - + - + - + - +
    1 1 package com.example
    2 2
    3 3 class TwoSum {
    4 4
    5 5 companion object {
    6 6 fun sumNumbers(a: Int, b: Int): Any {
    7 7 return if (a == 0 && b == 0) {
    8 8 "Both numbers are zero"
    9 9 } else {
    10 10 a + b
    11 11 }
    12 12 }
    13 13 }
    14 14 }
    @@ -1718,14 +1908,18 @@ class RunCoverageTest { } th, td { padding: 8px; + margin-left: 20px; text-align: left; border-bottom: 1px solid #fdfdfd; } .line-number-col { - width: 5%; + width: 2%; + } + .line-number-row { + border-right: 1px dashed #000000 } .source-code-col { - width: 95%; + width: 98%; } .covered-line, .not-covered-line, .uncovered-line { white-space: pre-wrap; @@ -1742,26 +1936,52 @@ class RunCoverageTest { background-color: #ffcdd2; /* Light red */ } .uncovered-line { - background-color: #fafafa; /* Half white */ + background-color: #f1f1f1; /* light gray */ } .coverage-summary { - margin-bottom: 20px; + margin-bottom: 20px; } h2 { - text-align: center; + text-align: center; } ul { - list-style-type: none; - padding: 0; - text-align: center; + list-style-type: none; + padding: 0; + text-align: center; } .summary-box { - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 8px; - padding: 10px; - margin-bottom: 20px; - text-align: center; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 8px; + padding: 10px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + } + .summary-left { + text-align: left; + } + .summary-right { + text-align: right; + } + .legend { + display: flex; + align-items: center; + } + .legend-item { + width: 20px; + height: 10px; + margin-right: 5px; + border-radius: 2px; + display: inline-block; + } + .legend .covered { + background-color: #c8e6c9; /* Light green */ + } + .legend .not-covered { + margin-left: 4px; + background-color: #ffcdd2; /* Light red */ } @media screen and (max-width: 768px) { body { @@ -1776,11 +1996,19 @@ class RunCoverageTest {

    Coverage Report

    -
      -
    • Covered File: app/main/java/com/example/TwoSum.kt
    • -
    • Coverage percentage: 75.00% covered
    • -
    • Line coverage: 3 covered / 4 found
    • -
    +
    + Covered File: app/main/java/com/example/TwoSum.kt
    +
    +
    + Covered +
    + Uncovered +
    +
    +
    +
    Coverage percentage: 75.00%
    +
    Line coverage: 3 / 4 covered
    +
    @@ -1790,46 +2018,46 @@ class RunCoverageTest { - + - + - + - + - + - + - + - + - + - + - + - + - + - +
    1 1 package com.example
    2 2
    3 3 class TwoSum {
    4 4
    5 5 companion object {
    6 6 fun sumNumbers(a: Int, b: Int): Any {
    7 7 return if (a == 0 && b == 0) {
    8 8 "Both numbers are zero"
    9 9 } else {
    10 10 a + b
    11 11 }
    12 12 }
    13 13 }
    14 14 }
    From 5d0bb7e9fd7aaae3d8edf8fd87952da78d8f4d2a Mon Sep 17 00:00:00 2001 From: Rd Date: Fri, 28 Jun 2024 09:21:26 +0530 Subject: [PATCH 105/105] Fixed failing test case that failed due to changes in file and unchanged sha value --- .../org/oppia/android/scripts/coverage/CoverageRunnerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt index 82d81424bbb..68fd8e7e3e6 100644 --- a/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt +++ b/scripts/src/javatests/org/oppia/android/scripts/coverage/CoverageRunnerTest.kt @@ -122,7 +122,7 @@ class CoverageRunnerTest { val expectedResult = CoverageReport.newBuilder() .setBazelTestTarget("//coverage/test/java/com/example:TwoSumTest") .setFilePath("coverage/main/java/com/example/TwoSum.kt") - .setFileSha1Hash("f6fb075e115775f6729615a79f0e7e34fe9735b5") + .setFileSha1Hash("1020b8f405555b3f4537fd07b912d3fb9ffa3354") .addCoveredLine( CoveredLine.newBuilder() .setLineNumber(3)