tokio_test/
macros.rs

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}