claims/
assert_ready_err.rs

1/// Asserts that the expression matches a [`Poll::Ready(Err(_))`] variant, returning the contained
2/// value.
3///
4/// ## Uses
5///
6/// Assertions are always checked in both debug and release builds, and cannot be disabled.
7/// See [`debug_assert_ready_err!`] for assertions that are not enabled in release builds by default.
8///
9/// ## Custom messages
10///
11/// This macro has a second form, where a custom panic message can be provided with or without
12/// arguments for formatting. See [`std::fmt`] for syntax for this form.
13///
14/// ## Examples
15///
16/// ```rust
17/// # #[macro_use] extern crate claims;
18/// # #[cfg(feature = "std")] extern crate std as core;
19/// # use std::task::Poll;
20/// # fn main() {
21/// let res: Poll<Result<i32, ()>> = Poll::Ready(Err(()));
22///
23/// assert_ready_err!(res);
24/// # }
25/// ```
26///
27/// The contained value will also be returned from this macro call:
28///
29/// ```rust
30/// # #[macro_use] extern crate claims;
31/// # use std::task::Poll;
32/// # fn main() {
33/// let res: Poll<Result<i32, String>> = Poll::Ready(Err("Something went wrong".to_string()));
34///
35/// let message = assert_ready_err!(res);
36/// assert_eq!("Something went wrong", message);
37/// # }
38/// ```
39///
40/// Both `Poll::Ready(Ok(..))` and [`Poll::Pending`] variants will panic:
41///
42/// ```rust,should_panic
43/// # #[macro_use] extern crate claims;
44/// # use std::task::Poll;
45/// # fn main() {
46/// let res: Poll<Result<i32, ()>> = Poll::Ready(Ok(42));
47///
48/// assert_ready_err!(res);  // Will panic
49/// # }
50/// ```
51///
52/// ```rust,should_panic
53/// # #[macro_use] extern crate claims;
54/// # use std::task::Poll;
55/// # fn main() {
56/// let res: Poll<Result<i32, ()>> = Poll::Pending;
57///
58/// assert_ready_err!(res);  // Will panic
59/// # }
60/// ```
61///
62/// [`Poll::Ready(Err(_))`]: https://doc.rust-lang.org/core/task/enum.Poll.html#variant.Ready
63/// [`Poll::Pending`]: https://doc.rust-lang.org/core/task/enum.Poll.html#variant.Pending
64/// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html
65/// [`debug_assert_ready_err!`]: crate::debug_assert_ready_err!
66#[macro_export]
67macro_rules! assert_ready_err {
68    ($cond:expr $(,)?) => {
69        match $cond {
70            ::core::task::Poll::Ready(::core::result::Result::Err(e)) => e,
71            ::core::task::Poll::Ready(::core::result::Result::Ok(t)) => ::core::panic!("assertion failed, expected Ready(Err(_)), got Ready(Ok({:?}))", t),
72            ::core::task::Poll::Pending => ::core::panic!("assertion failed, expected Ready(Err(_)), got Pending"),
73        }
74    };
75    ($cond:expr, $($arg:tt)+) => {
76        match $cond {
77            ::core::task::Poll::Ready(::core::result::Result::Err(e)) => e,
78            ::core::task::Poll::Ready(::core::result::Result::Ok(t)) => ::core::panic!("assertion failed, expected Ready(Err(_)), got Ready(Ok({:?})): {}", t, ::core::format_args!($($arg)+)),
79            ::core::task::Poll::Pending => ::core::panic!("assertion failed, expected Ready(Err(_)), got Pending: {}", ::core::format_args!($($arg)+)),
80        }
81    };
82}
83
84/// Asserts that the expression matches a [`Poll::Ready(Err(_))`] variant on debug builds.
85///
86/// This macro behaves nearly the same as [`assert_ready_err!`] on debug builds, although it does not
87/// return the value contained in the `Poll::Ready(Err(_))` variant. On release builds it is a no-op.
88///
89/// [`Poll::Ready(Err(_))`]: https://doc.rust-lang.org/core/task/enum.Poll.html#variant.Ready
90#[macro_export]
91macro_rules! debug_assert_ready_err {
92    ($($arg:tt)*) => {
93        #[cfg(debug_assertions)]
94        $crate::assert_ready_err!($($arg)*);
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use core::task::Poll::{Pending, Ready};
101
102    #[test]
103    fn ready_err() {
104        assert_ready_err!(Ready(Err::<(), _>(())));
105    }
106
107    #[test]
108    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Ready(Ok(()))")]
109    fn ready_ok() {
110        assert_ready_err!(Ready(Ok::<_, ()>(())));
111    }
112
113    #[test]
114    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Pending")]
115    fn not_ready() {
116        assert_ready_err!(Pending::<Result<(), ()>>);
117    }
118
119    #[test]
120    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Ready(Ok(())): foo")]
121    fn ready_ok_custom_message() {
122        assert_ready_err!(Ready(Ok::<_, ()>(())), "foo");
123    }
124
125    #[test]
126    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Pending: foo")]
127    fn not_ready_custom_message() {
128        assert_ready_err!(Pending::<Result<(), ()>>, "foo");
129    }
130
131    #[test]
132    fn ready_err_value_returned() {
133        let value = assert_ready_err!(Ready(Err::<(), _>(42)));
134        assert_eq!(value, 42);
135    }
136
137    #[test]
138    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
139    fn debug_ready_err() {
140        debug_assert_ready_err!(Ready(Err::<(), _>(())));
141    }
142
143    #[test]
144    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
145    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Ready(Ok(()))")]
146    fn debug_ready_ok() {
147        debug_assert_ready_err!(Ready(Ok::<_, ()>(())));
148    }
149
150    #[test]
151    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
152    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Pending")]
153    fn debug_not_ready() {
154        debug_assert_ready_err!(Pending::<Result<(), ()>>);
155    }
156
157    #[test]
158    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
159    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Ready(Ok(())): foo")]
160    fn debug_ready_ok_custom_message() {
161        debug_assert_ready_err!(Ready(Ok::<_, ()>(())), "foo");
162    }
163
164    #[test]
165    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
166    #[should_panic(expected = "assertion failed, expected Ready(Err(_)), got Pending: foo")]
167    fn debug_not_ready_custom_message() {
168        debug_assert_ready_err!(Pending::<Result<(), ()>>, "foo");
169    }
170
171    #[test]
172    #[cfg_attr(debug_assertions, ignore = "only run in release mode")]
173    fn debug_release_ready_ok() {
174        debug_assert_ready_err!(Ready(Ok::<_, ()>(())));
175    }
176
177    #[test]
178    #[cfg_attr(debug_assertions, ignore = "only run in release mode")]
179    fn debug_release_not_ready() {
180        debug_assert_ready_err!(Pending::<Result<(), ()>>);
181    }
182
183    #[test]
184    fn does_not_require_err_to_impl_debug() {
185        enum Foo {
186            Bar,
187        }
188
189        assert_ready_err!(Ready(Err::<(), _>(Foo::Bar)));
190    }
191
192    #[test]
193    fn debug_does_not_require_err_to_impl_debug() {
194        #[allow(dead_code)]
195        enum Foo {
196            Bar,
197        }
198
199        debug_assert_ready_err!(Ready(Err::<(), _>(Foo::Bar)));
200    }
201
202    #[test]
203    fn does_not_require_err_to_impl_debug_custom_message() {
204        enum Foo {
205            Bar,
206        }
207
208        assert_ready_err!(Ready(Err::<(), _>(Foo::Bar)), "foo");
209    }
210
211    #[test]
212    fn debug_does_not_require_err_to_impl_debug_custom_message() {
213        #[allow(dead_code)]
214        enum Foo {
215            Bar,
216        }
217
218        debug_assert_ready_err!(Ready(Err::<(), _>(Foo::Bar)), "foo");
219    }
220}