Skip to content

Commit 73fd4aa

Browse files
Update JaCoCo version to 0.8.12 and configure Java 17 compatibility; enhance test coverage reporting with new tasks for unit and instrumentation tests.
1 parent 8ef3f73 commit 73fd4aa

File tree

4 files changed

+233
-20
lines changed

4 files changed

+233
-20
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
buildscript {
22
ext {
3-
jacoco_version = '0.8.8'
3+
jacoco_version = '0.8.12'
44
agp_version = '8.2.1'
55
}
66
repositories {

contentstack/build.gradle

Lines changed: 227 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
id "com.android.library"
33
id "com.vanniktech.maven.publish" version "0.33.0"
4+
id 'jacoco'
45
}
56

67
ext {
@@ -12,6 +13,14 @@ ext {
1213
android {
1314
namespace "com.contentstack.sdk"
1415
compileSdk 34 // Using latest stable Android SDK version
16+
17+
// SDK compiles to Java 17 for JaCoCo compatibility
18+
// But can be built with Java 21 - tests use Java 17 toolchain
19+
compileOptions {
20+
sourceCompatibility JavaVersion.VERSION_17
21+
targetCompatibility JavaVersion.VERSION_17
22+
}
23+
1524
buildFeatures {
1625
buildConfig true
1726
}
@@ -30,10 +39,15 @@ android {
3039
}
3140

3241
testOptions {
33-
unitTests.all {
34-
// jacoco {
35-
// includeNoLocationClasses = true
36-
// }
42+
unitTests {
43+
includeAndroidResources = true
44+
returnDefaultValues = true
45+
all {
46+
jacoco {
47+
includeNoLocationClasses = true
48+
excludes = ['jdk.internal.*']
49+
}
50+
}
3751
}
3852
}
3953
// signing {
@@ -109,18 +123,37 @@ dependencies {
109123
def multidex = "2.0.1"
110124
def volley = "1.2.1"
111125
def junit = "4.13.2"
126+
def mockito = "5.2.0"
127+
def mockitoKotlin = "2.2.0"
112128
configurations.configureEach { resolutionStrategy.force 'com.android.support:support-annotations:23.1.0' }
113129
implementation fileTree(include: ['*.jar'], dir: 'libs')
114130
implementation "com.android.volley:volley:$volley"
115131
implementation "junit:junit:$junit"
116132

117133
// For AGP 7.4+
118134
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
135+
136+
// Unit Testing Dependencies
119137
testImplementation 'junit:junit:4.13.2'
138+
testImplementation "org.mockito:mockito-core:$mockito"
139+
testImplementation "org.mockito:mockito-inline:$mockito"
140+
testImplementation 'org.mockito:mockito-android:5.2.0'
141+
testImplementation 'org.robolectric:robolectric:4.15' // Updated to fix security vulnerabilities
142+
testImplementation 'androidx.test:core:1.5.0'
143+
testImplementation 'androidx.test:runner:1.5.2'
144+
testImplementation 'androidx.test.ext:junit:1.1.5'
145+
testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0'
146+
testImplementation 'org.json:json:20231013'
147+
// PowerMock for advanced mocking
148+
testImplementation 'org.powermock:powermock-module-junit4:2.0.9'
149+
testImplementation 'org.powermock:powermock-api-mockito2:2.0.9'
150+
testImplementation 'org.powermock:powermock-core:2.0.9'
151+
152+
// Android Test Dependencies
120153
androidTestImplementation 'androidx.test:core:1.5.0'
121-
testImplementation 'org.robolectric:robolectric:4.6.1'
122-
123-
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
154+
androidTestImplementation 'androidx.test:runner:1.5.2'
155+
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
156+
androidTestImplementation('androidx.test.espresso:espresso-core:3.5.1', {
124157
exclude group: 'com.android.support', module: 'support-annotations'
125158
})
126159

@@ -200,22 +233,198 @@ mavenPublishing {
200233
}
201234
}
202235

236+
jacoco {
237+
toolVersion = "0.8.12"
238+
}
239+
203240
tasks.register('jacocoTestReport', JacocoReport) {
204-
dependsOn('testDebugUnitTest', 'createDebugCoverageReport')
241+
dependsOn('testDebugUnitTest')
242+
243+
reports {
244+
xml.required = true
245+
html.required = true
246+
csv.required = false
247+
248+
xml.outputLocation = file("${buildDir}/reports/jacoco/jacocoTestReport/jacocoTestReport.xml")
249+
html.outputLocation = file("${buildDir}/reports/jacoco/jacocoTestReport/html")
250+
}
251+
252+
def excludePatterns = [
253+
'**/R.class',
254+
'**/R$*.class',
255+
'**/BuildConfig.*',
256+
'**/Manifest*.*',
257+
'**/*Test*.*',
258+
'android/**/*.*',
259+
'**/*$ViewInjector*.*',
260+
'**/*$ViewBinder*.*',
261+
'**/Lambda$*.class',
262+
'**/Lambda.class',
263+
'**/*Lambda.class',
264+
'**/*Lambda*.class',
265+
'**/*_MembersInjector.class',
266+
'**/Dagger*Component*.*',
267+
'**/*Module_*Factory.class',
268+
'**/AutoValue_*.*',
269+
'**/*JavascriptBridge.class',
270+
'**/package-info.class',
271+
'**/TestActivity.class',
272+
// External library exclusions
273+
'**/okhttp/**',
274+
'**/okio/**',
275+
'**/txtmark/**',
276+
'**/retrofit2/**',
277+
'**/volley/**'
278+
]
279+
280+
sourceDirectories.setFrom(files([
281+
"${project.projectDir}/src/main/java"
282+
]))
283+
284+
classDirectories.setFrom(files([
285+
fileTree(dir: "${buildDir}/intermediates/javac/debug", excludes: excludePatterns),
286+
fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: excludePatterns)
287+
]))
288+
289+
executionData.setFrom(fileTree(buildDir).include([
290+
"outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec",
291+
"jacoco/testDebugUnitTest.exec"
292+
]))
293+
}
294+
295+
// Combined coverage report for both unit and instrumentation tests
296+
tasks.register('jacocoCombinedReport', JacocoReport) {
297+
// This task can run after both test types complete
298+
// Make it depend on both if they're being run
299+
group = "Reporting"
300+
description = "Generate Jacoco coverage reports for both unit and instrumentation tests"
301+
205302
reports {
303+
xml.required = true
206304
html.required = true
305+
csv.required = false
306+
307+
xml.outputLocation = file("${buildDir}/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml")
308+
html.outputLocation = file("${buildDir}/reports/jacoco/jacocoCombinedReport/html")
207309
}
310+
311+
def excludePatterns = [
312+
'**/R.class',
313+
'**/R$*.class',
314+
'**/BuildConfig.*',
315+
'**/Manifest*.*',
316+
'**/*Test*.*',
317+
'android/**/*.*',
318+
'**/*$ViewInjector*.*',
319+
'**/*$ViewBinder*.*',
320+
'**/Lambda$*.class',
321+
'**/Lambda.class',
322+
'**/*Lambda.class',
323+
'**/*Lambda*.class',
324+
'**/*_MembersInjector.class',
325+
'**/Dagger*Component*.*',
326+
'**/*Module_*Factory.class',
327+
'**/AutoValue_*.*',
328+
'**/*JavascriptBridge.class',
329+
'**/package-info.class',
330+
'**/TestActivity.class',
331+
// External library exclusions
332+
'**/okhttp/**',
333+
'**/okio/**',
334+
'**/txtmark/**',
335+
'**/retrofit2/**',
336+
'**/volley/**'
337+
]
338+
339+
sourceDirectories.setFrom(files([
340+
"${project.projectDir}/src/main/java"
341+
]))
342+
343+
classDirectories.setFrom(files([
344+
fileTree(dir: "${buildDir}/intermediates/javac/debug", excludes: excludePatterns),
345+
fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: excludePatterns)
346+
]))
347+
348+
// Collect execution data from both unit tests and instrumentation tests
349+
executionData.setFrom(fileTree(buildDir).include([
350+
// Unit test coverage
351+
"outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec",
352+
"jacoco/testDebugUnitTest.exec",
353+
// Instrumentation test coverage
354+
"outputs/code_coverage/debugAndroidTest/connected/**/*.ec"
355+
]))
208356
}
209357

210-
// Configure jacocoTestReport after evaluation when classDirectories is available
211-
project.afterEvaluate {
212-
tasks.named('jacocoTestReport', JacocoReport) {
213-
classDirectories.setFrom(files(classDirectories.files.collect {
214-
fileTree(dir: it, exclude: [
215-
'**com/contentstack/okhttp**',
216-
'**com/contentstack/okio**',
217-
'**com/contentstack/txtmark**'
218-
])
219-
}))
358+
tasks.register('jacocoTestCoverageVerification', JacocoCoverageVerification) {
359+
dependsOn('testDebugUnitTest')
360+
361+
violationRules {
362+
rule {
363+
limit {
364+
minimum = 0.99
365+
}
366+
}
367+
368+
rule {
369+
element = 'CLASS'
370+
limit {
371+
counter = 'LINE'
372+
value = 'COVEREDRATIO'
373+
minimum = 0.99
374+
}
375+
excludes = [
376+
'*.R',
377+
'*.R$*',
378+
'*.BuildConfig',
379+
'*.*Test*',
380+
'*.TestActivity'
381+
]
382+
}
383+
384+
rule {
385+
element = 'CLASS'
386+
limit {
387+
counter = 'BRANCH'
388+
value = 'COVEREDRATIO'
389+
minimum = 0.99
390+
}
391+
excludes = [
392+
'*.R',
393+
'*.R$*',
394+
'*.BuildConfig',
395+
'*.*Test*',
396+
'*.TestActivity'
397+
]
398+
}
220399
}
400+
401+
def excludePatterns = [
402+
'**/R.class',
403+
'**/R$*.class',
404+
'**/BuildConfig.*',
405+
'**/Manifest*.*',
406+
'**/*Test*.*',
407+
'android/**/*.*',
408+
'**/package-info.class',
409+
'**/TestActivity.class'
410+
]
411+
412+
sourceDirectories.setFrom(files([
413+
"${project.projectDir}/src/main/java"
414+
]))
415+
416+
classDirectories.setFrom(files([
417+
fileTree(dir: "${buildDir}/intermediates/javac/debug", excludes: excludePatterns),
418+
fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: excludePatterns)
419+
]))
420+
421+
executionData.setFrom(fileTree(buildDir).include([
422+
"outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec",
423+
"jacoco/testDebugUnitTest.exec"
424+
]))
425+
}
426+
427+
// Make check task depend on coverage verification
428+
tasks.named('check') {
429+
dependsOn('jacocoTestReport', 'jacocoTestCoverageVerification')
221430
}

gradle.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ android.enableR8.fullMode=false
44
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
55
android.suppressUnsupportedCompileSdk=34
66

7+
# Use Java 17 for JaCoCo compatibility
8+
org.gradle.java.home=/opt/homebrew/opt/openjdk@17
9+
710
# Maven Central Publishing Configuration
811
# These values should be provided by environment variables in CI
912
# For new Central Portal, use Portal Token instead of username/password

gradle/wrapper/gradle-wrapper.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
33
#distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
44
#distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
5-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
5+
#distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
67
networkTimeout=10000
78
validateDistributionUrl=true
89
zipStoreBase=GRADLE_USER_HOME

0 commit comments

Comments
 (0)