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/", env!("CARGO_PKG_VERSION"), "/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/", env!("CARGO_PKG_VERSION"), "/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/", env!("CARGO_PKG_VERSION"), "/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/", env!("CARGO_PKG_VERSION"), "/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/",
203 env!("CARGO_PKG_VERSION"),
204 "/assertables/macro.assert_fn_err_eq.html\n",
205 " a_function label: `f`,\n",
206 " a_param label: `a`,\n",
207 " a_param debug: `1`,\n",
208 " b_function label: `g`,\n",
209 " b_param label: `b`,\n",
210 " b_param debug: `2`,\n",
211 " a: `1`,\n",
212 " b: `2`"
213 );
214 assert_eq!(actual.unwrap_err(), message);
215 }
216 }
217
218 mod arity_0 {
219
220 fn f() -> Result<i8, i8> {
221 Err(1)
222 }
223
224 fn g() -> Result<i8, i8> {
225 Err(2)
226 }
227
228 #[test]
229 fn eq() {
230 for _ in 0..1 {
231 let actual = assert_fn_err_eq_as_result!(f, f);
232 assert_eq!(actual.unwrap(), (1, 1));
233 }
234 }
235
236 #[test]
237 fn ne() {
238 let actual = assert_fn_err_eq_as_result!(f, g);
239 let message = concat!(
240 "assertion failed: `assert_fn_err_eq!(a_function, b_function)`\n",
241 "https://docs.rs/assertables/",
242 env!("CARGO_PKG_VERSION"),
243 "/assertables/macro.assert_fn_err_eq.html\n",
244 " a_function label: `f`,\n",
245 " b_function label: `g`,\n",
246 " a: `1`,\n",
247 " b: `2`"
248 );
249 assert_eq!(actual.unwrap_err(), message);
250 }
251 }
252}
253
254/// Assert a function error is equal to another.
255///
256/// Pseudocode:<br>
257/// (a_function(a_param) ⇒ Err(a) ⇒ a) = (b_function(b_param) ⇒ Err(b) ⇒ b)
258///
259/// * e, return `(a, b)`.
260///
261/// * Otherwise, call [`panic!`] with a message and the values of the
262/// expressions with their debug representations.
263///
264/// # Examples
265///
266/// ```rust
267/// use assertables::*;
268/// # use std::panic;
269/// fn f(i: i8) -> Result<String, String> {
270/// match i {
271/// 0..=9 => Ok(format!("{}", i)),
272/// _ => Err(format!("{:?} is out of range", i)),
273/// }
274/// }
275///
276/// # fn main() {
277/// let a: i8 = 10;
278/// let b: i8 = 10;
279/// assert_fn_err_eq!(f, a, f, b);
280///
281/// # let result = panic::catch_unwind(|| {
282/// // This will panic
283/// let a: i8 = 10;
284/// let b: i8 = 20;
285/// assert_fn_err_eq!(f, a, f, b);
286/// # });
287/// // assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`
288/// // https://docs.rs/assertables/9.7.0/assertables/macro.assert_fn_err_eq.html
289/// // a_function label: `f`,
290/// // a_param label: `a`,
291/// // a_param debug: `10`,
292/// // b_function label: `f`,
293/// // b_param label: `b`,
294/// // b_param debug: `20`,
295/// // a: `\"10 is out of range\"`,
296/// // b: `\"20 is out of range\"`
297/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
298/// # let message = concat!(
299/// # "assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`\n",
300/// # "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_fn_err_eq.html\n",
301/// # " a_function label: `f`,\n",
302/// # " a_param label: `a`,\n",
303/// # " a_param debug: `10`,\n",
304/// # " b_function label: `f`,\n",
305/// # " b_param label: `b`,\n",
306/// # " b_param debug: `20`,\n",
307/// # " a: `\"10 is out of range\"`,\n",
308/// # " b: `\"20 is out of range\"`"
309/// # );
310/// # assert_eq!(actual, message);
311/// # }
312/// ```
313///
314/// # Module macros
315///
316/// * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
317/// * [`assert_fn_err_eq_as_result`](macro@crate::assert_fn_err_eq_as_result)
318/// * [`debug_assert_fn_err_eq`](macro@crate::debug_assert_fn_err_eq)
319///
320#[macro_export]
321macro_rules! assert_fn_err_eq {
322
323 //// Arity 1
324
325 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr $(,)?) => {
326 match $crate::assert_fn_err_eq_as_result!($a_function, $a_param, $b_function, $b_param) {
327 Ok(x) => x,
328 Err(err) => panic!("{}", err),
329 }
330 };
331
332 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr, $($message:tt)+) => {
333 match $crate::assert_fn_err_eq_as_result!($a_function, $a_param, $b_function, $b_param) {
334 Ok(x) => x,
335 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
336 }
337 };
338
339 //// Arity 0
340
341 ($a_function:path, $b_function:path) => {
342 match $crate::assert_fn_err_eq_as_result!($a_function, $b_function) {
343 Ok(x) => x,
344 Err(err) => panic!("{}", err),
345 }
346 };
347
348 ($a_function:path, $b_function:path, $($message:tt)+) => {
349 match $crate::assert_fn_err_eq_as_result!($a_function, $b_function) {
350 Ok(x) => x,
351 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
352 }
353 };
354
355}
356
357#[cfg(test)]
358mod test_assert_fn_err_eq {
359 use std::panic;
360
361 mod arity_1 {
362 use super::*;
363
364 fn f(i: i8) -> Result<i8, i8> {
365 Err(i)
366 }
367
368 fn g(i: i8) -> Result<i8, i8> {
369 Err(i)
370 }
371
372 #[test]
373 fn eq() {
374 let a: i8 = 1;
375 let b: i8 = 1;
376 for _ in 0..1 {
377 let actual = assert_fn_err_eq!(f, a, g, b);
378 assert_eq!(actual, (1, 1));
379 }
380 }
381
382 #[test]
383 fn ne() {
384 let result = panic::catch_unwind(|| {
385 let a: i8 = 1;
386 let b: i8 = 2;
387 let _actual = assert_fn_err_eq!(f, a, g, b);
388 });
389 let message = concat!(
390 "assertion failed: `assert_fn_err_eq!(a_function, a_param, b_function, b_param)`\n",
391 "https://docs.rs/assertables/",
392 env!("CARGO_PKG_VERSION"),
393 "/assertables/macro.assert_fn_err_eq.html\n",
394 " a_function label: `f`,\n",
395 " a_param label: `a`,\n",
396 " a_param debug: `1`,\n",
397 " b_function label: `g`,\n",
398 " b_param label: `b`,\n",
399 " b_param debug: `2`,\n",
400 " a: `1`,\n",
401 " b: `2`"
402 );
403 assert_eq!(
404 result
405 .unwrap_err()
406 .downcast::<String>()
407 .unwrap()
408 .to_string(),
409 message
410 );
411 }
412 }
413
414 mod arity_0 {
415 use super::*;
416
417 fn f() -> Result<i8, i8> {
418 Err(1)
419 }
420
421 fn g() -> Result<i8, i8> {
422 Err(2)
423 }
424
425 #[test]
426 fn eq() {
427 for _ in 0..1 {
428 let actual = assert_fn_err_eq!(f, f);
429 assert_eq!(actual, (1, 1));
430 }
431 }
432
433 #[test]
434 fn ne() {
435 let result = panic::catch_unwind(|| {
436 let _actual = assert_fn_err_eq!(f, g);
437 });
438 let message = concat!(
439 "assertion failed: `assert_fn_err_eq!(a_function, b_function)`\n",
440 "https://docs.rs/assertables/",
441 env!("CARGO_PKG_VERSION"),
442 "/assertables/macro.assert_fn_err_eq.html\n",
443 " a_function label: `f`,\n",
444 " b_function label: `g`,\n",
445 " a: `1`,\n",
446 " b: `2`"
447 );
448 assert_eq!(
449 result
450 .unwrap_err()
451 .downcast::<String>()
452 .unwrap()
453 .to_string(),
454 message
455 );
456 }
457 }
458}
459
460/// Assert a function error is equal to another.
461///
462/// Pseudocode:<br>
463/// (a_function(a_param) ⇒ Err(a) ⇒ a) = (b_function(b_param) ⇒ Err(b) ⇒ b)
464///
465/// This macro provides the same statements as [`assert_fn_err_eq`](macro.assert_fn_err_eq.html),
466/// except this macro's statements are only enabled in non-optimized
467/// builds by default. An optimized build will not execute this macro's
468/// statements unless `-C debug-assertions` is passed to the compiler.
469///
470/// This macro is useful for checks that are too expensive to be present
471/// in a release build but may be helpful during development.
472///
473/// The result of expanding this macro is always type checked.
474///
475/// An unchecked assertion allows a program in an inconsistent state to
476/// keep running, which might have unexpected consequences but does not
477/// introduce unsafety as long as this only happens in safe code. The
478/// performance cost of assertions, however, is not measurable in general.
479/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
480/// after thorough profiling, and more importantly, only in safe code!
481///
482/// This macro is intended to work in a similar way to
483/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
484///
485/// # Module macros
486///
487/// * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
488/// * [`assert_fn_err_eq`](macro@crate::assert_fn_err_eq)
489/// * [`debug_assert_fn_err_eq`](macro@crate::debug_assert_fn_err_eq)
490///
491#[macro_export]
492macro_rules! debug_assert_fn_err_eq {
493 ($($arg:tt)*) => {
494 if $crate::cfg!(debug_assertions) {
495 $crate::assert_fn_err_eq!($($arg)*);
496 }
497 };
498}