• Home
Name Date Size #Lines LOC

..--

macro/06-Sep-2024-6644

src/06-Sep-2024-15898

tests/06-Sep-2024-192148

Android.bpD06-Sep-20241.4 KiB6662

OWNERSD06-Sep-202445 21

README.mdD06-Sep-20243.4 KiB12897

rustfmt.tomlD06-Sep-202493

README.md

1# rdroidtest
2
3This is a custom Rust test harness which allows tests to be ignored at runtime based on arbitrary
4criteria. The built-in Rust test harness only allows tests to be ignored at compile time, but this
5is often not enough on Android, where we want to ignore tests based on system properties or other
6characteristics of the device on which the test is being run, which are not known at build time.
7
8## Usage
9
10Unfortunately without the built-in support that rustc provides to the standard test harness, this
11one is slightly more cumbersome to use. Firstly, add it to the `rust_test` build rule in your
12`Android.bp` by adding the defaults provided:
13
14```soong
15rust_test {
16    name: "mycrate.test",
17    defaults: ["rdroidtest.defaults"],
18    // ...
19}
20```
21
22If you are testing a binary that has a `main` function, you'll need to remove it from the test
23build:
24
25```rust
26#[cfg(not(test))]
27fn main() {
28    // ...
29}
30```
31
32(If you're testing a library or anything else which doesn't have a `main` function, you don't need
33to worry about this.)
34
35Each test case should be marked with the `rdroidtest` attribute, rather than the standard
36`#[test]` attribute:
37
38```rust
39use rdroidtest::rdroidtest;
40
41#[rdroidtest]
42fn one_plus_one() {
43    assert_eq!(1 + 1, 2);
44}
45```
46
47To ignore a test, you can add an `ignore_if` attribute whose argument is an expression that
48evaluates to a boolean:
49
50```rust
51use rdroidtest::{ignore_if, rdroidtest};
52
53#[rdroidtest]
54#[ignore_if(!feeling_happy())]
55fn clap_hands() {
56    assert!(HANDS.clap().is_ok());
57}
58```
59
60Somewhere in your main module, you need to use the `test_main` macro to generate an entry point for
61the test harness:
62
63```rust
64rdroidtest::test_main!();
65```
66
67You can then run your tests as usual with `atest`.
68
69
70## Parameterized Tests
71
72To run the same test multiple times with different parameter values, add an argument to the
73`rdroidtest` attribute:
74
75```rust
76use rdroidtest::rdroidtest;
77
78#[rdroidtest(my_instances())]
79fn is_even(param: u32) {
80    assert_eq!(param % 2, 0);
81}
82```
83
84The initial argument to the `rdroidtest` attribute is an expression that generates the set of
85parameters to invoke the test with.  This expression should evaluate to a vector of `(String, T)`
86values for some type `T`:
87
88```rust
89fn my_instances() -> Vec<(String, u32)> {
90    vec![
91        ("one".to_string(), 1),
92        ("two".to_string(), 2),
93        ("three".to_string(), 3),
94    ]
95}
96```
97
98The test method will be invoked with each of the parameter values in turn, passed in as the single
99argument of type `T`.
100
101Parameterized tests can also be ignored, using an `ignore_if` attribute.  For a parameterized test,
102the argument is an expression that emits a boolean when invoked with a single argument, of type
103`&T`:
104
105```rust
106#[rdroidtest(my_instances())]
107#[ignore_if(feeling_odd)]
108fn is_even_too(param: u32) {
109    assert_eq!(param % 2, 0);
110}
111
112fn feeling_odd(param: &u32) -> bool {
113    *param % 2 == 1
114}
115```
116
117## Summary Table
118
119|               |  Normal              | Conditionally Ignore                          |
120|---------------|----------------------|-----------------------------------------------|
121| Normal        | `#[rdroidtest]`      | `#[rdroidtest]` <br> `#[ignore_if(<I>)]`      |
122| Parameterized | `#[rdroidtest(<G>)]` | `#[rdroidtest(<G>)]` <br> `#[ignore_if(<C>)]` |
123
124Where:
125- `<I>` is an expression that evaluates to a `bool`.
126- `<G>` is an expression that evaluates to a `Vec<String, T>`.
127- `<C>` is an callable expression with signature `fn(&T) -> bool`.
128