assertables/assert_some/
assert_some_ne_x.rs

1//! Assert an expression is Some and its value is not 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 = 2;
13//! assert_some_ne_x!(a, b);
14//! ```
15//!
16//! # Module macros
17//!
18//! * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
19//! * [`assert_some_ne_x_as_result`](macro@crate::assert_some_ne_x_as_result)
20//! * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_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_ne_x`](macro.assert_some_ne_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_ne_x`](macro@crate::assert_some_ne_x)
40/// * [`assert_some_ne_x_as_result`](macro@crate::assert_some_ne_x_as_result)
41/// * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_x)
42///
43#[macro_export]
44macro_rules! assert_some_ne_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_ne_x!(a, b)`\n",
54                            "https://docs.rs/assertables/9.8.4/assertables/macro.assert_some_ne_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_ne_x!(a, b)`\n",
72                    "https://docs.rs/assertables/9.8.4/assertables/macro.assert_some_ne_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_ne_x_as_result {
89    use std::sync::Once;
90
91    #[test]
92    fn lt() {
93        let a: Option<i8> = Option::Some(1);
94        let b: i8 = 2;
95        for _ in 0..1 {
96            let actual = assert_some_ne_x_as_result!(a, b);
97            assert_eq!(actual.unwrap(), 1);
98        }
99    }
100
101    #[test]
102    fn lt_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            2
121        }
122
123        assert_eq!(A.is_completed(), false);
124        assert_eq!(B.is_completed(), false);
125        let result = assert_some_ne_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 gt() {
133        let a: Option<i8> = Option::Some(2);
134        let b: i8 = 1;
135        for _ in 0..1 {
136            let actual = assert_some_ne_x_as_result!(a, b);
137            assert_eq!(actual.unwrap(), 2);
138        }
139    }
140
141    #[test]
142    fn gt_once() {
143        static A: Once = Once::new();
144        fn a() -> Option<i8> {
145            if A.is_completed() {
146                panic!("A.is_completed()")
147            } else {
148                A.call_once(|| {})
149            }
150            Option::Some(2)
151        }
152
153        static B: Once = Once::new();
154        fn b() -> i8 {
155            if B.is_completed() {
156                panic!("B.is_completed()")
157            } else {
158                B.call_once(|| {})
159            }
160            1
161        }
162
163        assert_eq!(A.is_completed(), false);
164        assert_eq!(B.is_completed(), false);
165        let result = assert_some_ne_x_as_result!(a(), b());
166        assert!(result.is_ok());
167        assert_eq!(A.is_completed(), true);
168        assert_eq!(B.is_completed(), true);
169    }
170
171    #[test]
172    fn eq() {
173        let a: Option<i8> = Option::Some(1);
174        let b: i8 = 1;
175        let actual = assert_some_ne_x_as_result!(a, b);
176        let message = concat!(
177            "assertion failed: `assert_some_ne_x!(a, b)`\n",
178            "https://docs.rs/assertables/9.8.4/assertables/macro.assert_some_ne_x.html\n",
179            " a label: `a`,\n",
180            " a debug: `Some(1)`,\n",
181            " a inner: `1`,\n",
182            " b label: `b`,\n",
183            " b debug: `1`"
184        );
185        assert_eq!(actual.unwrap_err(), message);
186    }
187
188    #[test]
189    fn not_some() {
190        let a: Option<i8> = Option::None;
191        let b: i8 = 1;
192        let actual = assert_some_ne_x_as_result!(a, b);
193        let message = concat!(
194            "assertion failed: `assert_some_ne_x!(a, b)`\n",
195            "https://docs.rs/assertables/9.8.4/assertables/macro.assert_some_ne_x.html\n",
196            " a label: `a`,\n",
197            " a debug: `None`,\n",
198            " b label: `b`,\n",
199            " b debug: `1`",
200        );
201        assert_eq!(actual.unwrap_err(), message);
202    }
203}
204
205/// Assert an expression is Some and its value is not equal to an expression.
206///
207/// Pseudocode:<br>
208/// (a ⇒ Some(a1) ⇒ a1) ≠ b
209///
210/// * If true, return `a1`.
211///
212/// * Otherwise, call [`panic!`] with a message and the values of the
213///   expressions with their debug representations.
214///
215/// # Examples
216///
217/// ```rust
218/// use assertables::*;
219/// # use std::panic;
220///
221/// # fn main() {
222/// let a: Option<i8> = Option::Some(1);
223/// let b: i8 = 2;
224/// assert_some_ne_x!(a, b);
225///
226/// # let result = panic::catch_unwind(|| {
227/// // This will panic
228/// let a: Option<i8> = Option::Some(1);
229/// let b: i8 = 1;
230/// assert_some_ne_x!(a, b);
231/// # });
232/// // assertion failed: `assert_some_ne_x!(a, b)`
233/// // https://docs.rs/assertables/…/assertables/macro.assert_some_ne_x.html
234/// //  a label: `a`,
235/// //  a debug: `Some(1)`,
236/// //  a inner: `1`,
237/// //  b label: `b`,
238/// //  b debug: `1`
239/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
240/// # let message = concat!(
241/// #     "assertion failed: `assert_some_ne_x!(a, b)`\n",
242/// #     "https://docs.rs/assertables/9.8.4/assertables/macro.assert_some_ne_x.html\n",
243/// #     " a label: `a`,\n",
244/// #     " a debug: `Some(1)`,\n",
245/// #     " a inner: `1`,\n",
246/// #     " b label: `b`,\n",
247/// #     " b debug: `1`",
248/// # );
249/// # assert_eq!(actual, message);
250/// # }
251/// ```
252///
253/// # Module macros
254///
255/// * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
256/// * [`assert_some_ne_x_as_result`](macro@crate::assert_some_ne_x_as_result)
257/// * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_x)
258///
259#[macro_export]
260macro_rules! assert_some_ne_x {
261    ($a:expr, $b:expr $(,)?) => {
262        match $crate::assert_some_ne_x_as_result!($a, $b) {
263            Ok(x) => x,
264            Err(err) => panic!("{}", err),
265        }
266    };
267    ($a:expr, $b:expr, $($message:tt)+) => {
268        match $crate::assert_some_ne_x_as_result!($a, $b) {
269            Ok(x) => x,
270            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
271        }
272    };
273}
274
275#[cfg(test)]
276mod test_assert_some_ne_x {
277    use std::panic;
278
279    #[test]
280    fn ne() {
281        let a: Option<i8> = Option::Some(1);
282        let b: i8 = 2;
283        for _ in 0..1 {
284            let actual = assert_some_ne_x!(a, b);
285            assert_eq!(actual, 1);
286        }
287    }
288
289    #[test]
290    fn eq() {
291        let a: Option<i8> = Option::Some(1);
292        let b: i8 = 1;
293        let result = panic::catch_unwind(|| {
294            let _actual = assert_some_ne_x!(a, b);
295        });
296        let message = concat!(
297            "assertion failed: `assert_some_ne_x!(a, b)`\n",
298            "https://docs.rs/assertables/9.8.4/assertables/macro.assert_some_ne_x.html\n",
299            " a label: `a`,\n",
300            " a debug: `Some(1)`,\n",
301            " a inner: `1`,\n",
302            " b label: `b`,\n",
303            " b debug: `1`"
304        );
305        assert_eq!(
306            result
307                .unwrap_err()
308                .downcast::<String>()
309                .unwrap()
310                .to_string(),
311            message
312        );
313    }
314
315    #[test]
316    fn not_some() {
317        let a: Option<i8> = Option::None;
318        let b: i8 = 1;
319        let result = panic::catch_unwind(|| {
320            let _actual = assert_some_ne_x!(a, b);
321        });
322        let message = concat!(
323            "assertion failed: `assert_some_ne_x!(a, b)`\n",
324            "https://docs.rs/assertables/9.8.4/assertables/macro.assert_some_ne_x.html\n",
325            " a label: `a`,\n",
326            " a debug: `None`,\n",
327            " b label: `b`,\n",
328            " b debug: `1`",
329        );
330        assert_eq!(
331            result
332                .unwrap_err()
333                .downcast::<String>()
334                .unwrap()
335                .to_string(),
336            message
337        );
338    }
339}
340
341/// Assert an expression is Some and its value is not equal to an expression.
342///
343/// Pseudocode:<br>
344/// (a ⇒ Some(a1) ⇒ a1) ≠ b
345///
346/// This macro provides the same statements as [`assert_some_ne_x`](macro.assert_some_ne_x.html),
347/// except this macro's statements are only enabled in non-optimized
348/// builds by default. An optimized build will not execute this macro's
349/// statements unless `-C debug-assertions` is passed to the compiler.
350///
351/// This macro is useful for checks that are too expensive to be present
352/// in a release build but may be helpful during development.
353///
354/// The result of expanding this macro is always type checked.
355///
356/// An unchecked assertion allows a program in an inconsistent state to
357/// keep running, which might have unexpected consequences but does not
358/// introduce unsafety as long as this only happens in safe code. The
359/// performance cost of assertions, however, is not measurable in general.
360/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
361/// after thorough profiling, and more importantly, only in safe code!
362///
363/// This macro is intended to work in a similar way to
364/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
365///
366/// # Module macros
367///
368/// * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
369/// * [`assert_some_ne_x`](macro@crate::assert_some_ne_x)
370/// * [`debug_assert_some_ne_x`](macro@crate::debug_assert_some_ne_x)
371///
372#[macro_export]
373macro_rules! debug_assert_some_ne_x {
374    ($($arg:tt)*) => {
375        if $crate::cfg!(debug_assertions) {
376            $crate::assert_some_ne_x!($($arg)*);
377        }
378    };
379}