assertables/assert_fn/
assert_fn_lt.rs

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