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