dyn_error/err_box/fn_impl.rs
1use crate::ErrBoxCheckFailure;
2use std::error::Error;
3
4/// Tests whether the given [Result] is actually
5/// an [Err] with a [Box] containing an [Error] implementation
6/// equal to the *expected* instance:
7///
8/// * If the equality check succeeds, just returns [Ok] with
9/// a no-op `()` value;
10///
11/// * otherwise, returns [Err] - with a descriptive [ErrBoxCheckFailure].
12///
13/// ```
14/// use dyn_error::*;
15/// use std::fmt::Display;
16/// use std::error::Error;
17///
18/// #[derive(Debug, PartialEq, Eq)]
19/// struct MyErr(pub u8);
20///
21/// impl Display for MyErr {
22/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23/// write!(f, "Custom error: {}", self.0)
24/// }
25/// }
26///
27/// impl Error for MyErr {};
28///
29/// let result: Result<String, Box<dyn Error>> = Err(Box::new(
30/// MyErr(90)
31/// ));
32///
33/// assert_eq!(
34/// check_err_box(
35/// result,
36/// MyErr(90)
37/// ),
38/// Ok(())
39/// );
40/// ```
41///
42/// In case of inequality, the function returns [Err]
43/// with [ErrBoxCheckFailure::NotEqual], containing the
44/// string representations of the two instances:
45///
46/// ```
47/// use dyn_error::*;
48/// use std::fmt::Display;
49/// use std::error::Error;
50///
51/// #[derive(Debug, PartialEq, Eq)]
52/// struct MyErr(pub u8);
53///
54/// impl Display for MyErr {
55/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56/// write!(f, "Custom error: {}", self.0)
57/// }
58/// }
59///
60/// impl Error for MyErr {};
61///
62/// let result: Result<String, Box<dyn Error>> = Err(Box::new(
63/// MyErr(90)
64/// ));
65///
66/// assert_eq!(
67/// check_err_box(result, MyErr(7)),
68/// Err(ErrBoxCheckFailure::NotEqual {
69/// expected: "Custom error: 7".to_string(),
70/// actual: "Custom error: 90".to_string()
71/// })
72/// );
73/// ```
74///
75/// Of course, the check also fails if the boxed error and the expected error belong to unrelated types:
76///
77/// ```
78/// use dyn_error::*;
79/// use std::fmt::Display;
80/// use std::error::Error;
81///
82/// #[derive(Debug, PartialEq, Eq)]
83/// struct AlphaErr(pub u8);
84/// impl Display for AlphaErr {
85/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86/// write!(f, "Alpha error: {}", self.0)
87/// }
88/// }
89/// impl Error for AlphaErr {};
90///
91/// #[derive(Debug, PartialEq, Eq)]
92/// struct BetaErr(pub u8);
93/// impl Display for BetaErr {
94/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95/// write!(f, "Beta error: {}", self.0)
96/// }
97/// }
98/// impl Error for BetaErr {};
99///
100/// let result: Result<String, Box<dyn Error>> = Err(Box::new(
101/// BetaErr(90)
102/// ));
103///
104/// assert_eq!(
105/// check_err_box(result, AlphaErr(90)),
106/// Err(ErrBoxCheckFailure::DowncastFailed)
107/// );
108/// ```
109///
110/// Finally, the function fails also if the result is just [Ok]:
111///
112/// ```
113/// use dyn_error::*;
114/// use std::fmt::Display;
115/// use std::error::Error;
116///
117/// #[derive(Debug, PartialEq, Eq)]
118/// struct MyErr(pub u8);
119///
120/// impl Display for MyErr {
121/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122/// write!(f, "Custom error: {}", self.0)
123/// }
124/// }
125///
126/// impl Error for MyErr {};
127///
128/// let result: Result<String, Box<dyn Error>> = Ok("Dodo".to_string());
129///
130/// check_err_box(result, MyErr(7));
131/// ```
132pub fn check_err_box<T, E: Error + PartialEq<E> + 'static>(
133 result: Result<T, Box<dyn Error>>,
134 expected_err: E,
135) -> Result<(), ErrBoxCheckFailure> {
136 match result {
137 Ok(_) => Err(ErrBoxCheckFailure::ResultIsNotErr),
138
139 Err(ref e) => match e.downcast_ref::<E>() {
140 Some(boxed_err) => {
141 if expected_err == *boxed_err {
142 Ok(())
143 } else {
144 Err(ErrBoxCheckFailure::NotEqual {
145 expected: expected_err.to_string(),
146 actual: boxed_err.to_string(),
147 })
148 }
149 }
150
151 None => Err(ErrBoxCheckFailure::DowncastFailed),
152 },
153 }
154}