claims/
assert_err_eq.rs

1/// Asserts that the left expression contains an [`Err(E)`] variant and its contained value of type
2/// `E` equals the right expression.
3///
4/// ## Uses
5///
6/// Assertions are always checked in both debug and release builds, and cannot be disabled. See
7/// [`debug_assert_err_eq!`] 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/// # fn main() {
19/// let res: Result<(), i32> = Err(1);
20///
21/// assert_err_eq!(res, 1);
22///
23/// // With a custom message
24/// assert_err_eq!(res, 1, "Everything is good with {:?}", res);
25/// # }
26/// ```
27///
28/// The contained value will be returned from the macro call:
29///
30/// ```rust
31/// # #[macro_use] extern crate claims;
32/// # fn main() {
33/// let res: Result<(), i32> = Err(1);
34///
35/// let value = assert_err_eq!(res, 1);
36/// assert_eq!(value, 1);
37/// # }
38/// ```
39///
40/// An `Ok(_)` variant will panic:
41///
42/// ```rust,should_panic
43/// # #[macro_use] extern crate claims;
44/// # fn main() {
45/// let res: Result<(), i32> = Ok(());
46///
47/// assert_err_eq!(res, 1);  // Will panic
48/// # }
49/// ```
50///
51/// [`Err(E)`]: https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err
52/// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html
53/// [`debug_assert_err_eq!`]: crate::debug_assert_err_eq!
54#[macro_export]
55macro_rules! assert_err_eq {
56    ($cond:expr, $expected:expr $(,)?) => {
57        match $cond {
58            ::core::result::Result::Err(t) => {
59                ::core::assert_eq!(t, $expected);
60                t
61            },
62            ok @ ::core::result::Result::Ok(_) => {
63                ::core::panic!("assertion failed, expected Err(_), got {:?}", ok);
64            }
65        }
66    };
67    ($cond:expr, $expected:expr, $($arg:tt)+) => {
68        match $cond {
69            ::core::result::Result::Err(t) => {
70                ::core::assert_eq!(t, $expected, $($arg)+);
71                t
72            },
73            ok @ ::core::result::Result::Ok(_) => {
74                ::core::panic!("assertion failed, expected Err(_), got {:?}: {}", ok, ::core::format_args!($($arg)+));
75            }
76        }
77    };
78}
79
80/// Asserts that the left expression contains an [`Err(E)`] variant and its contained value of type
81/// `E` equals the right expression in debug builds.
82///
83/// This macro behaves nearly the same as [`assert_err_eq!`] on debug builds, although it does not
84/// return the value contained in the `Err` variant. On release builds it is a no-op.
85///
86/// [`Err(E)`]: https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err
87#[macro_export]
88macro_rules! debug_assert_err_eq {
89    ($($arg:tt)*) => {
90        #[cfg(debug_assertions)]
91        $crate::assert_err_eq!($($arg)*);
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    #[test]
98    fn equal() {
99        assert_err_eq!(Err::<(), _>(42), 42);
100    }
101
102    #[test]
103    #[should_panic]
104    fn not_equal() {
105        assert_err_eq!(Err::<(), _>(42), 100);
106    }
107
108    #[test]
109    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(())")]
110    fn not_err() {
111        assert_err_eq!(Ok::<_, usize>(()), 42);
112    }
113
114    #[test]
115    #[should_panic(expected = "foo")]
116    fn not_equal_custom_message() {
117        assert_err_eq!(Err::<(), _>(1), 2, "foo");
118    }
119
120    #[test]
121    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(()): foo")]
122    fn not_err_custom_message() {
123        assert_err_eq!(Ok::<_, usize>(()), 2, "foo");
124    }
125
126    #[test]
127    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
128    fn debug_equal() {
129        debug_assert_err_eq!(Err::<(), _>(42), 42);
130    }
131
132    #[test]
133    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
134    #[should_panic]
135    fn debug_not_equal() {
136        debug_assert_err_eq!(Err::<(), _>(42), 100);
137    }
138
139    #[test]
140    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
141    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(())")]
142    fn debug_not_err() {
143        debug_assert_err_eq!(Ok::<_, usize>(()), 42);
144    }
145
146    #[test]
147    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
148    #[should_panic(expected = "foo")]
149    fn debug_not_equal_custom_message() {
150        debug_assert_err_eq!(Err::<(), _>(1), 2, "foo");
151    }
152
153    #[test]
154    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
155    #[should_panic(expected = "assertion failed, expected Err(_), got Ok(()): foo")]
156    fn debug_not_err_custom_message() {
157        debug_assert_err_eq!(Ok::<_, usize>(()), 2, "foo");
158    }
159
160    #[test]
161    #[cfg_attr(debug_assertions, ignore = "only run in release mode")]
162    fn debug_release_not_equal() {
163        debug_assert_err_eq!(Err::<(), _>(42), 100);
164    }
165
166    #[test]
167    #[cfg_attr(debug_assertions, ignore = "only run in release mode")]
168    fn debug_release_not_err() {
169        debug_assert_err_eq!(Ok::<_, usize>(()), 42);
170    }
171}