assertables/assert_fn_err/
assert_fn_err_eq.rs

1//! Assert a function Err(…) is equal to another.
2//!
3//! Pseudocode:<br>
4//! (a_function(a_param) ⇒ Err(a) ⇒ a) = (b_function(b_param) ⇒ Err(b) ⇒ b)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//! fn f(i: i8) -> Result<String, String> {
11//!     match i {
12//!         0..=9 => Ok(format!("{}", i)),
13//!         _ => Err(format!("{:?} is out of range", i)),
14//!     }
15//! }
16//!
17//! let a: i8 = 10;
18//! let b: i8 = 10;
19//! assert_fn_err_eq!(f, a, f, b);
20//! ```
21//!
22//! # Module macros
23//!
24//! * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
25//! * [`assert_fn_err_eq_as_result`](macro@crate::assert_fn_err_eq_as_result)
26//! * [`debug_assert_fn_err_eq`](macro@crate::debug_assert_fn_err_eq)
27
28/// Assert a function error is equal to another.
29///
30/// Pseudocode:<br>
31/// (a_function(a_param) ⇒ Err(a) ⇒ a) = (b_function(b_param) ⇒ Err(b) ⇒ b)
32///
33/// * e, return Result `Ok(a)`.
34///
35/// * Otherwise, return Result `Err(message)`.
36///
37/// This macro is useful for runtime checks, such as checking parameters,
38/// or sanitizing inputs, or handling different results in different ways.
39///
40/// # Module macros
41///
42/// * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
43/// * [`assert_fn_err_eq_as_result`](macro@crate::assert_fn_err_eq_as_result)
44/// * [`debug_assert_fn_err_eq`](macro@crate::debug_assert_fn_err_eq)
45///
46#[macro_export]
47macro_rules! assert_fn_err_eq_as_result {
48
49    //// Arity 1
50
51    ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr $(,)?) => {
52        match (&$a_function, &$a_param, &$b_function, &$b_param) {
53            (_a_function, a_param, _b_function, b_param) => {
54                match (
55                    $a_function($a_param),
56                    $b_function($b_param)
57                ) {
58                    (Err(a), Err(b)) => {
59                        if a == b {
60                            Ok((a, b))
61                        } else {
62                            Err(
63                                format!(
64                                    concat!(
65                                        "assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`\n",
66                                        "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_fn_err_eq.html\n",
67                                        " a_function label: `{}`,\n",
68                                        "    a_param label: `{}`,\n",
69                                        "    a_param debug: `{:?}`,\n",
70                                        " b_function label: `{}`,\n",
71                                        "    b_param label: `{}`,\n",
72                                        "    b_param debug: `{:?}`,\n",
73                                        "                a: `{:?}`,\n",
74                                        "                b: `{:?}`"
75                                    ),
76                                    stringify!($a_function),
77                                    stringify!($a_param),
78                                    a_param,
79                                    stringify!($b_function),
80                                    stringify!($b_param),
81                                    b_param,
82                                    a,
83                                    b
84                                )
85                            )
86                        }
87                    },
88                    (a, b) => {
89                        Err(
90                            format!(
91                                concat!(
92                                    "assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`\n",
93                                    "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_fn_err_eq.html\n",
94                                    " a_function label: `{}`,\n",
95                                    "    a_param label: `{}`,\n",
96                                    "    a_param debug: `{:?}`,\n",
97                                    " b_function label: `{}`,\n",
98                                    "    b_param label: `{}`,\n",
99                                    "    b_param debug: `{:?}`,\n",
100                                    "                a: `{:?}`,\n",
101                                    "                b: `{:?}`"
102                                ),
103                                stringify!($a_function),
104                                stringify!($a_param),
105                                a_param,
106                                stringify!($b_function),
107                                stringify!($b_param),
108                                b_param,
109                                a,
110                                b
111                            )
112                        )
113                    }
114                }
115            }
116        }
117    };
118
119    //// Arity 0
120
121    ($a_function:path, $b_function:path) => {
122        match (
123            $a_function(),
124            $b_function()
125        ) {
126            (Err(a), Err(b)) => {
127                if a == b {
128                    Ok((a, b))
129                } else {
130                    Err(
131                        format!(
132                            concat!(
133                                "assertion failed: `assert_fn_err_eq!(a_function, b_function)`\n",
134                                "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_fn_err_eq.html\n",
135                                " a_function label: `{}`,\n",
136                                " b_function label: `{}`,\n",
137                                "                a: `{:?}`,\n",
138                                "                b: `{:?}`"
139                            ),
140                            stringify!($a_function),
141                            stringify!($b_function),
142                            a,
143                            b
144                        )
145                    )
146                }
147            },
148            (a, b) => {
149                Err(
150                    format!(
151                        concat!(
152                            "assertion failed: `assert_fn_err_eq!(a_function, b_function)`\n",
153                            "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_fn_err_eq.html\n",
154                            " a_function label: `{}`,\n",
155                            " b_function label: `{}`,\n",
156                            "                a: `{:?}`,\n",
157                            "                b: `{:?}`"
158                        ),
159                        stringify!($a_function),
160                        stringify!($b_function),
161                        a,
162                        b
163                    )
164                )
165            }
166        }
167    };
168
169}
170
171#[cfg(test)]
172mod test_assert_fn_err_eq_as_result {
173    // use std::sync::Once;
174
175    mod arity_1 {
176
177        fn f(i: i8) -> Result<i8, i8> {
178            Err(i)
179        }
180
181        fn g(i: i8) -> Result<i8, i8> {
182            Err(i)
183        }
184
185        #[test]
186        fn eq() {
187            let a: i8 = 1;
188            let b: i8 = 1;
189            for _ in 0..1 {
190                let actual = assert_fn_err_eq_as_result!(f, a, g, b);
191                assert_eq!(actual.unwrap(), (1, 1));
192            }
193        }
194
195        #[test]
196        fn ne() {
197            let a: i8 = 1;
198            let b: i8 = 2;
199            let actual = assert_fn_err_eq_as_result!(f, a, g, b);
200            let message = concat!(
201                "assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`\n",
202                "https://docs.rs/assertables/",
203                env!("CARGO_PKG_VERSION"),
204                "/assertables/macro.assert_fn_err_eq.html\n",
205                " a_function label: `f`,\n",
206                "    a_param label: `a`,\n",
207                "    a_param debug: `1`,\n",
208                " b_function label: `g`,\n",
209                "    b_param label: `b`,\n",
210                "    b_param debug: `2`,\n",
211                "                a: `1`,\n",
212                "                b: `2`"
213            );
214            assert_eq!(actual.unwrap_err(), message);
215        }
216    }
217
218    mod arity_0 {
219
220        fn f() -> Result<i8, i8> {
221            Err(1)
222        }
223
224        fn g() -> Result<i8, i8> {
225            Err(2)
226        }
227
228        #[test]
229        fn eq() {
230            for _ in 0..1 {
231                let actual = assert_fn_err_eq_as_result!(f, f);
232                assert_eq!(actual.unwrap(), (1, 1));
233            }
234        }
235
236        #[test]
237        fn ne() {
238            let actual = assert_fn_err_eq_as_result!(f, g);
239            let message = concat!(
240                "assertion failed: `assert_fn_err_eq!(a_function, b_function)`\n",
241                "https://docs.rs/assertables/",
242                env!("CARGO_PKG_VERSION"),
243                "/assertables/macro.assert_fn_err_eq.html\n",
244                " a_function label: `f`,\n",
245                " b_function label: `g`,\n",
246                "                a: `1`,\n",
247                "                b: `2`"
248            );
249            assert_eq!(actual.unwrap_err(), message);
250        }
251    }
252}
253
254/// Assert a function error is equal to another.
255///
256/// Pseudocode:<br>
257/// (a_function(a_param) ⇒ Err(a) ⇒ a) = (b_function(b_param) ⇒ Err(b) ⇒ b)
258///
259/// * e, return `(a, b)`.
260///
261/// * Otherwise, call [`panic!`] with a message and the values of the
262///   expressions with their debug representations.
263///
264/// # Examples
265///
266/// ```rust
267/// use assertables::*;
268/// # use std::panic;
269/// fn f(i: i8) -> Result<String, String> {
270///     match i {
271///         0..=9 => Ok(format!("{}", i)),
272///         _ => Err(format!("{:?} is out of range", i)),
273///     }
274/// }
275///
276/// # fn main() {
277/// let a: i8 = 10;
278/// let b: i8 = 10;
279/// assert_fn_err_eq!(f, a, f, b);
280///
281/// # let result = panic::catch_unwind(|| {
282/// // This will panic
283/// let a: i8 = 10;
284/// let b: i8 = 20;
285/// assert_fn_err_eq!(f, a, f, b);
286/// # });
287/// // assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`
288/// // https://docs.rs/assertables/9.7.0/assertables/macro.assert_fn_err_eq.html
289/// //  a_function label: `f`,
290/// //     a_param label: `a`,
291/// //     a_param debug: `10`,
292/// //  b_function label: `f`,
293/// //     b_param label: `b`,
294/// //     b_param debug: `20`,
295/// //                 a: `\"10 is out of range\"`,
296/// //                 b: `\"20 is out of range\"`
297/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
298/// # let message = concat!(
299/// #     "assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`\n",
300/// #     "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_fn_err_eq.html\n",
301/// #     " a_function label: `f`,\n",
302/// #     "    a_param label: `a`,\n",
303/// #     "    a_param debug: `10`,\n",
304/// #     " b_function label: `f`,\n",
305/// #     "    b_param label: `b`,\n",
306/// #     "    b_param debug: `20`,\n",
307/// #     "                a: `\"10 is out of range\"`,\n",
308/// #     "                b: `\"20 is out of range\"`"
309/// # );
310/// # assert_eq!(actual, message);
311/// # }
312/// ```
313///
314/// # Module macros
315///
316/// * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
317/// * [`assert_fn_err_eq_as_result`](macro@crate::assert_fn_err_eq_as_result)
318/// * [`debug_assert_fn_err_eq`](macro@crate::debug_assert_fn_err_eq)
319///
320#[macro_export]
321macro_rules! assert_fn_err_eq {
322
323    //// Arity 1
324
325    ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr $(,)?) => {
326        match $crate::assert_fn_err_eq_as_result!($a_function, $a_param, $b_function, $b_param) {
327            Ok(x) => x,
328            Err(err) => panic!("{}", err),
329        }
330    };
331
332    ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr, $($message:tt)+) => {
333        match $crate::assert_fn_err_eq_as_result!($a_function, $a_param, $b_function, $b_param) {
334            Ok(x) => x,
335            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
336        }
337    };
338
339    //// Arity 0
340
341    ($a_function:path, $b_function:path) => {
342        match $crate::assert_fn_err_eq_as_result!($a_function, $b_function) {
343            Ok(x) => x,
344            Err(err) => panic!("{}", err),
345        }
346    };
347
348    ($a_function:path, $b_function:path, $($message:tt)+) => {
349        match $crate::assert_fn_err_eq_as_result!($a_function, $b_function) {
350            Ok(x) => x,
351            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
352        }
353    };
354
355}
356
357#[cfg(test)]
358mod test_assert_fn_err_eq {
359    use std::panic;
360
361    mod arity_1 {
362        use super::*;
363
364        fn f(i: i8) -> Result<i8, i8> {
365            Err(i)
366        }
367
368        fn g(i: i8) -> Result<i8, i8> {
369            Err(i)
370        }
371
372        #[test]
373        fn eq() {
374            let a: i8 = 1;
375            let b: i8 = 1;
376            for _ in 0..1 {
377                let actual = assert_fn_err_eq!(f, a, g, b);
378                assert_eq!(actual, (1, 1));
379            }
380        }
381
382        #[test]
383        fn ne() {
384            let result = panic::catch_unwind(|| {
385                let a: i8 = 1;
386                let b: i8 = 2;
387                let _actual = assert_fn_err_eq!(f, a, g, b);
388            });
389            let message = concat!(
390                "assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`\n",
391                "https://docs.rs/assertables/",
392                env!("CARGO_PKG_VERSION"),
393                "/assertables/macro.assert_fn_err_eq.html\n",
394                " a_function label: `f`,\n",
395                "    a_param label: `a`,\n",
396                "    a_param debug: `1`,\n",
397                " b_function label: `g`,\n",
398                "    b_param label: `b`,\n",
399                "    b_param debug: `2`,\n",
400                "                a: `1`,\n",
401                "                b: `2`"
402            );
403            assert_eq!(
404                result
405                    .unwrap_err()
406                    .downcast::<String>()
407                    .unwrap()
408                    .to_string(),
409                message
410            );
411        }
412    }
413
414    mod arity_0 {
415        use super::*;
416
417        fn f() -> Result<i8, i8> {
418            Err(1)
419        }
420
421        fn g() -> Result<i8, i8> {
422            Err(2)
423        }
424
425        #[test]
426        fn eq() {
427            for _ in 0..1 {
428                let actual = assert_fn_err_eq!(f, f);
429                assert_eq!(actual, (1, 1));
430            }
431        }
432
433        #[test]
434        fn ne() {
435            let result = panic::catch_unwind(|| {
436                let _actual = assert_fn_err_eq!(f, g);
437            });
438            let message = concat!(
439                "assertion failed: `assert_fn_err_eq!(a_function, b_function)`\n",
440                "https://docs.rs/assertables/",
441                env!("CARGO_PKG_VERSION"),
442                "/assertables/macro.assert_fn_err_eq.html\n",
443                " a_function label: `f`,\n",
444                " b_function label: `g`,\n",
445                "                a: `1`,\n",
446                "                b: `2`"
447            );
448            assert_eq!(
449                result
450                    .unwrap_err()
451                    .downcast::<String>()
452                    .unwrap()
453                    .to_string(),
454                message
455            );
456        }
457    }
458}
459
460/// Assert a function error is equal to another.
461///
462/// Pseudocode:<br>
463/// (a_function(a_param) ⇒ Err(a) ⇒ a) = (b_function(b_param) ⇒ Err(b) ⇒ b)
464///
465/// This macro provides the same statements as [`assert_fn_err_eq`](macro.assert_fn_err_eq.html),
466/// except this macro's statements are only enabled in non-optimized
467/// builds by default. An optimized build will not execute this macro's
468/// statements unless `-C debug-assertions` is passed to the compiler.
469///
470/// This macro is useful for checks that are too expensive to be present
471/// in a release build but may be helpful during development.
472///
473/// The result of expanding this macro is always type checked.
474///
475/// An unchecked assertion allows a program in an inconsistent state to
476/// keep running, which might have unexpected consequences but does not
477/// introduce unsafety as long as this only happens in safe code. The
478/// performance cost of assertions, however, is not measurable in general.
479/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
480/// after thorough profiling, and more importantly, only in safe code!
481///
482/// This macro is intended to work in a similar way to
483/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
484///
485/// # Module macros
486///
487/// * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
488/// * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
489/// * [`debug_assert_fn_err_eq`](macro@crate::debug_assert_fn_err_eq)
490///
491#[macro_export]
492macro_rules! debug_assert_fn_err_eq {
493    ($($arg:tt)*) => {
494        if $crate::cfg!(debug_assertions) {
495            $crate::assert_fn_err_eq!($($arg)*);
496        }
497    };
498}