Skip to main content

assertables/assert_some/
assert_some_eq_x.rs

1//! Assert an expression is Some and its value is equal to an expression.
2//!
3//! Pseudocode:<br>
4//! (a ⇒ Some(a1) ⇒ a1) = b
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a: Option<i8> = Option::Some(1);
12//! let b: i8 = 1;
13//! assert_some_eq_x!(a, b);
14//! ```
15//!
16//! # Module macros
17//!
18//! * [`assert_some_eq_x`](macro@crate::assert_some_eq_x)
19//! * [`assert_some_eq_x_as_result`](macro@crate::assert_some_eq_x_as_result)
20//! * [`debug_assert_some_eq_x`](macro@crate::debug_assert_some_eq_x)
21
22/// Assert a.is_some() and a.unwrap() are equal to another.
23///
24/// Pseudocode:<br>
25/// (a ⇒ Some(a1) ⇒ a1) = b
26///
27/// * If true, return Result `Ok(a1)`.
28///
29/// * Otherwise, return Result `Err(message)`.
30///
31/// This macro provides the same statements as [`assert_some_eq_x`](macro.assert_some_eq_x.html),
32/// except this macro returns a Option, rather than doing a panic.
33///
34/// This macro is useful for runtime checks, such as checking parameters,
35/// or sanitizing inputs, or handling different results in different ways.
36///
37/// # Module macros
38///
39/// * [`assert_some_eq_x`](macro@crate::assert_some_eq_x)
40/// * [`assert_some_eq_x_as_result`](macro@crate::assert_some_eq_x_as_result)
41/// * [`debug_assert_some_eq_x`](macro@crate::debug_assert_some_eq_x)
42///
43#[macro_export]
44macro_rules! assert_some_eq_x_as_result {
45    ($a:expr, $b:expr $(,)?) => {
46        match ($a) {
47            Some(a1) => {
48                if a1 == $b {
49                    Ok(a1)
50                } else {
51                    Err(format!(
52                        concat!(
53                            "assertion failed: `assert_some_eq_x!(a, b)`\n",
54                            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_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            _ => Err(format!(
70                concat!(
71                    "assertion failed: `assert_some_eq_x!(a, b)`\n",
72                    "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
73                    " a label: `{}`,\n",
74                    " a debug: `{:?}`,\n",
75                    " b label: `{}`,\n",
76                    " b debug: `{:?}`",
77                ),
78                stringify!($a),
79                $a,
80                stringify!($b),
81                $b,
82            )),
83        }
84    };
85}
86
87#[cfg(test)]
88mod test_assert_some_eq_x_as_result {
89    use std::sync::Once;
90
91    #[test]
92    fn eq() {
93        let a: Option<i8> = Option::Some(1);
94        let b: i8 = 1;
95        for _ in 0..1 {
96            let actual = assert_some_eq_x_as_result!(a, b);
97            assert_eq!(actual.unwrap(), 1);
98        }
99    }
100
101    #[test]
102    fn eq_once() {
103        static A: Once = Once::new();
104        fn a() -> Option<i8> {
105            if A.is_completed() {
106                panic!("A.is_completed()")
107            } else {
108                A.call_once(|| {})
109            }
110            Option::Some(1)
111        }
112
113        static B: Once = Once::new();
114        fn b() -> i8 {
115            if B.is_completed() {
116                panic!("B.is_completed()")
117            } else {
118                B.call_once(|| {})
119            }
120            1
121        }
122
123        assert_eq!(A.is_completed(), false);
124        assert_eq!(B.is_completed(), false);
125        let result = assert_some_eq_x_as_result!(a(), b());
126        assert!(result.is_ok());
127        assert_eq!(A.is_completed(), true);
128        assert_eq!(B.is_completed(), true);
129    }
130
131    #[test]
132    fn ne() {
133        let a: Option<i8> = Option::Some(1);
134        let b: i8 = 2;
135        let actual = assert_some_eq_x_as_result!(a, b);
136        let message = concat!(
137            "assertion failed: `assert_some_eq_x!(a, b)`\n",
138            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
139            " a label: `a`,\n",
140            " a debug: `Some(1)`,\n",
141            " a inner: `1`,\n",
142            " b label: `b`,\n",
143            " b debug: `2`"
144        );
145        assert_eq!(actual.unwrap_err(), message);
146    }
147
148    #[test]
149    fn not_some() {
150        let a: Option<i8> = Option::None;
151        let b: i8 = 1;
152        let actual = assert_some_eq_x_as_result!(a, b);
153        let message = concat!(
154            "assertion failed: `assert_some_eq_x!(a, b)`\n",
155            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
156            " a label: `a`,\n",
157            " a debug: `None`,\n",
158            " b label: `b`,\n",
159            " b debug: `1`",
160        );
161        assert_eq!(actual.unwrap_err(), message);
162    }
163}
164
165/// Assert an expression is Some and its value is equal to an expression.
166///
167/// Pseudocode:<br>
168/// (a ⇒ Some(a1) ⇒ a1) = b
169///
170/// * If true, return `a1`.
171///
172/// * Otherwise, call [`panic!`] with a message and the values of the
173///   expressions with their debug representations.
174///
175/// # Examples
176///
177/// ```rust
178/// use assertables::*;
179/// # use std::panic;
180///
181/// # fn main() {
182/// let a: Option<i8> = Option::Some(1);
183/// let b: i8 = 1;
184/// assert_some_eq_x!(a, b);
185///
186/// # let result = panic::catch_unwind(|| {
187/// // This will panic
188/// let a: Option<i8> = Option::Some(1);
189/// let b: i8 = 2;
190/// assert_some_eq_x!(a, b);
191/// # });
192/// // assertion failed: `assert_some_eq_x!(a, b)`
193/// // https://docs.rs/assertables/…/assertables/macro.assert_some_eq_x.html
194/// //  a label: `a`,
195/// //  a debug: `Some(1)`,
196/// //  a inner: `1`,
197/// //  b label: `b`,
198/// //  b debug: `2`
199/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
200/// # let message = concat!(
201/// #     "assertion failed: `assert_some_eq_x!(a, b)`\n",
202/// #     "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
203/// #     " a label: `a`,\n",
204/// #     " a debug: `Some(1)`,\n",
205/// #     " a inner: `1`,\n",
206/// #     " b label: `b`,\n",
207/// #     " b debug: `2`",
208/// # );
209/// # assert_eq!(actual, message);
210/// # }
211/// ```
212///
213/// # Module macros
214///
215/// * [`assert_some_eq_x`](macro@crate::assert_some_eq_x)
216/// * [`assert_some_eq_x_as_result`](macro@crate::assert_some_eq_x_as_result)
217/// * [`debug_assert_some_eq_x`](macro@crate::debug_assert_some_eq_x)
218///
219#[macro_export]
220macro_rules! assert_some_eq_x {
221    ($a:expr, $b:expr $(,)?) => {
222        match $crate::assert_some_eq_x_as_result!($a, $b) {
223            Ok(x) => x,
224            Err(err) => panic!("{}", err),
225        }
226    };
227    ($a:expr, $b:expr, $($message:tt)+) => {
228        match $crate::assert_some_eq_x_as_result!($a, $b) {
229            Ok(x) => x,
230            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
231        }
232    };
233}
234
235#[cfg(test)]
236mod test_assert_some_eq_x {
237    use std::panic;
238
239    #[test]
240    fn eq() {
241        let a: Option<i8> = Option::Some(1);
242        let b: i8 = 1;
243        for _ in 0..1 {
244            let actual = assert_some_eq_x!(a, b);
245            assert_eq!(actual, 1);
246        }
247    }
248
249    #[test]
250    fn ne() {
251        let a: Option<i8> = Option::Some(1);
252        let b: i8 = 2;
253        let result = panic::catch_unwind(|| {
254            let _actual = assert_some_eq_x!(a, b);
255        });
256        let message = concat!(
257            "assertion failed: `assert_some_eq_x!(a, b)`\n",
258            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
259            " a label: `a`,\n",
260            " a debug: `Some(1)`,\n",
261            " a inner: `1`,\n",
262            " b label: `b`,\n",
263            " b debug: `2`"
264        );
265        assert_eq!(
266            result
267                .unwrap_err()
268                .downcast::<String>()
269                .unwrap()
270                .to_string(),
271            message
272        );
273    }
274
275    #[test]
276    fn not_some() {
277        let a: Option<i8> = Option::None;
278        let b: i8 = 1;
279        let result = panic::catch_unwind(|| {
280            let _actual = assert_some_eq_x!(a, b);
281        });
282        let message = concat!(
283            "assertion failed: `assert_some_eq_x!(a, b)`\n",
284            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
285            " a label: `a`,\n",
286            " a debug: `None`,\n",
287            " b label: `b`,\n",
288            " b debug: `1`",
289        );
290        assert_eq!(
291            result
292                .unwrap_err()
293                .downcast::<String>()
294                .unwrap()
295                .to_string(),
296            message
297        );
298    }
299}
300
301/// Assert an expression is Some and its value is equal to an expression.
302///
303/// Pseudocode:<br>
304/// (a ⇒ Some(a1) ⇒ a1) = b
305///
306/// This macro provides the same statements as [`assert_some_eq_x`](macro.assert_some_eq_x.html),
307/// except this macro's statements are only enabled in non-optimized
308/// builds by default. An optimized build will not execute this macro's
309/// statements unless `-C debug-assertions` is passed to the compiler.
310///
311/// This macro is useful for checks that are too expensive to be present
312/// in a release build but may be helpful during development.
313///
314/// The result of expanding this macro is always type checked.
315///
316/// An unchecked assertion allows a program in an inconsistent state to
317/// keep running, which might have unexpected consequences but does not
318/// introduce unsafety as long as this only happens in safe code. The
319/// performance cost of assertions, however, is not measurable in general.
320/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
321/// after thorough profiling, and more importantly, only in safe code!
322///
323/// This macro is intended to work in a similar way to
324/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
325///
326/// # Module macros
327///
328/// * [`assert_some_eq_x`](macro@crate::assert_some_eq_x)
329/// * [`assert_some_eq_x`](macro@crate::assert_some_eq_x)
330/// * [`debug_assert_some_eq_x`](macro@crate::debug_assert_some_eq_x)
331///
332#[macro_export]
333macro_rules! debug_assert_some_eq_x {
334    ($($arg:tt)*) => {
335        if cfg!(debug_assertions) {
336            $crate::assert_some_eq_x!($($arg)*);
337        }
338    };
339}
340
341#[cfg(test)]
342mod test_debug_assert_some_eq_x {
343    use std::panic;
344
345    #[test]
346    fn eq() {
347        let a: Option<i8> = Option::Some(1);
348        let b: i8 = 1;
349        for _ in 0..1 {
350            let _actual = debug_assert_some_eq_x!(a, b);
351            // assert_eq!(actual, 1);
352        }
353    }
354
355    #[test]
356    fn ne() {
357        let a: Option<i8> = Option::Some(1);
358        let b: i8 = 2;
359        let result = panic::catch_unwind(|| {
360            let _actual = debug_assert_some_eq_x!(a, b);
361        });
362        let message = concat!(
363            "assertion failed: `assert_some_eq_x!(a, b)`\n",
364            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
365            " a label: `a`,\n",
366            " a debug: `Some(1)`,\n",
367            " a inner: `1`,\n",
368            " b label: `b`,\n",
369            " b debug: `2`"
370        );
371        assert_eq!(
372            result
373                .unwrap_err()
374                .downcast::<String>()
375                .unwrap()
376                .to_string(),
377            message
378        );
379    }
380
381    #[test]
382    fn not_some() {
383        let a: Option<i8> = Option::None;
384        let b: i8 = 1;
385        let result = panic::catch_unwind(|| {
386            let _actual = debug_assert_some_eq_x!(a, b);
387        });
388        let message = concat!(
389            "assertion failed: `assert_some_eq_x!(a, b)`\n",
390            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_some_eq_x.html\n",
391            " a label: `a`,\n",
392            " a debug: `None`,\n",
393            " b label: `b`,\n",
394            " b debug: `1`",
395        );
396        assert_eq!(
397            result
398                .unwrap_err()
399                .downcast::<String>()
400                .unwrap()
401                .to_string(),
402            message
403        );
404    }
405}