assertables/assert_some/
assert_some.rs

1//!Assert expression is Some.
2//!
3//! Pseudocode:<br>
4//! a is Some
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! let a: Option<i8> = Option::Some(1);
12//! assert_some!(a);
13//! ```
14//!
15//! # Module macros
16//!
17//! * [`assert_some`](macro@crate::assert_some)
18//! * [`assert_some_as_result`](macro@crate::assert_some_as_result)
19//! * [`debug_assert_some`](macro@crate::debug_assert_some)
20
21/// Assert an expression.is_some() is true.
22///
23/// Pseudocode:<br>
24/// a is Some(a1)
25///
26/// * If true, return Result `Ok(a1)`.
27///
28/// * Otherwise, return Result `Err(message)`.
29///
30/// This macro is useful for runtime checks, such as checking parameters,
31/// or sanitizing inputs, or handling different results in different ways.
32///
33/// # Module macros
34///
35/// * [`assert_some`](macro@crate::assert_some)
36/// * [`assert_some_as_result`](macro@crate::assert_some_as_result)
37/// * [`debug_assert_some`](macro@crate::debug_assert_some)
38///
39#[macro_export]
40macro_rules! assert_some_as_result {
41    ($a:expr $(,)?) => {
42        match ($a) {
43            Some(a1) => Ok(a1),
44            _ => Err(format!(
45                concat!(
46                    "assertion failed: `assert_some!(a)`\n",
47                    "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
48                    " option label: `{}`,\n",
49                    " option debug: `{:?}`",
50                ),
51                stringify!($a),
52                $a
53            )),
54        }
55    };
56}
57
58#[cfg(test)]
59mod test_assert_some_as_result {
60    use std::sync::Once;
61
62    #[test]
63    fn success() {
64        let a: Option<i8> = Option::Some(1);
65        for _ in 0..1 {
66            let actual = assert_some_as_result!(a);
67            assert_eq!(actual.unwrap(), 1);
68        }
69    }
70
71    #[test]
72    fn success_once() {
73        static A: Once = Once::new();
74        fn a() -> Option<i8> {
75            if A.is_completed() {
76                panic!("A.is_completed()")
77            } else {
78                A.call_once(|| {})
79            }
80            Option::Some(1)
81        }
82
83        assert_eq!(A.is_completed(), false);
84        let result = assert_some_as_result!(a());
85        assert!(result.is_ok());
86        assert_eq!(A.is_completed(), true);
87    }
88
89    #[test]
90    fn failure() {
91        let a: Option<i8> = Option::None;
92        let actual = assert_some_as_result!(a);
93        let message = concat!(
94            "assertion failed: `assert_some!(a)`\n",
95            "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
96            " option label: `a`,\n",
97            " option debug: `None`",
98        );
99        assert_eq!(actual.unwrap_err(), message);
100    }
101}
102
103/// Assert expression is Some.
104///
105/// Pseudocode:<br>
106/// a is Some(a1)
107///
108/// * If true, return `a1`.
109///
110/// * Otherwise, call [`panic!`] with a message and the values of the
111///   expressions with their debug representations.
112///
113/// # Examples
114///
115/// ```rust
116/// use assertables::*;
117/// # use std::panic;
118///
119/// # fn main() {
120/// let a: Option<i8> = Option::Some(1);
121/// assert_some!(a);
122///
123/// # let result = panic::catch_unwind(|| {
124/// // This will panic
125/// let a: Option<i8> = Option::None;
126/// assert_some!(a);
127/// # });
128/// // assertion failed: `assert_some!(a)`
129/// // https://docs.rs/assertables/…/assertables/macro.assert_some.html
130/// //  option label: `a`,
131/// //  option debug: `None`
132/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
133/// # let message = concat!(
134/// #     "assertion failed: `assert_some!(a)`\n",
135/// #     "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
136/// #     " option label: `a`,\n",
137/// #     " option debug: `None`",
138/// # );
139/// # assert_eq!(actual, message);
140/// # }
141/// ```
142///
143/// # Module macros
144///
145/// * [`assert_some`](macro@crate::assert_some)
146/// * [`assert_some_as_result`](macro@crate::assert_some_as_result)
147/// * [`debug_assert_some`](macro@crate::debug_assert_some)
148///
149#[macro_export]
150macro_rules! assert_some {
151    ($a:expr $(,)?) => {
152        match $crate::assert_some_as_result!($a) {
153            Ok(x) => x,
154            Err(err) => panic!("{}", err),
155        }
156    };
157    ($a:expr, $($message:tt)+) => {
158        match $crate::assert_some_as_result!($a) {
159            Ok(x) => x,
160            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
161        }
162    };
163}
164
165#[cfg(test)]
166mod test_assert_some {
167    use std::panic;
168
169    #[test]
170    fn success() {
171        let a: Option<i8> = Option::Some(1);
172        for _ in 0..1 {
173            let actual = assert_some!(a);
174            assert_eq!(actual, 1);
175        }
176    }
177
178    #[test]
179    fn failure() {
180        let a: Option<i8> = Option::None;
181        let result = panic::catch_unwind(|| {
182            let _actual = assert_some!(a);
183        });
184        let message = concat!(
185            "assertion failed: `assert_some!(a)`\n",
186            "https://docs.rs/assertables/9.8.3/assertables/macro.assert_some.html\n",
187            " option label: `a`,\n",
188            " option debug: `None`",
189        );
190        assert_eq!(
191            result
192                .unwrap_err()
193                .downcast::<String>()
194                .unwrap()
195                .to_string(),
196            message
197        );
198    }
199}
200
201/// Assert expression is Some.
202///
203/// Pseudocode:<br>
204/// a is Some
205///
206/// This macro provides the same statements as [`assert_some`](macro.assert_some.html),
207/// except this macro's statements are only enabled in non-optimized
208/// builds by default. An optimized build will not execute this macro's
209/// statements unless `-C debug-assertions` is passed to the compiler.
210///
211/// This macro is useful for checks that are too expensive to be present
212/// in a release build but may be helpful during development.
213///
214/// The result of expanding this macro is always type checked.
215///
216/// An unchecked assertion allows a program in an inconsistent state to
217/// keep running, which might have unexpected consequences but does not
218/// introduce unsafety as long as this only happens in safe code. The
219/// performance cost of assertions, however, is not measurable in general.
220/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
221/// after thorough profiling, and more importantly, only in safe code!
222///
223/// This macro is intended to work in a similar way to
224/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
225///
226/// # Module macros
227///
228/// * [`assert_some`](macro@crate::assert_some)
229/// * [`assert_some`](macro@crate::assert_some)
230/// * [`debug_assert_some`](macro@crate::debug_assert_some)
231///
232#[macro_export]
233macro_rules! debug_assert_some {
234    ($($arg:tt)*) => {
235        if $crate::cfg!(debug_assertions) {
236            $crate::assert_some!($($arg)*);
237        }
238    };
239}