Android-Tutorial-Test-ShowCase/gradlescripts/jacoco.config.gradle

218 lines
No EOL
8 KiB
Groovy

// filter of files that shouldn't be part of the report
def androidFileFilter =
[ //jdk
'jdk.internal.*',
// data binding
'**/databinding/*.class',
'**/BR.*',
// android
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*',
// kotlin
'**/META-INF/*',
'**/*MapperImpl*.*',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/*Component*.*',
'**/*BR*.*',
'**/Manifest*.*',
'**/*$Lambda$*.*',
'**/*Companion*.*',
'**/*Module*.*',
'**/*Dagger*.*',
'**/*Hilt*.*',
'**/*MembersInjector*.*',
'**/*_MembersInjector.class',
'**/*_Factory*.*',
'**/*_Provide*Factory*.*',
'**/*Extensions*.*',
// sealed and data classes
'**/*$Result.*',
'**/*$Result$*.*',
// adapters generated by moshi
'**/*JsonAdapter.*',
// room
'**/*_Impl.class',
'**/*_Impl*.*',
// hilt
'**/hilt_aggregated_deps/*'
]
/ **
* Setup Jacoco for Android module.
* - applies Plugin to the module.
* - sets up the "debug" build type for jacoco
* - creates tasks:
* - if androidTest folder exists creates a jacocoAndroidTestReport alias for the jacoco coverageReport, otherwise an empty task.
* - if test folder exists creates a jacocoUnitTestReport alias for the jacoco coverageReport, otherwise an empty task.
* - creates jacocoTestReport which runs both alias tasks created before.
*
* Note: "jacocoTestReport" is the task name which is default for Java Modules.
* /
def setupAndroidJacoco(Project module, ArrayList<String> fileFilter, String jacocoVersion) {
configure(module) {
apply plugin: "jacoco"
module.android.testOptions.unitTests.all {
jacoco.includeNoLocationClasses = true
jacoco.excludes = fileFilter
}
android.buildTypes.debug.enableAndroidTestCoverage true
android.buildTypes.debug.enableUnitTestCoverage true
jacoco.toolVersion = "$jacocoVersion"
def hasAndroidTests = new File("${module.projectDir}/src/androidTest").exists()
def hasUnitTests = new File("${module.projectDir}/src/test").exists()
if (hasUnitTests) {
task jacocoUnitTestReport(dependsOn: ["createDebugUnitTestCoverageReport"]) {
group = "verification"
}
} else {
task jacocoUnitTestReport() {
group = "verification"
}
}
if (hasAndroidTests) {
task jacocoAndroidTestReport(dependsOn: ["createDebugAndroidTestCoverageReport"]) {
group = "verification"
}
} else {
task jacocoAndroidTestReport() {
group = "verification"
}
}
task jacocoTestReport(dependsOn: ["jacocoUnitTestReport", "jacocoAndroidTestReport"]) {
group = "verification"
}
}
}
/ **
* Setup Jacoco for Java module.
* - applies Plugin to the module.
* - updates the `jacocoTestReport` task to ignore the `androidFileFilter`
* - ensures tests run before `jacocoTestReport`
* /
def setupJavaJacoco(Project module, ArrayList<String> fileFilter) {
configure(module) {
apply plugin: "jacoco"
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: fileFilter)
}))
}
}
}
}
/ **
* Setup Jacoco for submodules based on their android or java module type
*/
subprojects { module ->
plugins.withType(JavaPlugin).whenPluginAdded {
setupJavaJacoco(module, androidFileFilter)
}
plugins.withId("com.android.application") {
setupAndroidJacoco(module, androidFileFilter, "$jacoco_version")
}
plugins.withId("com.android.library") {
setupAndroidJacoco(module, androidFileFilter, "$jacoco_version")
}
}
/ **
* Setup Aggregation tasks for Jacoco.
* - jacocoRootReport: can be used to generate the report after submodules `jacocoTestReport` has been ran at least once.
* - runTestAndJacocoRootReport: calls the `jacocoTestReport` of each submodule then calls `jacocoRootReport` for aggregation.
*
* Context, how the aggregated report works:
* The jacoco tasks created by the plugin generate .ec and .exec Execution-Data files in specific locations.
* - These Execution-Data files are all pulled into one `JacocoReport` task (`executionData.from`).
* - All the source files from all the submodules are pulled into the same `JacocoReport` task (`sourceDirectories.from`)
* - All the class files from all the submodules are pulled into the same `JacocoReport` task (`classDirectories.from`)
* Then finally the report is configured to be generated at root `build\coverage-report`
* /
configure(rootProject) {
apply plugin: "jacoco"
def testTypeName = "debug"
task runTestAndJacocoRootReport(type: JacocoReport, group: 'Coverage reports') {
description = 'Run Tests and Generates report from all subprojects'
// add all non empty subProjects `jacocoTestReport` task as a dependency.
// note: these tasks are default Jacoco Task for Java and have been added above for Android modules.
def codeProjects = subprojects.findAll({ it.subprojects.isEmpty() })
codeProjects.forEach {
dependsOn += ["$it.path:jacocoTestReport"]
}
finalizedBy("jacocoRootReport")
}
task jacocoRootReport(type: JacocoReport, group: 'Coverage reports') {
description = 'Generates report from all subprojects'
def codeProjects = subprojects.findAll({ it.subprojects.isEmpty() })
sourceDirectories.from = files(codeProjects.collect { "${it.projectDir}/src/main/java" })
def classFileTrees = codeProjects.collect {
def javaClassFilesInJavaModuleTree = fileTree(
dir: "${it.buildDir}/classes/java/main",
excludes: androidFileFilter
)
def kotlinClassFilesInJavaModuleTree = fileTree(
dir: "${it.buildDir}/classes/kotlin/main",
excludes: androidFileFilter
)
def javaClassFilesInAndroidModuleTree = fileTree(
dir: "${it.buildDir}/intermediates/javac/${testTypeName}/classes",
excludes: androidFileFilter
)
def kotlinClassFilesInAndroidModuleTree = fileTree(
dir: "${it.buildDir}/tmp/kotlin-classes/${testTypeName}",
excludes: androidFileFilter
)
files([javaClassFilesInJavaModuleTree, kotlinClassFilesInJavaModuleTree, javaClassFilesInAndroidModuleTree, kotlinClassFilesInAndroidModuleTree])
}.flatten()
classDirectories.from = files(classFileTrees)
def executionDataFiles = codeProjects.collect {
def androidTestExecutionData = fileTree(
dir: "${it.buildDir}/outputs/code_coverage/${testTypeName}AndroidTest/connected/",
includes: ["**/*.ec", "**/*.exec"]
)
def androidUnitTestExecutionData = fileTree(
dir: "${it.buildDir}/outputs/unit_test_code_coverage/",
includes: ["**/*.ec", "**/*.exec"]
)
def javaUnitTestExecutionData = "${it.buildDir}/jacoco/test.exec"
[androidTestExecutionData, androidUnitTestExecutionData, javaUnitTestExecutionData]
}.flatten()
executionData.from = files(executionDataFiles)
reports {
html {
required = true
destination file("${buildDir}/coverage-report")
}
}
}
}