assertables/assert_fn/
assert_fn_ge.rs

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