assertables/assert_fn/
assert_fn_le.rs

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