1//! A collection of useful macros for testing futures and tokio based code
2
3/// Asserts a `Poll` is ready, returning the value.
4///
5/// This will invoke `panic!` if the provided `Poll` does not evaluate to `Poll::Ready` at
6/// runtime.
7///
8/// # Custom Messages
9///
10/// This macro has a second form, where a custom panic message can be provided with or without
11/// arguments for formatting.
12///
13/// # Examples
14///
15/// ```
16/// use futures_util::future;
17/// use tokio_test::{assert_ready, task};
18///
19/// let mut fut = task::spawn(future::ready(()));
20/// assert_ready!(fut.poll());
21/// ```
22#[macro_export]
23macro_rules! assert_ready {
24 ($e:expr) => {{
25 use core::task::Poll;
26 match $e {
27 Poll::Ready(v) => v,
28 Poll::Pending => panic!("pending"),
29 }
30 }};
31 ($e:expr, $($msg:tt)+) => {{
32 use core::task::Poll;
33 match $e {
34 Poll::Ready(v) => v,
35 Poll::Pending => {
36 panic!("pending; {}", format_args!($($msg)+))
37 }
38 }
39 }};
40}
41
42/// Asserts a `Poll<Result<...>>` is ready and `Ok`, returning the value.
43///
44/// This will invoke `panic!` if the provided `Poll` does not evaluate to `Poll::Ready(Ok(..))` at
45/// runtime.
46///
47/// # Custom Messages
48///
49/// This macro has a second form, where a custom panic message can be provided with or without
50/// arguments for formatting.
51///
52/// # Examples
53///
54/// ```
55/// use futures_util::future;
56/// use tokio_test::{assert_ready_ok, task};
57///
58/// let mut fut = task::spawn(future::ok::<_, ()>(()));
59/// assert_ready_ok!(fut.poll());
60/// ```
61#[macro_export]
62macro_rules! assert_ready_ok {
63 ($e:expr) => {{
64 use tokio_test::{assert_ready, assert_ok};
65 let val = assert_ready!($e);
66 assert_ok!(val)
67 }};
68 ($e:expr, $($msg:tt)+) => {{
69 use tokio_test::{assert_ready, assert_ok};
70 let val = assert_ready!($e, $($msg)*);
71 assert_ok!(val, $($msg)*)
72 }};
73}
74
75/// Asserts a `Poll<Result<...>>` is ready and `Err`, returning the error.
76///
77/// This will invoke `panic!` if the provided `Poll` does not evaluate to `Poll::Ready(Err(..))` at
78/// runtime.
79///
80/// # Custom Messages
81///
82/// This macro has a second form, where a custom panic message can be provided with or without
83/// arguments for formatting.
84///
85/// # Examples
86///
87/// ```
88/// use futures_util::future;
89/// use tokio_test::{assert_ready_err, task};
90///
91/// let mut fut = task::spawn(future::err::<(), _>(()));
92/// assert_ready_err!(fut.poll());
93/// ```
94#[macro_export]
95macro_rules! assert_ready_err {
96 ($e:expr) => {{
97 use tokio_test::{assert_ready, assert_err};
98 let val = assert_ready!($e);
99 assert_err!(val)
100 }};
101 ($e:expr, $($msg:tt)+) => {{
102 use tokio_test::{assert_ready, assert_err};
103 let val = assert_ready!($e, $($msg)*);
104 assert_err!(val, $($msg)*)
105 }};
106}
107
108/// Asserts a `Poll` is pending.
109///
110/// This will invoke `panic!` if the provided `Poll` does not evaluate to `Poll::Pending` at
111/// runtime.
112///
113/// # Custom Messages
114///
115/// This macro has a second form, where a custom panic message can be provided with or without
116/// arguments for formatting.
117///
118/// # Examples
119///
120/// ```
121/// use futures_util::future;
122/// use tokio_test::{assert_pending, task};
123///
124/// let mut fut = task::spawn(future::pending::<()>());
125/// assert_pending!(fut.poll());
126/// ```
127#[macro_export]
128macro_rules! assert_pending {
129 ($e:expr) => {{
130 use core::task::Poll;
131 match $e {
132 Poll::Pending => {}
133 Poll::Ready(v) => panic!("ready; value = {:?}", v),
134 }
135 }};
136 ($e:expr, $($msg:tt)+) => {{
137 use core::task::Poll;
138 match $e {
139 Poll::Pending => {}
140 Poll::Ready(v) => {
141 panic!("ready; value = {:?}; {}", v, format_args!($($msg)+))
142 }
143 }
144 }};
145}
146
147/// Asserts if a poll is ready and check for equality on the value
148///
149/// This will invoke `panic!` if the provided `Poll` does not evaluate to `Poll::Ready` at
150/// runtime and the value produced does not partially equal the expected value.
151///
152/// # Custom Messages
153///
154/// This macro has a second form, where a custom panic message can be provided with or without
155/// arguments for formatting.
156///
157/// # Examples
158///
159/// ```
160/// use futures_util::future;
161/// use tokio_test::{assert_ready_eq, task};
162///
163/// let mut fut = task::spawn(future::ready(42));
164/// assert_ready_eq!(fut.poll(), 42);
165/// ```
166#[macro_export]
167macro_rules! assert_ready_eq {
168 ($e:expr, $expect:expr) => {
169 let val = $crate::assert_ready!($e);
170 assert_eq!(val, $expect)
171 };
172
173 ($e:expr, $expect:expr, $($msg:tt)+) => {
174 let val = $crate::assert_ready!($e, $($msg)*);
175 assert_eq!(val, $expect, $($msg)*)
176 };
177}
178
179/// Asserts that the expression evaluates to `Ok` and returns the value.
180///
181/// This will invoke the `panic!` macro if the provided expression does not evaluate to `Ok` at
182/// runtime.
183///
184/// # Custom Messages
185///
186/// This macro has a second form, where a custom panic message can be provided with or without
187/// arguments for formatting.
188///
189/// # Examples
190///
191/// ```
192/// use tokio_test::assert_ok;
193///
194/// let n: u32 = assert_ok!("123".parse());
195///
196/// let s = "123";
197/// let n: u32 = assert_ok!(s.parse(), "testing parsing {:?} as a u32", s);
198/// ```
199#[macro_export]
200macro_rules! assert_ok {
201 ($e:expr) => {
202 assert_ok!($e,)
203 };
204 ($e:expr,) => {{
205 use std::result::Result::*;
206 match $e {
207 Ok(v) => v,
208 Err(e) => panic!("assertion failed: Err({:?})", e),
209 }
210 }};
211 ($e:expr, $($arg:tt)+) => {{
212 use std::result::Result::*;
213 match $e {
214 Ok(v) => v,
215 Err(e) => panic!("assertion failed: Err({:?}): {}", e, format_args!($($arg)+)),
216 }
217 }};
218}
219
220/// Asserts that the expression evaluates to `Err` and returns the error.
221///
222/// This will invoke the `panic!` macro if the provided expression does not evaluate to `Err` at
223/// runtime.
224///
225/// # Custom Messages
226///
227/// This macro has a second form, where a custom panic message can be provided with or without
228/// arguments for formatting.
229///
230/// # Examples
231///
232/// ```
233/// use tokio_test::assert_err;
234/// use std::str::FromStr;
235///
236///
237/// let err = assert_err!(u32::from_str("fail"));
238///
239/// let msg = "fail";
240/// let err = assert_err!(u32::from_str(msg), "testing parsing {:?} as u32", msg);
241/// ```
242#[macro_export]
243macro_rules! assert_err {
244 ($e:expr) => {
245 assert_err!($e,);
246 };
247 ($e:expr,) => {{
248 use std::result::Result::*;
249 match $e {
250 Ok(v) => panic!("assertion failed: Ok({:?})", v),
251 Err(e) => e,
252 }
253 }};
254 ($e:expr, $($arg:tt)+) => {{
255 use std::result::Result::*;
256 match $e {
257 Ok(v) => panic!("assertion failed: Ok({:?}): {}", v, format_args!($($arg)+)),
258 Err(e) => e,
259 }
260 }};
261}
262
263/// Asserts that an exact duration has elapsed since the start instant ±1ms.
264///
265/// ```rust
266/// use tokio::time::{self, Instant};
267/// use std::time::Duration;
268/// use tokio_test::assert_elapsed;
269/// # async fn test_time_passed() {
270///
271/// let start = Instant::now();
272/// let dur = Duration::from_millis(50);
273/// time::sleep(dur).await;
274/// assert_elapsed!(start, dur);
275/// # }
276/// ```
277///
278/// This 1ms buffer is required because Tokio's hashed-wheel timer has finite time resolution and
279/// will not always sleep for the exact interval.
280#[macro_export]
281macro_rules! assert_elapsed {
282 ($start:expr, $dur:expr) => {{
283 let elapsed = $start.elapsed();
284 // type ascription improves compiler error when wrong type is passed
285 let lower: std::time::Duration = $dur;
286
287 // Handles ms rounding
288 assert!(
289 elapsed >= lower && elapsed <= lower + std::time::Duration::from_millis(1),
290 "actual = {:?}, expected = {:?}",
291 elapsed,
292 lower
293 );
294 }};
295}
296