xref: /aosp_15_r20/external/cronet/testing/rust_gtest_interop/README.md (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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