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