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}