assertables/assert_fn_err/assert_fn_err_lt.rs
1//! Assert a function Err(…) is less than another.
2//!
3//! Pseudocode:<br>
4//! (a_function(a_param) ⇒ Err(a) ⇒ a) < (b_function(b_param) ⇒ Err(b) ⇒ b)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//! fn f(i: i8) -> Result<String, String> {
11//! match i {
12//! 0..=9 => Ok(format!("{}", i)),
13//! _ => Err(format!("{:?} is out of range", i)),
14//! }
15//! }
16//!
17//! let a: i8 = 10;
18//! let b: i8 = 20;
19//! assert_fn_err_lt!(f, a, f, b);
20//! ```
21//!
22//! # Module macros
23//!
24//! * [`assert_fn_err_lt`](macro@crate::assert_fn_err_lt)
25//! * [`assert_fn_err_lt_as_result`](macro@crate::assert_fn_err_lt_as_result)
26//! * [`debug_assert_fn_err_lt`](macro@crate::debug_assert_fn_err_lt)
27
28/// Assert a function error is less than another.
29///
30/// * If true, return Result `Ok(a)`.
31///
32/// * Otherwise, return Result `Err(message)`.
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_err_lt`](macro@crate::assert_fn_err_lt)
40/// * [`assert_fn_err_lt_as_result`](macro@crate::assert_fn_err_lt_as_result)
41/// * [`debug_assert_fn_err_lt`](macro@crate::debug_assert_fn_err_lt)
42///
43#[macro_export]
44macro_rules! assert_fn_err_lt_as_result {
45
46 //// Arity 1
47
48 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr $(,)?) => {
49 match (&$a_function, &$a_param, &$b_function, &$b_param) {
50 (_a_function, a_param, _b_function, b_param) => {
51 match (
52 $a_function($a_param),
53 $b_function($b_param)
54 ) {
55 (Err(a), Err(b)) => {
56 if a < b {
57 Ok((a, b))
58 } else {
59 Err(
60 format!(
61 concat!(
62 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
63 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
64 " a_function label: `{}`,\n",
65 " a_param label: `{}`,\n",
66 " a_param debug: `{:?}`,\n",
67 " b_function label: `{}`,\n",
68 " b_param label: `{}`,\n",
69 " b_param debug: `{:?}`,\n",
70 " a: `{:?}`,\n",
71 " b: `{:?}`"
72 ),
73 stringify!($a_function),
74 stringify!($a_param),
75 a_param,
76 stringify!($b_function),
77 stringify!($b_param),
78 b_param,
79 a,
80 b
81 )
82 )
83 }
84 },
85 (a, b) => {
86 Err(
87 format!(
88 concat!(
89 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
90 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
91 " a_function label: `{}`,\n",
92 " a_param label: `{}`,\n",
93 " a_param debug: `{:?}`,\n",
94 " b_function label: `{}`,\n",
95 " b_param label: `{}`,\n",
96 " b_param debug: `{:?}`,\n",
97 " a: `{:?}`,\n",
98 " b: `{:?}`"
99 ),
100 stringify!($a_function),
101 stringify!($a_param),
102 a_param,
103 stringify!($b_function),
104 stringify!($b_param),
105 b_param,
106 a,
107 b
108 )
109 )
110 }
111 }
112 }
113 }
114 };
115
116 //// Arity 0
117
118 ($a_function:path, $b_function:path) => {
119 match (
120 $a_function(),
121 $b_function()
122 ) {
123 (Err(a), Err(b)) => {
124 if a < b {
125 Ok((a, b))
126 } else {
127 Err(
128 format!(
129 concat!(
130 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
131 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
132 " a_function label: `{}`,\n",
133 " b_function label: `{}`,\n",
134 " a: `{:?}`,\n",
135 " b: `{:?}`"
136 ),
137 stringify!($a_function),
138 stringify!($b_function),
139 a,
140 b
141 )
142 )
143 }
144 },
145 (a, b) => {
146 Err(
147 format!(
148 concat!(
149 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
150 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
151 " a_function label: `{}`,\n",
152 " b_function label: `{}`,\n",
153 " a: `{:?}`,\n",
154 " b: `{:?}`"
155 ),
156 stringify!($a_function),
157 stringify!($b_function),
158 a,
159 b
160 )
161 )
162 }
163 }
164 };
165
166}
167
168#[cfg(test)]
169mod test_assert_fn_err_lt_as_result {
170 // use std::sync::Once;
171
172 mod arity_1 {
173
174 fn f(i: i8) -> Result<i8, i8> {
175 Err(i)
176 }
177
178 fn g(i: i8) -> Result<i8, i8> {
179 Err(i)
180 }
181
182 #[test]
183 fn lt() {
184 let a: i8 = 1;
185 let b: i8 = 2;
186 for _ in 0..1 {
187 let actual = assert_fn_err_lt_as_result!(f, a, g, b);
188 assert_eq!(actual.unwrap(), (1, 2));
189 }
190 }
191
192 #[test]
193 fn eq() {
194 let a: i8 = 1;
195 let b: i8 = 1;
196 let actual = assert_fn_err_lt_as_result!(f, a, g, b);
197 let message = concat!(
198 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
199 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
200 " a_function label: `f`,\n",
201 " a_param label: `a`,\n",
202 " a_param debug: `1`,\n",
203 " b_function label: `g`,\n",
204 " b_param label: `b`,\n",
205 " b_param debug: `1`,\n",
206 " a: `1`,\n",
207 " b: `1`"
208 );
209 assert_eq!(actual.unwrap_err(), message);
210 }
211
212 #[test]
213 fn gt() {
214 let a: i8 = 2;
215 let b: i8 = 1;
216 let actual = assert_fn_err_lt_as_result!(f, a, g, b);
217 let message = concat!(
218 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
219 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
220 " a_function label: `f`,\n",
221 " a_param label: `a`,\n",
222 " a_param debug: `2`,\n",
223 " b_function label: `g`,\n",
224 " b_param label: `b`,\n",
225 " b_param debug: `1`,\n",
226 " a: `2`,\n",
227 " b: `1`"
228 );
229 assert_eq!(actual.unwrap_err(), message);
230 }
231 }
232
233 mod arity_0 {
234
235 fn f() -> Result<i8, i8> {
236 Err(1)
237 }
238
239 fn g() -> Result<i8, i8> {
240 Err(2)
241 }
242
243 #[test]
244 fn lt() {
245 for _ in 0..1 {
246 let actual = assert_fn_err_lt_as_result!(f, g);
247 assert_eq!(actual.unwrap(), (1, 2));
248 }
249 }
250
251 #[test]
252 fn eq() {
253 let actual = assert_fn_err_lt_as_result!(f, f);
254 let message = concat!(
255 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
256 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
257 " a_function label: `f`,\n",
258 " b_function label: `f`,\n",
259 " a: `1`,\n",
260 " b: `1`"
261 );
262 assert_eq!(actual.unwrap_err(), message);
263 }
264
265 #[test]
266 fn gt() {
267 let actual = assert_fn_err_lt_as_result!(g, f);
268 let message = concat!(
269 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
270 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
271 " a_function label: `g`,\n",
272 " b_function label: `f`,\n",
273 " a: `2`,\n",
274 " b: `1`"
275 );
276 assert_eq!(actual.unwrap_err(), message);
277 }
278 }
279}
280
281/// Assert a function error is less than another.
282///
283/// * If true, return `(a, b)`.
284///
285/// * Otherwise, call [`panic!`] with a message and the values of the
286/// expressions with their debug representations.
287///
288/// # Examples
289///
290/// ```rust
291/// use assertables::*;
292/// # use std::panic;
293/// fn f(i: i8) -> Result<String, String> {
294/// match i {
295/// 0..=9 => Ok(format!("{}", i)),
296/// _ => Err(format!("{:?} is out of range", i)),
297/// }
298/// }
299///
300/// # fn main() {
301/// let a: i8 = 10;
302/// let b: i8 = 20;
303/// assert_fn_err_lt!(f, a, f, b);
304///
305/// # let result = panic::catch_unwind(|| {
306/// // This will panic
307/// let a: i8 = 20;
308/// let b: i8 = 10;
309/// assert_fn_err_lt!(f, a, f, b);
310/// # });
311/// // assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`
312/// // https://docs.rs/assertables/…/assertables/macro.assert_fn_err_lt.html
313/// // a_function label: `f`,
314/// // a_param label: `a`,
315/// // a_param debug: `20`,
316/// // b_function label: `f`,
317/// // b_param label: `b`,
318/// // b_param debug: `10`,
319/// // a: `\"20 is out of range\"`,
320/// // b: `\"10 is out of range\"`
321/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
322/// # let message = concat!(
323/// # "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
324/// # "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
325/// # " a_function label: `f`,\n",
326/// # " a_param label: `a`,\n",
327/// # " a_param debug: `20`,\n",
328/// # " b_function label: `f`,\n",
329/// # " b_param label: `b`,\n",
330/// # " b_param debug: `10`,\n",
331/// # " a: `\"20 is out of range\"`,\n",
332/// # " b: `\"10 is out of range\"`"
333/// # );
334/// # assert_eq!(actual, message);
335/// # }
336/// ```
337///
338/// # Module macros
339///
340/// * [`assert_fn_err_lt`](macro@crate::assert_fn_err_lt)
341/// * [`assert_fn_err_lt_as_result`](macro@crate::assert_fn_err_lt_as_result)
342/// * [`debug_assert_fn_err_lt`](macro@crate::debug_assert_fn_err_lt)
343///
344#[macro_export]
345macro_rules! assert_fn_err_lt {
346
347 //// Arity 1
348
349 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr $(,)?) => {
350 match $crate::assert_fn_err_lt_as_result!($a_function, $a_param, $b_function, $b_param) {
351 Ok(x) => x,
352 Err(err) => panic!("{}", err),
353 }
354 };
355
356 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr, $($message:tt)+) => {
357 match $crate::assert_fn_err_lt_as_result!($a_function, $a_param, $b_function, $b_param) {
358 Ok(x) => x,
359 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
360 }
361 };
362
363 //// Arity 0
364
365 ($a_function:path, $b_function:path) => {
366 match $crate::assert_fn_err_lt_as_result!($a_function, $b_function) {
367 Ok(x) => x,
368 Err(err) => panic!("{}", err),
369 }
370 };
371
372 ($a_function:path, $b_function:path, $($message:tt)+) => {
373 match $crate::assert_fn_err_lt_as_result!($a_function, $b_function) {
374 Ok(x) => x,
375 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
376 }
377 };
378}
379
380#[cfg(test)]
381mod test_assert_fn_err_lt {
382 use std::panic;
383
384 mod arity_1 {
385 use super::*;
386
387 fn f(i: i8) -> Result<i8, i8> {
388 Err(i)
389 }
390
391 fn g(i: i8) -> Result<i8, i8> {
392 Err(i)
393 }
394
395 #[test]
396 fn lt() {
397 let a: i8 = 1;
398 let b: i8 = 2;
399 for _ in 0..1 {
400 let actual = assert_fn_err_lt!(f, a, g, b);
401 let expect = (1, 2);
402 assert_eq!(actual, expect);
403 }
404 }
405
406 #[test]
407 fn eq() {
408 let result = panic::catch_unwind(|| {
409 let a: i8 = 1;
410 let b: i8 = 1;
411 let _actual = assert_fn_err_lt!(f, a, g, b);
412 });
413 let message = concat!(
414 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
415 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
416 " a_function label: `f`,\n",
417 " a_param label: `a`,\n",
418 " a_param debug: `1`,\n",
419 " b_function label: `g`,\n",
420 " b_param label: `b`,\n",
421 " b_param debug: `1`,\n",
422 " a: `1`,\n",
423 " b: `1`"
424 );
425 assert_eq!(
426 result
427 .unwrap_err()
428 .downcast::<String>()
429 .unwrap()
430 .to_string(),
431 message
432 );
433 }
434
435 #[test]
436 fn gt() {
437 let result = panic::catch_unwind(|| {
438 let a: i8 = 2;
439 let b: i8 = 1;
440 let _actual = assert_fn_err_lt!(f, a, g, b);
441 });
442 let message = concat!(
443 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
444 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
445 " a_function label: `f`,\n",
446 " a_param label: `a`,\n",
447 " a_param debug: `2`,\n",
448 " b_function label: `g`,\n",
449 " b_param label: `b`,\n",
450 " b_param debug: `1`,\n",
451 " a: `2`,\n",
452 " b: `1`"
453 );
454 assert_eq!(
455 result
456 .unwrap_err()
457 .downcast::<String>()
458 .unwrap()
459 .to_string(),
460 message
461 );
462 }
463 }
464
465 mod arity_0 {
466 use super::*;
467
468 fn f() -> Result<i8, i8> {
469 Err(1)
470 }
471
472 fn g() -> Result<i8, i8> {
473 Err(2)
474 }
475
476 #[test]
477 fn lt() {
478 for _ in 0..1 {
479 let actual = assert_fn_err_lt!(f, g);
480 let expect = (1, 2);
481 assert_eq!(actual, expect);
482 }
483 }
484
485 #[test]
486 fn eq() {
487 let result = panic::catch_unwind(|| {
488 let _actual = assert_fn_err_lt!(f, f);
489 });
490 let message = concat!(
491 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
492 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
493 " a_function label: `f`,\n",
494 " b_function label: `f`,\n",
495 " a: `1`,\n",
496 " b: `1`"
497 );
498 assert_eq!(
499 result
500 .unwrap_err()
501 .downcast::<String>()
502 .unwrap()
503 .to_string(),
504 message
505 );
506 }
507
508 #[test]
509 fn gt() {
510 let result = panic::catch_unwind(|| {
511 let _actual = assert_fn_err_lt!(g, f);
512 });
513 let message = concat!(
514 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
515 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
516 " a_function label: `g`,\n",
517 " b_function label: `f`,\n",
518 " a: `2`,\n",
519 " b: `1`"
520 );
521 assert_eq!(
522 result
523 .unwrap_err()
524 .downcast::<String>()
525 .unwrap()
526 .to_string(),
527 message
528 );
529 }
530 }
531}
532
533/// Assert a function error is less than another.
534///
535/// This macro provides the same statements as [`assert_fn_err_lt`](macro.assert_fn_err_lt.html),
536/// except this macro's statements are only enabled in non-optimized
537/// builds by default. An optimized build will not execute this macro's
538/// statements unless `-C debug-assertions` is passed to the compiler.
539///
540/// This macro is useful for checks that are too expensive to be present
541/// in a release build but may be helpful during development.
542///
543/// The result of expanding this macro is always type checked.
544///
545/// An unchecked assertion allows a program in an inconsistent state to
546/// keep running, which might have unexpected consequences but does not
547/// introduce unsafety as long as this only happens in safe code. The
548/// performance cost of assertions, however, is not measurable in general.
549/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
550/// after thorough profiling, and more importantly, only in safe code!
551///
552/// This macro is intended to work in a similar way to
553/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
554///
555/// # Module macros
556///
557/// * [`assert_fn_err_lt`](macro@crate::assert_fn_err_lt)
558/// * [`assert_fn_err_lt`](macro@crate::assert_fn_err_lt)
559/// * [`debug_assert_fn_err_lt`](macro@crate::debug_assert_fn_err_lt)
560///
561#[macro_export]
562macro_rules! debug_assert_fn_err_lt {
563 ($($arg:tt)*) => {
564 if cfg!(debug_assertions) {
565 $crate::assert_fn_err_lt!($($arg)*);
566 }
567 };
568}
569
570#[cfg(test)]
571mod test_debug_assert_fn_err_lt {
572 use std::panic;
573
574 mod arity_1 {
575 use super::*;
576
577 fn f(i: i8) -> Result<i8, i8> {
578 Err(i)
579 }
580
581 fn g(i: i8) -> Result<i8, i8> {
582 Err(i)
583 }
584
585 #[test]
586 fn lt() {
587 let a: i8 = 1;
588 let b: i8 = 2;
589 for _ in 0..1 {
590 let _actual = debug_assert_fn_err_lt!(f, a, g, b);
591 let _expect = (1, 2);
592 // assert_eq!(actual, expect);
593 }
594 }
595
596 #[test]
597 fn eq() {
598 let result = panic::catch_unwind(|| {
599 let a: i8 = 1;
600 let b: i8 = 1;
601 let _actual = debug_assert_fn_err_lt!(f, a, g, b);
602 });
603 let message = concat!(
604 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
605 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
606 " a_function label: `f`,\n",
607 " a_param label: `a`,\n",
608 " a_param debug: `1`,\n",
609 " b_function label: `g`,\n",
610 " b_param label: `b`,\n",
611 " b_param debug: `1`,\n",
612 " a: `1`,\n",
613 " b: `1`"
614 );
615 assert_eq!(
616 result
617 .unwrap_err()
618 .downcast::<String>()
619 .unwrap()
620 .to_string(),
621 message
622 );
623 }
624
625 #[test]
626 fn gt() {
627 let result = panic::catch_unwind(|| {
628 let a: i8 = 2;
629 let b: i8 = 1;
630 let _actual = debug_assert_fn_err_lt!(f, a, g, b);
631 });
632 let message = concat!(
633 "assertion failed: `assert_fn_err_lt!(a_function, a_param, b_function, b_param)`\n",
634 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
635 " a_function label: `f`,\n",
636 " a_param label: `a`,\n",
637 " a_param debug: `2`,\n",
638 " b_function label: `g`,\n",
639 " b_param label: `b`,\n",
640 " b_param debug: `1`,\n",
641 " a: `2`,\n",
642 " b: `1`"
643 );
644 assert_eq!(
645 result
646 .unwrap_err()
647 .downcast::<String>()
648 .unwrap()
649 .to_string(),
650 message
651 );
652 }
653 }
654
655 mod arity_0 {
656 use super::*;
657
658 fn f() -> Result<i8, i8> {
659 Err(1)
660 }
661
662 fn g() -> Result<i8, i8> {
663 Err(2)
664 }
665
666 #[test]
667 fn lt() {
668 for _ in 0..1 {
669 let _actual = debug_assert_fn_err_lt!(f, g);
670 let _expect = (1, 2);
671 // assert_eq!(actual, expect);
672 }
673 }
674
675 #[test]
676 fn eq() {
677 let result = panic::catch_unwind(|| {
678 let _actual = debug_assert_fn_err_lt!(f, f);
679 });
680 let message = concat!(
681 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
682 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
683 " a_function label: `f`,\n",
684 " b_function label: `f`,\n",
685 " a: `1`,\n",
686 " b: `1`"
687 );
688 assert_eq!(
689 result
690 .unwrap_err()
691 .downcast::<String>()
692 .unwrap()
693 .to_string(),
694 message
695 );
696 }
697
698 #[test]
699 fn gt() {
700 let result = panic::catch_unwind(|| {
701 let _actual = debug_assert_fn_err_lt!(g, f);
702 });
703 let message = concat!(
704 "assertion failed: `assert_fn_err_lt!(a_function, b_function)`\n",
705 "https://docs.rs/assertables/9.8.6/assertables/macro.assert_fn_err_lt.html\n",
706 " a_function label: `g`,\n",
707 " b_function label: `f`,\n",
708 " a: `2`,\n",
709 " b: `1`"
710 );
711 assert_eq!(
712 result
713 .unwrap_err()
714 .downcast::<String>()
715 .unwrap()
716 .to_string(),
717 message
718 );
719 }
720 }
721}