assertables/assert_ok/
assert_ok_eq.rs

1//! Assert two expressions are Ok and their values are equal.
2//!
3//! Pseudocode:<br>
4//! (a ⇒ Ok(a1) ⇒ a1) = (b ⇒ Ok(b1) ⇒ b1)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a: Result<i8, i8> = Ok(1);
12//! let b: Result<i8, i8> = Ok(1);
13//! assert_ok_eq!(a, b);
14//! ```
15//!
16//! # Module macros
17//!
18//! * [`assert_ok_eq`](macro@crate::assert_ok_eq)
19//! * [`assert_ok_eq_as_result`](macro@crate::assert_ok_eq_as_result)
20//! * [`debug_assert_ok_eq`](macro@crate::debug_assert_ok_eq)
21
22/// Assert two expressions are Ok and their values are equal.
23///
24/// Pseudocode:<br>
25/// (a ⇒ Ok(a1) ⇒ a1) = (b ⇒ Ok(b1) ⇒ b1)
26///
27/// * If true, return Result `Ok((a1, b1))`.
28///
29/// * Otherwise, return Result `Err(message)`.
30///
31/// This macro is useful for runtime checks, such as checking parameters,
32/// or sanitizing inputs, or handling different results in different ways.
33///
34/// # Module macros
35///
36/// * [`assert_ok_eq`](macro@crate::assert_ok_eq)
37/// * [`assert_ok_eq_as_result`](macro@crate::assert_ok_eq_as_result)
38/// * [`debug_assert_ok_eq`](macro@crate::debug_assert_ok_eq)
39///
40#[macro_export]
41macro_rules! assert_ok_eq_as_result {
42    ($a:expr, $b:expr $(,)?) => {
43        (
44            {
45                let a = ($a);
46                let b = ($b);
47                match (a, b) {
48                    (Ok(a1), Ok(b1)) => {
49                        if a1 == b1 {
50                            Ok((a1, b1))
51                        } else {
52                            Err(
53                                format!(
54                                    concat!(
55                                        "assertion failed: `assert_ok_eq!(a, b)`\n",
56                                        "https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html\n",
57                                        " a label: `{}`,\n",
58                                        " a debug: `{:?}`,\n",
59                                        " a inner: `{:?}`,\n",
60                                        " b label: `{}`,\n",
61                                        " b debug: `{:?}`,\n",
62                                        " b inner: `{:?}`"
63                                    ),
64                                    stringify!($a),
65                                    a,
66                                    a1,
67                                    stringify!($b),
68                                    b,
69                                    b1
70                                )
71                            )
72                        }
73                    },
74                    _ => {
75                        Err(
76                            format!(
77                                concat!(
78                                    "assertion failed: `assert_ok_eq!(a, b)`\n",
79                                    "https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html\n",
80                                    " a label: `{}`,\n",
81                                    " a debug: `{:?}`,\n",
82                                    " b label: `{}`,\n",
83                                    " b debug: `{:?}`",
84                                ),
85                                stringify!($a),
86                                a,
87                                stringify!($b),
88                                b
89                            )
90                        )
91                    }
92                }
93            }
94        )
95    };
96}
97
98#[cfg(test)]
99mod test_assert_ok_eq_as_result {
100
101    #[test]
102    fn eq() {
103        let a: Result<i8, i8> = Ok(1);
104        let b: Result<i8, i8> = Ok(1);
105        let actual = assert_ok_eq_as_result!(a, b);
106        assert_eq!(actual.unwrap(), (1, 1));
107    }
108
109    #[test]
110    fn ne() {
111        let a: Result<i8, i8> = Ok(1);
112        let b: Result<i8, i8> = Ok(2);
113        let actual = assert_ok_eq_as_result!(a, b);
114        let message = concat!(
115            "assertion failed: `assert_ok_eq!(a, b)`\n",
116            "https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html\n",
117            " a label: `a`,\n",
118            " a debug: `Ok(1)`,\n",
119            " a inner: `1`,\n",
120            " b label: `b`,\n",
121            " b debug: `Ok(2)`,\n",
122            " b inner: `2`",
123        );
124        assert_eq!(actual.unwrap_err(), message);
125    }
126
127    #[test]
128    fn not_ok() {
129        let a: Result<i8, i8> = Err(1);
130        let b: Result<i8, i8> = Ok(1);
131        let actual = assert_ok_eq_as_result!(a, b);
132        let message = concat!(
133            "assertion failed: `assert_ok_eq!(a, b)`\n",
134            "https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html\n",
135            " a label: `a`,\n",
136            " a debug: `Err(1)`,\n",
137            " b label: `b`,\n",
138            " b debug: `Ok(1)`",
139        );
140        assert_eq!(actual.unwrap_err(), message);
141    }
142
143    #[test]
144    fn idempotent() {
145        let a = 100;
146        let b = 100;
147        let a_atomic = std::sync::atomic::AtomicU32::new(a);
148        let a_increment = || Err::<u32, u32>(a_atomic.fetch_add(1, std::sync::atomic::Ordering::SeqCst));
149        let b_atomic = std::sync::atomic::AtomicU32::new(b);
150        let b_increment = || Err::<u32, u32>(b_atomic.fetch_add(1, std::sync::atomic::Ordering::SeqCst));
151        let _ = assert_ok_eq_as_result!(a_increment(), b_increment());
152        assert_eq!(a_atomic.load(std::sync::atomic::Ordering::SeqCst), a + 1);
153        assert_eq!(b_atomic.load(std::sync::atomic::Ordering::SeqCst), b + 1);
154    }
155
156}
157
158/// Assert two expressions are Ok and their values are equal.
159///
160/// Pseudocode:<br>
161/// (a ⇒ Ok(a1) ⇒ a1) = (b ⇒ Ok(b1) ⇒ b1)
162///
163/// * If true, return `(a1, b1)`.
164///
165/// * Otherwise, call [`panic!`] with a message and the values of the
166///   expressions with their debug representations.
167///
168/// # Examples
169///
170/// ```rust
171/// use assertables::*;
172/// # use std::panic;
173///
174/// # fn main() {
175/// let a: Result<i8, i8> = Ok(1);
176/// let b: Result<i8, i8> = Ok(1);
177/// assert_ok_eq!(a, b);
178///
179/// # let result = panic::catch_unwind(|| {
180/// // This will panic
181/// let a: Result<i8, i8> = Ok(1);
182/// let b: Result<i8, i8> = Ok(2);
183/// assert_ok_eq!(a, b);
184/// # });
185/// // assertion failed: `assert_ok_eq!(a, b)`
186/// // https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html
187/// //  a label: `a`,
188/// //  a debug: `Ok(1)`,
189/// //  a inner: `1`,
190/// //  b label: `b`,
191/// //  b debug: `Ok(2)`,
192/// //  b inner: `2`
193/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
194/// # let message = concat!(
195/// #     "assertion failed: `assert_ok_eq!(a, b)`\n",
196/// #     "https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html\n",
197/// #     " a label: `a`,\n",
198/// #     " a debug: `Ok(1)`,\n",
199/// #     " a inner: `1`,\n",
200/// #     " b label: `b`,\n",
201/// #     " b debug: `Ok(2)`,\n",
202/// #     " b inner: `2`",
203/// # );
204/// # assert_eq!(actual, message);
205/// # }
206/// ```
207///
208/// # Module macros
209///
210/// * [`assert_ok_eq`](macro@crate::assert_ok_eq)
211/// * [`assert_ok_eq_as_result`](macro@crate::assert_ok_eq_as_result)
212/// * [`debug_assert_ok_eq`](macro@crate::debug_assert_ok_eq)
213///
214#[macro_export]
215macro_rules! assert_ok_eq {
216    ($a:expr, $b:expr $(,)?) => {{
217        match $crate::assert_ok_eq_as_result!($a, $b) {
218            Ok(x) => x,
219            Err(err) => panic!("{}", err),
220        }
221    }};
222    ($a:expr, $b:expr, $($message:tt)+) => {{
223        match $crate::assert_ok_eq_as_result!($a, $b) {
224            Ok(x) => x,
225            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
226        }
227    }};
228}
229
230#[cfg(test)]
231mod test_assert_ok_eq {
232    use std::panic;
233
234    #[test]
235    fn eq() {
236        let a: Result<i8, i8> = Ok(1);
237        let b: Result<i8, i8> = Ok(1);
238        let actual = assert_ok_eq!(a, b);
239        assert_eq!(actual, (1, 1));
240    }
241
242    #[test]
243    fn ne() {
244        let a: Result<i8, i8> = Ok(1);
245        let b: Result<i8, i8> = Ok(2);
246        let result = panic::catch_unwind(|| {
247            let _actual = assert_ok_eq!(a, b);
248        });
249        let message = concat!(
250            "assertion failed: `assert_ok_eq!(a, b)`\n",
251            "https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html\n",
252            " a label: `a`,\n",
253            " a debug: `Ok(1)`,\n",
254            " a inner: `1`,\n",
255            " b label: `b`,\n",
256            " b debug: `Ok(2)`,\n",
257            " b inner: `2`",
258        );
259        assert_eq!(
260            result
261                .unwrap_err()
262                .downcast::<String>()
263                .unwrap()
264                .to_string(),
265            message
266        );
267    }
268
269    #[test]
270    fn not_ok() {
271        let a: Result<i8, i8> = Err(1);
272        let b: Result<i8, i8> = Ok(1);
273        let result = panic::catch_unwind(|| {
274            let _actual = assert_ok_eq!(a, b);
275        });
276        let message = concat!(
277            "assertion failed: `assert_ok_eq!(a, b)`\n",
278            "https://docs.rs/assertables/9.5.1/assertables/macro.assert_ok_eq.html\n",
279            " a label: `a`,\n",
280            " a debug: `Err(1)`,\n",
281            " b label: `b`,\n",
282            " b debug: `Ok(1)`",
283        );
284        assert_eq!(
285            result
286                .unwrap_err()
287                .downcast::<String>()
288                .unwrap()
289                .to_string(),
290            message
291        );
292    }
293}
294
295/// Assert two expressions are Ok and their values are equal.
296///
297/// Pseudocode:<br>
298/// (a ⇒ Ok(a1) ⇒ a1) = (b ⇒ Ok(b1) ⇒ b1)
299///
300/// This macro provides the same statements as [`assert_ok_eq`](macro.assert_ok_eq.html),
301/// except this macro's statements are only enabled in non-optimized
302/// builds by default. An optimized build will not execute this macro's
303/// statements unless `-C debug-assertions` is passed to the compiler.
304///
305/// This macro is useful for checks that are too expensive to be present
306/// in a release build but may be helpful during development.
307///
308/// The result of expanding this macro is always type checked.
309///
310/// An unchecked assertion allows a program in an inconsistent state to
311/// keep running, which might have unexpected consequences but does not
312/// introduce unsafety as long as this only happens in safe code. The
313/// performance cost of assertions, however, is not measurable in general.
314/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
315/// after thorough profiling, and more importantly, only in safe code!
316///
317/// This macro is intended to work in a similar way to
318/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
319///
320/// # Module macros
321///
322/// * [`assert_ok_eq`](macro@crate::assert_ok_eq)
323/// * [`assert_ok_eq`](macro@crate::assert_ok_eq)
324/// * [`debug_assert_ok_eq`](macro@crate::debug_assert_ok_eq)
325///
326#[macro_export]
327macro_rules! debug_assert_ok_eq {
328    ($($arg:tt)*) => {
329        if $crate::cfg!(debug_assertions) {
330            $crate::assert_ok_eq!($($arg)*);
331        }
332    };
333}