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}