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 ] |
23 | macro_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 ] |
62 | macro_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 ] |
95 | macro_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 ] |
128 | macro_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 ] |
167 | macro_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 ] |
200 | macro_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 ] |
243 | macro_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 ] |
281 | macro_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 | |