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