assertables/assert_fn/
assert_fn_le_x.rs

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