From 6ec35a75d2dfcd22439f0e722820332b1552ae02 Mon Sep 17 00:00:00 2001 From: Rd Date: Tue, 4 Jun 2024 14:11:09 +0530 Subject: [PATCH 01/87] 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 02/87] 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 03/87] 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 04/87] 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 05/87] 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 06/87] 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 07/87] 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 08/87] 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 09/87] 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 10/87] 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 11/87] 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 12/87] 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 13/87] 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 14/87] 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 15/87] 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 16/87] 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 17/87] 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 18/87] 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 19/87] 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 20/87] 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 21/87] 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 22/87] 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 23/87] 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 24/87] 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 25/87] 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 26/87] 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 27/87] 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 28/87] 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 29/87] 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 30/87] 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 31/87] 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 32/87] 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 33/87] 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 34/87] 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 35/87] 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 36/87] 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 37/87] 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 38/87] 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 39/87] 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 40/87] 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 41/87] 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 42/87] 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 43/87] 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 44/87] 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 45/87] 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 46/87] 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 47/87] 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 48/87] 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 49/87] 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 50/87] 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 51/87] 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 52/87] 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 53/87] 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 54/87] 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 55/87] 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 56/87] 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 57/87] 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 58/87] 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 59/87] 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 60/87] 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 61/87] 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 62/87] 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 63/87] 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 64/87] 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 65/87] 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 66/87] 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 67/87] 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 68/87] 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 69/87] 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 70/87] 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 1b9426d196a1d790fc31e70721be88c52506a0b1 Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 06:33:47 +0530 Subject: [PATCH 71/87] 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 72/87] 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 73/87] 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 74/87] 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 75/87] 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 76/87] 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 77/87] 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 78/87] 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 79/87] 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 80/87] 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 81/87] 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 82/87] 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 83/87] 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 84/87] 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 85/87] 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 86/87] 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 a0bc41c4f53687cea066153fa069b491c923c18a Mon Sep 17 00:00:00 2001 From: Rd Date: Wed, 26 Jun 2024 21:46:01 +0530 Subject: [PATCH 87/87] 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)