blob: 138060aeea212aba86b6d293720c80f309cabc6d [file] [view]
# Test coverage for the compiler frontend (FIR) area
This module aggregates [JaCoCo](https://www.jacoco.org/jacoco/) test coverage for the FIR frontend
(`org.jetbrains.kotlin.fir.*` classes) from the test tasks agreed on in
[KQA-3083](https://youtrack.jetbrains.com/issue/KQA-3083):
- `:compiler:test`
- `:compiler:tests-integration:test`
- `:compiler:fir:analysis-tests:test`
- `:compiler:fir:fir2ir:test`
- `:compiler:fir:raw-fir:psi2fir:test`
- `:compiler:fir:raw-fir:light-tree2fir:test`
> This list is a snapshot for orientation — the authoritative list is the `jacocoAggregation(...)`
> dependencies in [`build.gradle.kts`](build.gradle.kts), which may grow to include more test
> tasks or additional FIR production modules over time.
Coverage collection is **disabled by default** and is a strict no-op for regular builds.
It is enabled with the Gradle property `kotlin.build.coverage.enabled` (also settable in
`local.properties`). The property must be passed to *every* coverage-related invocation —
including the report task — otherwise the test JVMs are not instrumented and the report is skipped.
The setup lives in two places only, so the coverage engine can be swapped without touching
the test modules themselves:
- `repo/gradle-build-conventions/test-coverage-convention` — applies JaCoCo to the producer
projects when the property is set;
- this module — aggregates execution data into a report via Gradle's
[`jacoco-report-aggregation`](https://docs.gradle.org/current/userguide/jacoco_report_aggregation_plugin.html)
plugin (Project-Isolation-compatible: data flows through outgoing configurations, no project
reaches into another project's build directory).
## How to generate the report
The report task triggers the required test tasks through Gradle's dependency graph — running the
report alone is enough:
```bash
./gradlew :compiler:test-coverage:firCoverageReport -Pkotlin.build.coverage.enabled=true
```
Or, in IDEA, run the checked-in **FIR Coverage Report** run configuration (`Tests` folder), which
runs the same task with the property already set.
Outputs:
- HTML: `compiler/test-coverage/build/reports/jacoco/firCoverageReport/html/index.html`
- XML: `compiler/test-coverage/build/reports/jacoco/firCoverageReport/firCoverageReport.xml`
To collect coverage from a subset of the suites, exclude the unwanted test tasks with `-x`;
the report is built from whatever execution data exists:
```bash
./gradlew :compiler:test-coverage:firCoverageReport -Pkotlin.build.coverage.enabled=true \
-x :compiler:test -x :compiler:tests-integration:test \
-x :compiler:fir:analysis-tests:test -x :compiler:fir:fir2ir:test
# keeps only the raw-fir suites
```
Raw execution data lands in each producing project's `build/jacoco/test.exec`. Re-running a test
task with a different `--tests` filter overwrites its `.exec` file, so collect one scope per
invocation.
> Note: with `kotlin.build.coverage.enabled=true` the test tasks are configured with
> `ignoreFailures = true`, so failing tests don't abort the build and the report is still
> generated from the collected data. The failures are still printed in the test output.
## How to open the report
Open the HTML report in a browser, or in IntelliJ IDEA — double-click
`html/index.html`: IDEA shows coverage for loaded modules in the Coverage tool window and renders
per-file coverage in the Project view. (IDEA refuses to open reports located outside the project
directory.)
## Known limitations
- Only `org.jetbrains.kotlin.*` classes are instrumented (see `test-coverage-convention`).
This is deliberate: instrumenting everything breaks reflection-sensitive tests — debugger
stepping/local-variable tests fail because `com.sun.tools.jdi` reflects over JDWP constant
classes and trips on JaCoCo's synthetic members, and some codegen tests reflect over the
bytecode they generate and load. Widen the filter here and in the report module together
if the report scope ever grows beyond `org.jetbrains.kotlin`.
- Only code running inside the test JVMs is instrumented; tests that spawn external processes
(some `:compiler:tests-integration` scenarios) don't contribute the coverage of those processes.
- JaCoCo reports branch data on Kotlin bytecode constructs (inline functions, `when` mappings,
suspend state machines) that can look noisier than Kotlin-aware engines — keep this in mind
when reading branch counters.