1*6777b538SAndroid Build Coastguard Worker# Rust integration into C++ Gtest targets. 2*6777b538SAndroid Build Coastguard Worker 3*6777b538SAndroid Build Coastguard WorkerThis directory contains the tools for writing gtest-based tests in Rust and 4*6777b538SAndroid Build Coastguard Workerintegrating them into Chromium's C++ gtest binaries. The tools are all 5*6777b538SAndroid Build Coastguard Workeraccessible through the `rust_gtest_interop` target which is automatically 6*6777b538SAndroid Build Coastguard Workerincluded in test targets that depend on `//testing/gtest`. 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker## To add rust unittests to a C++ Gtest target 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard WorkerA typical Gtest target is defined in a BUILD.gn file, with something like this: 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard Worker`BUILD.gn`: 13*6777b538SAndroid Build Coastguard Worker```gn 14*6777b538SAndroid Build Coastguard Workertest("some_unittests") { 15*6777b538SAndroid Build Coastguard Worker sources = [ 16*6777b538SAndroid Build Coastguard Worker "a_cpp_file.cc", 17*6777b538SAndroid Build Coastguard Worker "another_cpp_file.cc", 18*6777b538SAndroid Build Coastguard Worker ] 19*6777b538SAndroid Build Coastguard Worker deps = [ 20*6777b538SAndroid Build Coastguard Worker "//testing/gtest", 21*6777b538SAndroid Build Coastguard Worker ] 22*6777b538SAndroid Build Coastguard Worker} 23*6777b538SAndroid Build Coastguard Worker``` 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard WorkerTo add a Rust file to the test suite, simply add it to the `sources`. Unlike 26*6777b538SAndroid Build Coastguard Workerother Rust crates, the `crate_root` is not specified, since it is generated from 27*6777b538SAndroid Build Coastguard Workerthe sources list. 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard Worker`BUILD.gn`: 30*6777b538SAndroid Build Coastguard Worker```gn 31*6777b538SAndroid Build Coastguard Workertest("some_unittests") { 32*6777b538SAndroid Build Coastguard Worker sources = [ 33*6777b538SAndroid Build Coastguard Worker "a_cpp_file.cc", 34*6777b538SAndroid Build Coastguard Worker "another_cpp_file.cc", 35*6777b538SAndroid Build Coastguard Worker "a_rust_file.rs", 36*6777b538SAndroid Build Coastguard Worker ] 37*6777b538SAndroid Build Coastguard Worker deps = [ 38*6777b538SAndroid Build Coastguard Worker "//testing/gtest", 39*6777b538SAndroid Build Coastguard Worker ] 40*6777b538SAndroid Build Coastguard Worker} 41*6777b538SAndroid Build Coastguard Worker``` 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard WorkerTransitively depending on a `rust_static_library` will include its tests 44*6777b538SAndroid Build Coastguard Worker(similarly to tests authored in C++), although in that case the 45*6777b538SAndroid Build Coastguard Worker`rust_static_library` should explicitly declare its dependency on 46*6777b538SAndroid Build Coastguard Worker`//testing/rust_gtest_interop` and set `testonly` as well as 47*6777b538SAndroid Build Coastguard Worker`is_gtest_unittests`. 48*6777b538SAndroid Build Coastguard Worker 49*6777b538SAndroid Build Coastguard Worker```gn 50*6777b538SAndroid Build Coastguard Workerrust_static_library("my_rust_lib_unittests") { 51*6777b538SAndroid Build Coastguard Worker testonly = true 52*6777b538SAndroid Build Coastguard Worker is_gtest_unittests = true 53*6777b538SAndroid Build Coastguard Worker crate_root = "my_rust_lib_unittest.rs" 54*6777b538SAndroid Build Coastguard Worker sources = [ "my_rust_lib_unittest.rs" ] 55*6777b538SAndroid Build Coastguard Worker deps = [ 56*6777b538SAndroid Build Coastguard Worker ":my_rust_lib", 57*6777b538SAndroid Build Coastguard Worker "//testing/rust_gtest_interop", 58*6777b538SAndroid Build Coastguard Worker ] 59*6777b538SAndroid Build Coastguard Worker} 60*6777b538SAndroid Build Coastguard Worker 61*6777b538SAndroid Build Coastguard Workertest("some_unittests") { 62*6777b538SAndroid Build Coastguard Worker ... 63*6777b538SAndroid Build Coastguard Worker deps += [ ":my_rust_lib_unittests" ] 64*6777b538SAndroid Build Coastguard Worker} 65*6777b538SAndroid Build Coastguard Worker``` 66*6777b538SAndroid Build Coastguard Worker 67*6777b538SAndroid Build Coastguard Worker## To write a Gtest unit test in Rust 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard WorkerTo write a unit test, you simply write a function an decorate it with the 70*6777b538SAndroid Build Coastguard Worker`#[gtest]` macro. The macro takes 2 arguments, which are the test suite name and 71*6777b538SAndroid Build Coastguard Workerthe test name, just like the C++ `TEST()` macro. 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard WorkerThe `#[gtest]` macro is provided by the `rust_gtest_interop` crate, and is 74*6777b538SAndroid Build Coastguard Workerexported in the `prelude` module. Typically a unit test file would start with 75*6777b538SAndroid Build Coastguard Worker`use rust_gtest_interop::prelude::*;` which includes all of the available 76*6777b538SAndroid Build Coastguard Workergtest macros. This is similar to writing `#include 77*6777b538SAndroid Build Coastguard Worker"testing/gtest/include/gtest/gtest.h"` in C++. 78*6777b538SAndroid Build Coastguard Worker 79*6777b538SAndroid Build Coastguard WorkerA Rust test: 80*6777b538SAndroid Build Coastguard Worker```rs 81*6777b538SAndroid Build Coastguard Workeruse rust_gtest_interop::prelude::*; // Provides all the gtest macros. 82*6777b538SAndroid Build Coastguard Worker 83*6777b538SAndroid Build Coastguard Worker#[gtest(MyTestSuite, MyTestOfThing)] 84*6777b538SAndroid Build Coastguard Workerfn test() { 85*6777b538SAndroid Build Coastguard Worker ... 86*6777b538SAndroid Build Coastguard Worker} 87*6777b538SAndroid Build Coastguard Worker``` 88*6777b538SAndroid Build Coastguard Worker 89*6777b538SAndroid Build Coastguard WorkerA C++ test: 90*6777b538SAndroid Build Coastguard Worker```cpp 91*6777b538SAndroid Build Coastguard Worker#include "testing/gtest/include/gtest/gtest.h" // Provides all the gtest macros. 92*6777b538SAndroid Build Coastguard Worker 93*6777b538SAndroid Build Coastguard WorkerTEST(MyTestSuite, MyTestOfThing) { 94*6777b538SAndroid Build Coastguard Worker ... 95*6777b538SAndroid Build Coastguard Worker} 96*6777b538SAndroid Build Coastguard Worker``` 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker### Expectations 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard WorkerWe have access to many of the same EXPECT macros in Rust that are familiar to 101*6777b538SAndroid Build Coastguard WorkerC++ Gtest users, though they are used with Rust's macro syntax. 102*6777b538SAndroid Build Coastguard Worker 103*6777b538SAndroid Build Coastguard WorkerThe macros currently available are: 104*6777b538SAndroid Build Coastguard Worker```rs 105*6777b538SAndroid Build Coastguard Workerexpect_true!(is_friday()); 106*6777b538SAndroid Build Coastguard Workerexpect_false!(is_saturday()); 107*6777b538SAndroid Build Coastguard Worker 108*6777b538SAndroid Build Coastguard Workerexpect_eq!(2, 1 + 1); // A == B 109*6777b538SAndroid Build Coastguard Workerexpect_ne!(3, 1 + 2); // A != B 110*6777b538SAndroid Build Coastguard Worker 111*6777b538SAndroid Build Coastguard Workerexpect_lt!(1 * 1, 1 * 2); // A < B 112*6777b538SAndroid Build Coastguard Workerexpect_gt!(4 * 1, 1 * 2); // A > B 113*6777b538SAndroid Build Coastguard Workerexpect_le!(2 * 1, 1 * 2); // A <= B 114*6777b538SAndroid Build Coastguard Workerexpect_ge!(3 * 1, 2 * 3); // A >= B 115*6777b538SAndroid Build Coastguard Worker``` 116*6777b538SAndroid Build Coastguard Worker 117*6777b538SAndroid Build Coastguard Worker### Returning a Result 118*6777b538SAndroid Build Coastguard Worker 119*6777b538SAndroid Build Coastguard WorkerA C++ test always returns void and Rust tests usually do as well. But if your 120*6777b538SAndroid Build Coastguard Workertest calls a function that returns `Result`, it is convenient to make use of the 121*6777b538SAndroid Build Coastguard Worker[`?` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator) 122*6777b538SAndroid Build Coastguard Workerinstead of checking the Result value explicitly. Thus a test can either return: 123*6777b538SAndroid Build Coastguard Worker 124*6777b538SAndroid Build Coastguard Worker1. `()` aka void. 125*6777b538SAndroid Build Coastguard Worker1. `std::result::Result<(), E>` for any `E` that can be converted to a 126*6777b538SAndroid Build Coastguard Worker `std::error::Error`. (Or in Rust parlance, for any `E` for which there is 127*6777b538SAndroid Build Coastguard Worker `Into<std::error::Error>`). Common error types are `std::io::Error` or 128*6777b538SAndroid Build Coastguard Worker `String`. 129*6777b538SAndroid Build Coastguard Worker 130*6777b538SAndroid Build Coastguard WorkerIf the test with a `std::result::Result` return type returns `Result::Err`, the 131*6777b538SAndroid Build Coastguard Workertest will fail and display the error. 132*6777b538SAndroid Build Coastguard Worker 133*6777b538SAndroid Build Coastguard WorkerIn this example, the test will fail if it can not read from `file.txt`, or if it 134*6777b538SAndroid Build Coastguard Workerdoes not contain `"hello world"`: 135*6777b538SAndroid Build Coastguard Worker```rs 136*6777b538SAndroid Build Coastguard Worker#[gtest(TestingIO, ReadFile)] 137*6777b538SAndroid Build Coastguard Workerfn test() -> std::io::Result { 138*6777b538SAndroid Build Coastguard Worker let s = std::fs::read_to_string("file.txt")?; 139*6777b538SAndroid Build Coastguard Worker expect_eq!(s, "hello world"); 140*6777b538SAndroid Build Coastguard Worker Ok(()) 141*6777b538SAndroid Build Coastguard Worker} 142*6777b538SAndroid Build Coastguard Worker``` 143*6777b538SAndroid Build Coastguard Worker 144*6777b538SAndroid Build Coastguard Worker### Shared helper utilities 145*6777b538SAndroid Build Coastguard Worker 146*6777b538SAndroid Build Coastguard WorkerSometimes tests across different test files want to share helper utilities. Such 147*6777b538SAndroid Build Coastguard Workerhelpers should be placed in a separate GN target, typically named with a 148*6777b538SAndroid Build Coastguard Worker`_test_support` suffix, such as `starship_test_support` for the 149*6777b538SAndroid Build Coastguard Worker`starship_unittests`. And would also usually be found in a `test/` subdirectory. 150*6777b538SAndroid Build Coastguard Worker 151*6777b538SAndroid Build Coastguard Worker#### Example 152*6777b538SAndroid Build Coastguard WorkerThe `starship_unittests` test() target would include any unit test files, such as 153*6777b538SAndroid Build Coastguard Worker`starship_unittest.rs`. And the `starship_test_support` `rust_static_library()` 154*6777b538SAndroid Build Coastguard WorkerGN target would include the files in the `test/` subdirectory, such as 155*6777b538SAndroid Build Coastguard Worker`starship_test_helper.rs` and `starship_test_things.rs`. 156*6777b538SAndroid Build Coastguard Worker``` 157*6777b538SAndroid Build Coastguard Workersrc/ 158*6777b538SAndroid Build Coastguard Worker starship/ 159*6777b538SAndroid Build Coastguard Worker starship_unittest.rs 160*6777b538SAndroid Build Coastguard Worker test/ 161*6777b538SAndroid Build Coastguard Worker starship_test_helper.rs 162*6777b538SAndroid Build Coastguard Worker starship_test_things.rs 163*6777b538SAndroid Build Coastguard Worker``` 164