claims/
assert_err.rs

1/// Asserts that the expression matches an [`Err(_)`] variant, returning the contained value.
2///
3/// ## Uses
4///
5/// Assertions are always checked in both debug and release builds, and cannot be disabled.
6/// See [`debug_assert_err!`] for assertions that are not enabled in release builds by default.
7///
8/// ## Custom messages
9///
10/// This macro has a second form, where a custom panic message can be provided
11/// with or without arguments for formatting. See [`std::fmt`] for syntax for this form.
12///
13/// ## Examples
14///
15/// ```rust
16/// # #[macro_use] extern crate claims;
17/// # fn main() {
18/// let res: Result<i32, ()> = Err(());
19///
20/// assert_err!(res);
21///
22/// // With a custom message.
23/// assert_err!(res, "we are checking if there was an error with {:?}", res);
24/// # }
25/// ```
26///
27/// An `Ok(_)` variant will panic:
28///
29/// ```rust,should_panic
30/// # #[macro_use] extern crate claims;
31/// # fn main() {
32/// let res: Result<i32, ()> = Ok(42);
33///
34/// assert_err!(res);  // Will panic
35/// # }
36/// ```
37///
38/// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html
39/// [`Err(_)`]: https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err
40/// [`debug_assert_err!`]: crate::debug_assert_err!
41#[macro_export]
42macro_rules! assert_err {
43    ($cond:expr $(,)?) => {
44        match $cond {
45            ::core::result::Result::Err(e) => e,
46            ::core::result::Result::Ok(t) => ::core::panic!("assertion failed, expected Err(_), got Ok({:?})", t),
47        }
48    };
49    ($cond:expr, $($arg:tt)+) => {
50        match $cond {
51            ::core::result::Result::Err(e) => e,
52            ::core::result::Result::Ok(t) => ::core::panic!("assertion failed, expected Err(_), got Ok({:?}): {}", t, ::core::format_args!($($arg)+)),
53        }
54    };
55}
56
57/// Asserts that the expression matches an [`Err(_)`] variant in debug builds.
58///
59/// This macro behaves nearly the same as [`assert_err!`] on debug builds, although it does not
60/// return the value contained in the `Err` variant. On release builds it is a no-op.
61///
62/// [`Err(_)`]: https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err
63#[macro_export]
64macro_rules! debug_assert_err {
65    ($($arg:tt)*) => {
66        #[cfg(debug_assertions)]
67        $crate::assert_err!($($arg)*);
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    #[test]
74    fn err() {
75        assert_err!(Err::<(), _>(()));
76    }
77
78    #[test]
79    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(())")]
80    fn not_err() {
81        assert_err!(Ok::<_, ()>(()));
82    }
83
84    #[test]
85    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(()): foo")]
86    fn not_err_custom_message() {
87        assert_err!(Ok::<_, ()>(()), "foo");
88    }
89
90    #[test]
91    fn err_value_returned() {
92        let value = assert_err!(Err::<(), _>(42));
93        assert_eq!(value, 42);
94    }
95
96    #[test]
97    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
98    fn debug_err() {
99        debug_assert_err!(Err::<(), _>(()));
100    }
101
102    #[test]
103    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
104    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(())")]
105    fn debug_not_err() {
106        debug_assert_err!(Ok::<_, ()>(()));
107    }
108
109    #[test]
110    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
111    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(()): foo")]
112    fn debug_not_err_custom_message() {
113        debug_assert_err!(Ok::<_, ()>(()), "foo");
114    }
115
116    #[test]
117    #[cfg_attr(debug_assertions, ignore = "only run in release mode")]
118    fn debug_release_not_err() {
119        debug_assert_err!(Ok::<_, ()>(()));
120    }
121
122    #[test]
123    fn does_not_require_err_to_impl_debug() {
124        enum Foo {
125            Bar,
126        }
127
128        assert_err!(Err::<(), _>(Foo::Bar));
129    }
130
131    #[test]
132    fn debug_does_not_require_err_to_impl_debug() {
133        #[allow(dead_code)]
134        enum Foo {
135            Bar,
136        }
137
138        debug_assert_err!(Err::<(), _>(Foo::Bar));
139    }
140
141    #[test]
142    fn does_not_require_err_to_impl_debug_custom_message() {
143        enum Foo {
144            Bar,
145        }
146
147        assert_err!(Err::<(), _>(Foo::Bar), "foo");
148    }
149
150    #[test]
151    fn debug_does_not_require_err_to_impl_debug_custom_message() {
152        #[allow(dead_code)]
153        enum Foo {
154            Bar,
155        }
156
157        debug_assert_err!(Err::<(), _>(Foo::Bar), "foo");
158    }
159}