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}