claims/
assert_some.rs

1/// Asserts that the expression matches a [`Some(_)`] variant, returning the contained value.
2///
3/// ## Uses
4///
5/// Assertions are always checked in both debug and release builds, and cannot be disabled.
6/// See [`debug_assert_some!`] for assertions that are not enabled in release builds by default.
7///
8/// ## Custom messages
9///
10/// This macro has a second form, where a custom panic message can be provided with or without
11/// arguments for formatting. See [`std::fmt`] for syntax for this form.
12///
13/// ## Examples
14///
15/// ```rust
16/// # #[macro_use] extern crate claims;
17/// # fn main() {
18/// let maybe = Some(42);
19///
20/// assert_some!(maybe);
21///
22/// // With a custom message
23/// assert_some!(maybe, "Found it at {:?}", maybe);
24/// # }
25/// ```
26///
27/// A `None` variant will panic:
28///
29/// ```rust,should_panic
30/// # #[macro_use] extern crate claims;
31/// # fn main() {
32/// let maybe = None;
33///
34/// assert_some!(maybe);  // Will panic
35/// # }
36/// ```
37///
38/// [`Some(_)`]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.Some
39/// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html
40/// [`debug_assert_some!`]: crate::debug_assert_some!
41#[macro_export]
42macro_rules! assert_some {
43    ($cond:expr $(,)?) => {
44        match $cond {
45            ::core::option::Option::Some(t) => t,
46            ::core::option::Option::None => {
47                ::core::panic!("assertion failed, expected Some(_), got None");
48            }
49        }
50    };
51    ($cond:expr, $($arg:tt)+) => {
52        match $cond {
53            ::core::option::Option::Some(t) => t,
54            ::core::option::Option::None => {
55                ::core::panic!("assertion failed, expected Some(_), got None: {}", ::core::format_args!($($arg)+));
56            }
57        }
58    };
59}
60
61/// Asserts that the expression matches a [`Some(_)`] variant on debug builds.
62///
63/// This macro behaves nearly the same as [`assert_some!`] on debug builds, although it does not
64/// return the value contained in the `Some` variant. On release builds it is a no-op.
65///
66/// [`Some(_)`]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.Some
67#[macro_export]
68macro_rules! debug_assert_some {
69    ($($arg:tt)*) => {
70        #[cfg(debug_assertions)]
71        $crate::assert_some!($($arg)*);
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    #[test]
78    fn some() {
79        assert_some!(Some(()));
80    }
81
82    #[test]
83    #[should_panic(expected = "assertion failed, expected Some(_), got None")]
84    fn not_some() {
85        assert_some!(None::<()>);
86    }
87
88    #[test]
89    #[should_panic(expected = "assertion failed, expected Some(_), got None: foo")]
90    fn not_some_custom_message() {
91        assert_some!(None::<()>, "foo");
92    }
93
94    #[test]
95    fn some_value_returned() {
96        let value = assert_some!(Some(42));
97        assert_eq!(value, 42);
98    }
99
100    #[test]
101    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
102    fn debug_some() {
103        debug_assert_some!(Some(()));
104    }
105
106    #[test]
107    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
108    #[should_panic(expected = "assertion failed, expected Some(_), got None")]
109    fn debug_not_some() {
110        debug_assert_some!(None::<()>);
111    }
112
113    #[test]
114    #[cfg_attr(not(debug_assertions), ignore = "only run in debug mode")]
115    #[should_panic(expected = "assertion failed, expected Some(_), got None: foo")]
116    fn debug_not_some_custom_message() {
117        debug_assert_some!(None::<()>, "foo");
118    }
119
120    #[test]
121    #[cfg_attr(debug_assertions, ignore = "only run in release mode")]
122    fn debug_release_not_some() {
123        debug_assert_some!(None::<()>);
124    }
125
126    #[test]
127    fn does_not_require_some_to_impl_debug() {
128        enum Foo {
129            Bar,
130        }
131
132        assert_some!(Some(Foo::Bar));
133    }
134
135    #[test]
136    fn debug_does_not_require_some_to_impl_debug() {
137        #[allow(dead_code)]
138        enum Foo {
139            Bar,
140        }
141
142        debug_assert_some!(Some(Foo::Bar));
143    }
144
145    #[test]
146    fn does_not_require_some_to_impl_debug_custom_message() {
147        enum Foo {
148            Bar,
149        }
150
151        assert_some!(Some(Foo::Bar), "foo");
152    }
153
154    #[test]
155    fn debug_does_not_require_some_to_impl_debug_custom_message() {
156        #[allow(dead_code)]
157        enum Foo {
158            Bar,
159        }
160
161        debug_assert_some!(Some(Foo::Bar), "foo");
162    }
163}