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.2/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.2/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.2/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.2/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 if $guard) {
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 failure() {
195            let a = 'a';
196            let result = panic::catch_unwind(|| {
197                let _actual = assert_not_matches!(a, 'a'..='z');
198            });
199            let message = concat!(
200                "assertion failed: `assert_not_matches!(a)`\n",
201                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_not_matches.html\n",
202                " args: `a, 'a'..='z'`",
203            );
204            assert_eq!(
205                result
206                    .unwrap_err()
207                    .downcast::<String>()
208                    .unwrap()
209                    .to_string(),
210                message
211            );
212        }
213    }
214
215    //// Use Some as per  https://doc.rust-lang.org/std/macro.matches.html
216    mod use_some {
217        use std::panic;
218
219        #[test]
220        fn success() {
221            let a = Some(2);
222            let actual = assert_not_matches!(a, Some(x) if x < 2);
223            assert_eq!(actual, ());
224        }
225
226        #[test]
227        fn failure() {
228            let a = Some(1);
229            let result = panic::catch_unwind(|| {
230                let _actual = assert_not_matches!(a, Some(x) if x < 2);
231            });
232            let message = concat!(
233                "assertion failed: `assert_not_matches!(a)`\n",
234                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_not_matches.html\n",
235                " args: `a, Some(x) if x < 2`",
236            );
237            assert_eq!(
238                result
239                    .unwrap_err()
240                    .downcast::<String>()
241                    .unwrap()
242                    .to_string(),
243                message
244            );
245        }
246    }
247}
248
249/// Assert expression is Some.
250///
251/// This macro provides the same statements as [`assert_not_matches`](macro.assert_not_matches.html),
252/// except this macro's statements are only enabled in non-optimized
253/// builds by default. An optimized build will not execute this macro's
254/// statements unless `-C debug-assertions` is passed to the compiler.
255///
256/// This macro is useful for checks that are too expensive to be present
257/// in a release build but may be helpful during development.
258///
259/// The result of expanding this macro is always type checked.
260///
261/// An unchecked assertion allows a program in an inconsistent state to
262/// keep running, which might have unexpected consequences but does not
263/// introduce unsafety as long as this only happens in safe code. The
264/// performance cost of assertions, however, is not measurable in general.
265/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
266/// after thorough profiling, and more importantly, only in safe code!
267///
268/// This macro is intended to work in a similar way to
269/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
270///
271/// # Module macros
272///
273/// * [`assert_not_matches`](macro@crate::assert_not_matches)
274/// * [`assert_not_matches`](macro@crate::assert_not_matches)
275/// * [`debug_assert_not_matches`](macro@crate::debug_assert_not_matches)
276///
277#[macro_export]
278macro_rules! debug_assert_not_matches {
279    ($($arg:tt)*) => {
280        if $crate::cfg!(debug_assertions) {
281            $crate::assert_not_matches!($($arg)*);
282        }
283    };
284}