assertables/assert_err/
assert_err_ne.rs

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