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