assertables/assert_matches/
assert_not_matches.rs

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