assertables/assert_err/
assert_err_eq_x.rs

1//! Assert an expression is Err and its value is equal to an expression.
2//!
3//! Pseudocode:<br>
4//! (a ⇒ Err(a1) ⇒ a1) = b
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a: Result<i8, i8> = Err(1);
12//! let b: i8 = 1;
13//! assert_err_eq_x!(a, b);
14//! ```
15//!
16//! # Module macros
17//!
18//! * [`assert_err_eq_x`](macro@crate::assert_err_eq_x)
19//! * [`assert_err_eq_x_as_result`](macro@crate::assert_err_eq_x_as_result)
20//! * [`debug_assert_err_eq_x`](macro@crate::debug_assert_err_eq_x)
21
22/// Assert an expression is Err and its value is equal to an expression.
23///
24/// Pseudocode:<br>
25/// (a ⇒ Err(a1) ⇒ a1) = b
26///
27/// * If true, return Result `Ok(a1)`.
28///
29/// * Otherwise, return Result `Err(message)`.
30///
31/// This macro is useful for runtime checks, such as checking parameters,
32/// or sanitizing inputs, or handling different results in different ways.
33///
34/// # Module macros
35///
36/// * [`assert_err_eq_x`](macro@crate::assert_err_eq_x)
37/// * [`assert_err_eq_x_as_result`](macro@crate::assert_err_eq_x_as_result)
38/// * [`debug_assert_err_eq_x`](macro@crate::debug_assert_err_eq_x)
39///
40#[macro_export]
41macro_rules! assert_err_eq_x_as_result {
42    ($a:expr, $b:expr $(,)?) => {
43        match ($a, $b) {
44            (a, b) => match (a) {
45                Err(a1) => {
46                    if a1 == b {
47                        Ok(a1)
48                    } else {
49                        Err(format!(
50                            concat!(
51                                "assertion failed: `assert_err_eq_x!(a, b)`\n",
52                                "https://docs.rs/assertables/9.8.3/assertables/macro.assert_err_eq_x.html\n",
53                                " a label: `{}`,\n",
54                                " a debug: `{:?}`,\n",
55                                " a inner: `{:?}`,\n",
56                                " b label: `{}`,\n",
57                                " b debug: `{:?}`",
58                            ),
59                            stringify!($a),
60                            a,
61                            a1,
62                            stringify!($b),
63                            b
64                        ))
65                    }
66                }
67                _ => Err(format!(
68                    concat!(
69                        "assertion failed: `assert_err_eq_x!(a, b)`\n",
70                        "https://docs.rs/assertables/9.8.3/assertables/macro.assert_err_eq_x.html\n",
71                        " a label: `{}`,\n",
72                        " a debug: `{:?}`,\n",
73                        " b label: `{}`,\n",
74                        " b debug: `{:?}`",
75                    ),
76                    stringify!($a),
77                    a,
78                    stringify!($b),
79                    b,
80                )),
81            },
82        }
83    };
84}
85
86#[cfg(test)]
87mod test_assert_err_eq_x_as_result {
88    use std::sync::Once;
89
90    #[test]
91    fn eq() {
92        let a: Result<i8, i8> = Err(1);
93        let b: i8 = 1;
94        for _ in 0..1 {
95            let actual = assert_err_eq_x_as_result!(a, b);
96            assert_eq!(actual.unwrap(), 1);
97        }
98    }
99
100    #[test]
101    fn eq_once() {
102        static A: Once = Once::new();
103        fn a() -> Result<i8, i8> {
104            if A.is_completed() {
105                panic!("A.is_completed()")
106            } else {
107                A.call_once(|| {})
108            }
109            Err(1)
110        }
111
112        static B: Once = Once::new();
113        fn b() -> i8 {
114            if B.is_completed() {
115                panic!("B.is_completed()")
116            } else {
117                B.call_once(|| {})
118            }
119            1
120        }
121
122        assert_eq!(A.is_completed(), false);
123        assert_eq!(B.is_completed(), false);
124        let result = assert_err_eq_x_as_result!(a(), b());
125        assert!(result.is_ok());
126        assert_eq!(A.is_completed(), true);
127        assert_eq!(B.is_completed(), true);
128    }
129    #[test]
130    fn ne() {
131        let a: Result<i8, i8> = Err(1);
132        let b: i8 = 2;
133        let actual = assert_err_eq_x_as_result!(a, b);
134        let message = concat!(
135            "assertion failed: `assert_err_eq_x!(a, b)`\n",
136            "https://docs.rs/assertables/9.8.3/assertables/macro.assert_err_eq_x.html\n",
137            " a label: `a`,\n",
138            " a debug: `Err(1)`,\n",
139            " a inner: `1`,\n",
140            " b label: `b`,\n",
141            " b debug: `2`"
142        );
143        assert_eq!(actual.unwrap_err(), message);
144    }
145
146    #[test]
147    fn failure_because_not_err() {
148        let a: Result<i8, i8> = Ok(1);
149        let b: i8 = 1;
150        let actual = assert_err_eq_x_as_result!(a, b);
151        let message = concat!(
152            "assertion failed: `assert_err_eq_x!(a, b)`\n",
153            "https://docs.rs/assertables/9.8.3/assertables/macro.assert_err_eq_x.html\n",
154            " a label: `a`,\n",
155            " a debug: `Ok(1)`,\n",
156            " b label: `b`,\n",
157            " b debug: `1`",
158        );
159        assert_eq!(actual.unwrap_err(), message);
160    }
161}
162
163/// Assert an expression is Err and its value is equal to an expression.
164///
165/// Pseudocode:<br>
166/// (a ⇒ Err(a1) ⇒ a1) = b
167///
168/// * If true, return `a1`.
169///
170/// * Otherwise, call [`panic!`] with a message and the values of the
171///   expressions with their debug representations.
172///
173/// # Examples
174///
175/// ```rust
176/// use assertables::*;
177/// # use std::panic;
178///
179/// # fn main() {
180/// let a: Result<i8, i8> = Err(1);
181/// let b: i8 = 1;
182/// assert_err_eq_x!(a, b);
183///
184/// # let result = panic::catch_unwind(|| {
185/// // This will panic
186/// let a: Result<i8, i8> = Err(1);
187/// let b: i8 = 2;
188/// assert_err_eq_x!(a, b);
189/// # });
190/// // assertion failed: `assert_err_eq_x!(a, b)`
191/// // https://docs.rs/assertables/…/assertables/macro.assert_err_eq_x.html
192/// //  a label: `a`,
193/// //  a debug: `Err(1)`,
194/// //  a inner: `1`,
195/// //  b label: `b`,
196/// //  b debug: `2`
197/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
198/// # let message = concat!(
199/// #     "assertion failed: `assert_err_eq_x!(a, b)`\n",
200/// #     "https://docs.rs/assertables/9.8.3/assertables/macro.assert_err_eq_x.html\n",
201/// #     " a label: `a`,\n",
202/// #     " a debug: `Err(1)`,\n",
203/// #     " a inner: `1`,\n",
204/// #     " b label: `b`,\n",
205/// #     " b debug: `2`",
206/// # );
207/// # assert_eq!(actual, message);
208/// # }
209/// ```
210///
211/// # Module macros
212///
213/// * [`assert_err_eq_x`](macro@crate::assert_err_eq_x)
214/// * [`assert_err_eq_x_as_result`](macro@crate::assert_err_eq_x_as_result)
215/// * [`debug_assert_err_eq_x`](macro@crate::debug_assert_err_eq_x)
216///
217#[macro_export]
218macro_rules! assert_err_eq_x {
219    ($a:expr, $b:expr $(,)?) => {
220        match $crate::assert_err_eq_x_as_result!($a, $b) {
221            Ok(x) => x,
222            Err(err) => panic!("{}", err),
223        }
224    };
225    ($a:expr, $b:expr, $($message:tt)+) => {
226        match $crate::assert_err_eq_x_as_result!($a, $b) {
227            Ok(x) => x,
228            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
229        }
230    };
231}
232
233#[cfg(test)]
234mod test_assert_err_eq_x {
235    use std::panic;
236
237    #[test]
238    fn success() {
239        let a: Result<i8, i8> = Err(1);
240        let b: i8 = 1;
241        for _ in 0..1 {
242            let actual = assert_err_eq_x!(a, b);
243            assert_eq!(actual, 1);
244        }
245    }
246
247    #[test]
248    fn ne() {
249        let result = panic::catch_unwind(|| {
250            let a: Result<i8, i8> = Err(1);
251            let b: i8 = 2;
252            let _actual = assert_err_eq_x!(a, b);
253        });
254        let message = concat!(
255            "assertion failed: `assert_err_eq_x!(a, b)`\n",
256            "https://docs.rs/assertables/9.8.3/assertables/macro.assert_err_eq_x.html\n",
257            " a label: `a`,\n",
258            " a debug: `Err(1)`,\n",
259            " a inner: `1`,\n",
260            " b label: `b`,\n",
261            " b debug: `2`"
262        );
263        assert_eq!(
264            result
265                .unwrap_err()
266                .downcast::<String>()
267                .unwrap()
268                .to_string(),
269            message
270        );
271    }
272
273    #[test]
274    fn failure_because_not_err() {
275        let result = panic::catch_unwind(|| {
276            let a: Result<i8, i8> = Ok(1);
277            let b: i8 = 1;
278            let _actual = assert_err_eq_x!(a, b);
279        });
280        let message = concat!(
281            "assertion failed: `assert_err_eq_x!(a, b)`\n",
282            "https://docs.rs/assertables/9.8.3/assertables/macro.assert_err_eq_x.html\n",
283            " a label: `a`,\n",
284            " a debug: `Ok(1)`,\n",
285            " b label: `b`,\n",
286            " b debug: `1`",
287        );
288        assert_eq!(
289            result
290                .unwrap_err()
291                .downcast::<String>()
292                .unwrap()
293                .to_string(),
294            message
295        );
296    }
297}
298
299/// Assert an expression is Err and its value is equal to an expression.
300///
301/// Pseudocode:<br>
302/// (a ⇒ Err(a1) ⇒ a1) = b
303///
304/// This macro provides the same statements as [`assert_err_eq_x`](macro.assert_err_eq_x.html),
305/// except this macro's statements are only enabled in non-optimized
306/// builds by default. An optimized build will not execute this macro's
307/// statements unless `-C debug-assertions` is passed to the compiler.
308///
309/// This macro is useful for checks that are too expensive to be present
310/// in a release build but may be helpful during development.
311///
312/// The result of expanding this macro is always type checked.
313///
314/// An unchecked assertion allows a program in an inconsistent state to
315/// keep running, which might have unexpected consequences but does not
316/// introduce unsafety as long as this only happens in safe code. The
317/// performance cost of assertions, however, is not measurable in general.
318/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
319/// after thorough profiling, and more importantly, only in safe code!
320///
321/// This macro is intended to work in a similar way to
322/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
323///
324/// # Module macros
325///
326/// * [`assert_err_eq_x`](macro@crate::assert_err_eq_x)
327/// * [`assert_err_eq_x`](macro@crate::assert_err_eq_x)
328/// * [`debug_assert_err_eq_x`](macro@crate::debug_assert_err_eq_x)
329///
330#[macro_export]
331macro_rules! debug_assert_err_eq_x {
332    ($($arg:tt)*) => {
333        if $crate::cfg!(debug_assertions) {
334            $crate::assert_err_eq_x!($($arg)*);
335        }
336    };
337}