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