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}