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