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}