-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathjacoco.gradle
More file actions
173 lines (145 loc) · 6.45 KB
/
jacoco.gradle
File metadata and controls
173 lines (145 loc) · 6.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Jacoco configuration extracted from build.gradle
apply plugin: 'jacoco'
jacoco {
toolVersion = '0.8.8'
}
// Enable JaCoCo for the test task
tasks.withType(Test) {
// Enable JaCoCo coverage
jacoco {
includeNoLocationClasses = true
excludes = ['jdk.internal.*']
// Explicitly enable for Robolectric tests
enabled = true
}
// Configure system properties for Robolectric + JaCoCo compatibility
systemProperty 'robolectric.enabledSdks', '28,29,30,31,32,33'
finalizedBy jacocoTestReport
}
// Unit test coverage report task
// This task generates Jacoco coverage reports for unit tests only
tasks.register('jacocoTestReport', JacocoReport) {
dependsOn 'testDebugUnitTest'
reports {
xml.required = true
html.required = true
csv.required = false
}
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
// Updated to handle multiple possible class directory locations
def classDirectoriesFiles = []
// Try multiple possible class directory locations for different AGP versions
def possibleClassDirs = [
"${buildDir}/intermediates/javac/debug/classes",
"${buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes",
"${buildDir}/intermediates/runtime_library_classes_dir/debug",
"${buildDir}/intermediates/classes/debug",
"${buildDir}/classes/java/main",
"${buildDir}/tmp/kotlin-classes/debug"
]
possibleClassDirs.each { dirPath ->
def dir = file(dirPath)
if (dir.exists() && dir.isDirectory()) {
def classDir = fileTree(dir: dirPath, excludes: fileFilter)
if (classDir.files.size() > 0) {
classDirectoriesFiles.add(classDir)
}
}
}
// Include all source directories (Java and Kotlin)
sourceDirectories.from = files([
'src/main/java',
'src/main/kotlin'
])
// Include all found class files
classDirectories.from = files(classDirectoriesFiles)
// Include execution data files from multiple possible locations
def execFiles = fileTree(dir: "$buildDir", includes: [
'jacoco/testDebugUnitTest.exec',
'outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec',
'jacoco/*.exec',
'outputs/**/**.exec'
])
executionData.from = files(execFiles.filter { it.exists() })
outputs.upToDateWhen { false }
doFirst {
// Enhanced logging for debugging
logger.lifecycle("=== JaCoCo Report Generation ===")
// Log source directories
logger.lifecycle("Source directories:")
sourceDirectories.files.each { dir ->
if (dir.exists()) {
logger.lifecycle(" - Found: $dir")
} else {
logger.lifecycle(" - Missing: $dir")
}
}
// Log class directories
logger.lifecycle("Class directories:")
classDirectories.files.each { dir ->
logger.lifecycle(" - $dir (${dir.exists() ? 'exists' : 'missing'})")
}
// Log execution data files
def execDataFiles = executionData.files
logger.lifecycle("Execution data files:")
if (execDataFiles.isEmpty() || !execDataFiles.any { it.exists() }) {
logger.warn(" - No execution data files found - coverage report will be empty")
} else {
execDataFiles.each { file ->
if (file.exists()) {
logger.lifecycle(" - Found: $file (${file.length()} bytes)")
} else {
logger.lifecycle(" - Missing: $file")
}
}
}
logger.lifecycle("================================")
}
}
// Task to ensure JaCoCo XML report is created in the exact location SonarQube expects
task generateJacocoXmlReport {
doLast {
// Create the directory if it doesn't exist
def reportDir = file("${buildDir}/reports/jacoco/jacocoTestReport")
reportDir.mkdirs()
// Check if we have a JaCoCo exec file
def execFiles = fileTree(dir: "${buildDir}", includes: ['**/*.exec'])
if (execFiles.isEmpty()) {
// Create an empty report file if no exec files found
def reportFile = new File(reportDir, "jacocoTestReport.xml")
reportFile.text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<report name=\"android-client\">\n</report>"
println "Created empty JaCoCo report at ${reportFile.absolutePath}"
} else {
println "Found JaCoCo exec files: ${execFiles.files}"
// If we have exec files but no report, we could use JaCoCo's ant task to generate one
// This is a simplified version - in a real scenario you'd use the JaCoCo ant task
}
// Check if the report exists and log its content
def reportFile = new File(reportDir, "jacocoTestReport.xml")
if (reportFile.exists()) {
println "\n==== JaCoCo Report Content ===="
println "Report file size: ${reportFile.length()} bytes"
if (reportFile.length() > 0) {
def xmlContent = reportFile.text
println "First 500 chars of report: ${xmlContent.take(500)}..."
// Count packages, classes, and methods
def packageCount = (xmlContent =~ /<package/).count
def classCount = (xmlContent =~ /<class/).count
def methodCount = (xmlContent =~ /<method/).count
def lineCount = (xmlContent =~ /<line/).count
println "Report contains:\n - ${packageCount} packages\n - ${classCount} classes\n - ${methodCount} methods\n - ${lineCount} lines"
// Check for covered lines
def coveredLineCount = (xmlContent =~ /ci=\"1\"/).count
println " - ${coveredLineCount} covered lines"
if (coveredLineCount == 0) {
println "WARNING: No covered lines found in the report!"
}
} else {
println "Report file is empty!"
}
println "===========================\n"
} else {
println "Report file does not exist at ${reportFile.absolutePath}"
}
}
}