diff --git a/android-tests/README.md b/android-tests/README.md index 729af19c..af822c99 100644 --- a/android-tests/README.md +++ b/android-tests/README.md @@ -26,35 +26,97 @@ module; it is a standalone Gradle build kept separate so the default `mvn` goal - JDK 17 on `PATH` (AGP 8.x requires it). - Android SDK with `platforms/android-34` and `build-tools/34.0.0` installed; export `ANDROID_HOME` (or `ANDROID_SDK_ROOT`) to point at it. -- Either an attached emulator/device (`adb devices` shows it) or the AGP managed device - bundled into this build (`api31`, AOSP system image). -- The library JAR built by the parent Maven build: + ```shell + export ANDROID_HOME=/path/to/android ``` - cd .. && mvn -DskipTests package +- Either an attached emulator/device (`adb devices` shows it) or the AGP managed device bundled into this build (`api33`, AOSP system image). +- The library JAR built by the parent Maven build: + + ```shell + mvn -f.. -DskipTests package ``` ## Running Against an attached emulator/device: -``` +```shell ./gradlew connectedAndroidTest ``` -Against the bundled AGP managed device (downloads the AOSP API 31 system image on first -run, then provisions and tears down a headless emulator for each invocation): +Against the bundled AGP managed device +(downloads the AOSP API 33 system image on first run, +then provisions and tears down a headless emulator for each invocation): +```shell +./gradlew api33DebugAndroidTest ``` -./gradlew api31DebugAndroidTest + +## Coverage + +The run is instrumented with JaCoCo, +pinned to the version the Maven build reports with, +and leaves one execution data file per device under `build/outputs/code_coverage`. +The full round trip: + +1. Build the JAR the instrumented tests run against: + + ```shell + mvn -f.. -DskipTests package + ``` + +2. Run the tests on a device, either an attached one or the bundled managed device: + + ```shell + ./gradlew connectedDebugAndroidTest + ./gradlew api33DebugAndroidTest + ``` + +3. Fold the device data into the project's coverage: + + ```shell + mvn -f.. -Pjacoco verify site + ``` + + The JVM suite runs under the JaCoCo agent in this step, + so both halves end up in `target/jacoco.exec`: + the `jacoco` profile merges whatever this module produced into it in the site lifecycle, + just before the report is written. + The coverage check runs earlier, on the JVM data alone, + so its minimums mean the same thing whether a device run is lying around; + the device data widens the report, not the bar. + +Repeat step 2 whenever the library changes. +The execution data identifies each class by its bytecode, +and JaCoCo drops data that no longer matches the compiled class, +so a device run left over from an older JAR quietly lowers the numbers instead of inflating them. + +### Maximum coverage + +This library is written to work from JDK 8 through 25 and on Android. +Since new JAXP methods were introduced in JDK 9, 13, and 18, +maximum coverage is obtained by the following recipe: + +```shell +export JDK8=/path/to/jdk8 +export JDK21=/path/to/jdk21 +export ANDROID_HOME=/path/to/android +JAVA_HOME=$JDK21 mvn -f.. -Pjacoco clean package +./gradlew api33DebugAndroidTest +JAVA_HOME=$JDK8 mvn -f.. -Pjacoco test +JAVA_HOME=$JDK21 mvn -f.. -Pjacoco verify site ``` ## Excluded test groups -The build excludes JUnit 5 tags for JAXP types Android does not ship: +The build runs the `dom`, `sax`, `schema`, and `trax` tags and excludes the rest: - `stax`: there is no `XMLInputFactory` on Android. -- `schema`: there is no `SchemaFactory` on Android. +- `xpath`: Android ships an XPath implementation, + but it is currently untested. - `xpath3`: relies on Saxon, which is not on the Android classpath. -DOM, SAX, TrAX and XPath 1.0 paths are exercised in full. +DOM, SAX, TrAX, and schema paths are exercised in full; +the schema tests run against the Apache Xerces the `androidTest` classpath brings in, +since Android ships `javax.xml.validation` without a `SchemaFactory` implementation. diff --git a/android-tests/build.gradle.kts b/android-tests/build.gradle.kts index e8bfc34c..845b1e1e 100644 --- a/android-tests/build.gradle.kts +++ b/android-tests/build.gradle.kts @@ -42,6 +42,17 @@ android { targetCompatibility = JavaVersion.VERSION_1_8 } + // Match the JaCoCo the Maven build reports with, so the on-device agent understands the same execution data format. + testCoverage { + jacocoVersion = "0.8.15" + } + + buildTypes { + getByName("debug") { + enableAndroidTestCoverage = true + } + } + sourceSets { getByName("androidTest") { java.srcDirs("../src/test/java") diff --git a/pom.xml b/pom.xml index 443148c6..e63ea551 100644 --- a/pom.xml +++ b/pom.xml @@ -75,14 +75,19 @@ limitations under the License. 2.12.2 2.16 - + true - 0.97 - 0.97 - 0.99 - 0.91 - 0.96 - 0.96 + 0.96 + 0.93 + 0.95 + 0.87 + 0.93 + 0.92 + + surefire + + report-only + + + + + ${project.build.directory}/surefire-reports/jdk-xerces + ${project.build.directory}/surefire-reports/saxon + ${project.build.directory}/surefire-reports/saxon-xerces + ${project.build.directory}/surefire-reports/stockjdk + ${project.build.directory}/surefire-reports/woodstox + ${project.build.directory}/surefire-reports/xalan + ${project.build.directory}/surefire-reports/xalan-xerces + ${project.build.directory}/surefire-reports/xerces + + + + + failsafe + + + failsafe-report-only + + + + + + + jacoco + + + + org.jacoco + jacoco-maven-plugin + + + merge-android + pre-site + + merge + + + + + ${project.build.directory} + + jacoco.exec + + + + ${project.basedir}/android-tests/build/outputs/code_coverage + + **/*.ec + + + + ${project.build.directory}/jacoco.exec + + + + + + +