Testing¶
What there is¶
| Location | What it tests | How to run |
|---|---|---|
tests/uniffi/* |
Generated bindings, one fixture per feature, on every target | ./gradlew :tests:uniffi:<name>:allTests |
tests/runtime |
The runtime through generated bindings | ./gradlew :tests:runtime:allTests |
runtime/src/*Test |
The runtime itself, including Android host and device tests | ./gradlew :runtime:allTests |
examples/* |
That the examples build and their tests pass | ./gradlew :examples:<name>:allTests |
build-logic/gradle-plugin/src/test |
Plugin unit tests | ./gradlew -p build-logic check |
cargo test |
The Rust crates in the workspace, including the bindgen | cargo test |
CI (.github/workflows/run-tests.yml) runs cargo test, ./gradlew -p build-logic check and
./gradlew build on Linux. It cross-compiles for Android, Windows (MinGW) and aarch64 Linux.
Apple targets are not built in CI. Run them locally on a Mac before merging changes to native
code.
Fixtures¶
Most fixtures in tests/uniffi/ are ports of the fixtures in UniFFI's own repository, with the
Kotlin tests turned into common tests. Each fixture is a Rust crate and a Gradle module:
tests/uniffi/callbacks/
├── Cargo.toml crate-type = ["cdylib", "staticlib"], or with "lib" when it is depended upon
├── build.rs generate_scaffolding_from_current_dir() for UDL fixtures
├── build.gradle.kts plugins { id("uniffi-tests-from-library") }
├── uniffi.toml package_name = "callbacks"
└── src/
├── callbacks.udl
├── commonMain/rust/lib.rs
└── commonTest/kotlin/CallbacksTest.kt
uniffi-tests-from-library(build-logic/conventions/) applies the plugin withbindgenFromPath(<repo>/bindgen)andgenerateFromLibrary(), declares all targets the host can build, and adds the test dependencies (kotlin("test"), kotest assertions, coroutines-test). It setsaddRuntime = falseand depends onproject(":runtime")instead, so tests always run against the runtime in the working tree.tests/build-commonprovidesgenerate_scaffolding_from_current_dir(), which finds the UDL file from the directory name.- Every fixture is a member of the Cargo workspace in the root
Cargo.tomland is included insettings.gradle.kts.
Adding a fixture¶
- Create the directory with the files above. Copy a similar fixture as a starting point.
- Add it to
membersin the rootCargo.tomlandinclude(":tests:uniffi:<name>")tosettings.gradle.kts. - Write tests in
src/commonTest/kotlin. UsejvmTestornativeTestonly for platform-specific behaviour.
Working on the generator¶
All fixtures use the bindgen from the working tree (bindgenFromPath), which is reinstalled when
its sources change. A typical loop:
./gradlew :tests:uniffi:coverall:jvmTest # fast feedback
./gradlew :tests:uniffi:coverall:macosArm64Test # check native too
Look at the generated code in tests/uniffi/<name>/build/uniffi/bindings/. Compile errors usually
point there.
Tip
JVM and Native get their FFI declarations from different places (JNA classes vs. C headers). A change can compile on one and break the other. Run at least one JVM and one native target.
Debugging crashes¶
- A test that crashes the process (SIGABRT, exit code 134) produces no console output, because the
JVM dies before Gradle collects it. Read
build/test-results/<task>/TEST-*.xml, or run the test class on its own with--info. - For Rust panics, set
RUST_BACKTRACE=1in the environment of the test task. - On JVM,
-Djna.debug_load=trueshows where JNA looks for the library.