assertables/assert_fn_err/
assert_fn_err_lt.rs

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