IMPORTANT: The file content has been truncated. Status: Showing lines 350-500 of 557 total lines. Action: To read more of the file, you can use the 'start_line' and 'end_line' parameters in a subsequent 'read_file' call. For example, to read the next section of the file, use start_line: 501. --- FILE CONTENT (truncated) --- taskPrefix = "Tablet10", deviceTaskName = "tablet10PixelTabletApi34ReleaseAndroidTest", outputDirectory = "tablet-10", previousCopyTask = copyTablet7StoreScreenshots, ) tasks.register("generateStoreScreenshots") { group = "Verification" description = "Runs store screenshot tests on managed devices and copies PNGs into distribution assets." dependsOn(copyTablet10StoreScreenshots) doLast { val missing = listOf("phone", "tablet-7", "tablet-10").flatMap { outputDirectory -> storeScreenshotFiles.mapNotNull { fileName -> val file = storeScreenshotsRoot.file("$outputDirectory/$fileName").asFile if (file.exists()) null else file } } if (missing.isNotEmpty()) { throw GradleException( "Missing generated store screenshots:\n" + missing.joinToString(separator = "\n") { "- ${it.path}" }, ) } } } tasks.register("verifyWithCoverage") { group = "Verification" description = "Runs JVM unit tests and generates a combined coverage report using JaCoCo with the static GMD baseline." dependsOn("testReleaseUnitTest") reports { xml.required.set(true) html.required.set(true) } val classFilter = listOf( "**/R.class", "**/R$*.class", "**/BuildConfig.*", "**/Manifest*.*", "**/*Test*.*", "android/**/*.*", "**/*_ViewBinding*.*", "**/*_MembersInjector*.*", "**/*_Factory*.*", "**/*_Provide*Factory*.*", "**/*ExtensionsKt*.*", // ComposableSingletons are compiler-generated classes for @Composable lambdas // that are often static and difficult to cover in unit tests, creating noise. "**/*ComposableSingletons*.*", ) val releaseTree = fileTree(layout.buildDirectory.dir("tmp/kotlin-classes/release")) { exclude(classFilter) } val javaTree = fileTree(layout.buildDirectory.dir("intermediates/javac/release/classes")) { exclude(classFilter) } classDirectories.setFrom(files(releaseTree, javaTree)) sourceDirectories.setFrom( files( "src/main/java", "src/main/kotlin", "src/release/java", "src/release/kotlin", ), ) // Collect all execution data from both unit tests and instrumented tests // Using specific roots to avoid implicit dependency issues with other tasks' outputs in the build folder val executionDataFiles = files( fileTree(layout.buildDirectory.dir("outputs/unit_test_code_coverage")) { include("**/*.exec") }, layout.projectDirectory.file("coverage-baselines/gmd_smoke.ec"), fileTree(layout.buildDirectory.dir("jacoco")) { include("**/*.exec") }, ) executionData.setFrom(executionDataFiles) doFirst { val lfsBaseline = layout.projectDirectory.file("coverage-baselines/gmd_smoke.ec").asFile if (!lfsBaseline.exists()) { throw GradleException( "Required coverage baseline is missing: ${lfsBaseline.path}. " + "Run 'git lfs pull' to fetch tracked baselines or './gradlew generateGmdCoverage' to regenerate it.", ) } if (lfsBaseline.length() < 1000) { val header = lfsBaseline.inputStream().use { it.readNBytes(100) }.toString(Charsets.UTF_8) if (header.startsWith("version https://git-lfs.github.com/spec/v1")) { throw GradleException("Coverage baseline is a Git LFS pointer. Please run 'git lfs pull' to fetch the actual file.") } } val existingFiles = executionDataFiles.files.filter { it.exists() } val dynamicExecutionFiles = existingFiles.filter { it.name != "gmd_smoke.ec" } if (dynamicExecutionFiles.isEmpty()) { throw GradleException( "No dynamic JaCoCo execution data files were found. " + "Ensure tests were executed with coverage enabled (e.g., via -Pcoverage).\n" + "Searched in:\n" + "- ${layout.buildDirectory.dir("outputs/unit_test_code_coverage").get()}\n" + "- ${layout.buildDirectory.dir("jacoco").get()}", ) } } } tasks.withType().configureEach { if (isCoverageEnabled) { configure { isEnabled = true // Required for Robolectric isIncludeNoLocationClasses = true excludes = listOf("jdk.internal.*") } } else { configure { isEnabled = false } } if (name.contains("Release")) { enabled = false } val defaultForks = (Runtime.getRuntime().availableProcessors() / 4).coerceAtLeast(2) maxParallelForks = (project.findProperty("testForks") as String?)?.toInt() ?: defaultForks forkEvery = 0L minHeapSize = "512m" maxHeapSize = "1536m" jvmArgs = listOf( "-XX:+UseG1GC", "-XX:MaxMetaspaceSize=512m", "-Dfile.encoding=UTF-8", ) systemProperty("robolectric.graphicsMode", "NATIVE") // Exclude tests tagged @Category(LocalOnly::class) from automated Gradle runs. // These tests are intended to be run directly from the IDE. // Note: This project uses JUnit 4 exclusively. If a Jupiter runner is ever added, // useJUnit { } will need to be scoped to only JUnit 4 tasks to avoid overriding // Jupiter configuration.