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}