assertables/assert_is_match/assert_is_match.rs
1//! Assert a matcher is a match for an expression.
2//!
3//! Pseudocode:<br>
4//! a.is_match(b)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//! use regex::Regex;
11//!
12//! let a = Regex::new(r"lf").expect("regex");
13//! let b = "alfa";
14//! assert_is_match!(a, b);
15//! ```
16//!
17//! # Module macros
18//!
19//! * [`assert_is_match`](macro@crate::assert_is_match)
20//! * [`assert_is_match_as_result`](macro@crate::assert_is_match_as_result)
21//! * [`debug_assert_is_match`](macro@crate::debug_assert_is_match)
22
23/// Assert an expression (such as a regex) is a match for an expression (such as a string).
24///
25/// Pseudocode:<br>
26/// a.is_match(b)
27///
28/// * If true, return Result `Ok(())`.
29///
30/// * Otherwise, return Result `Err(message)`.
31///
32/// This macro is useful for runtime checks, such as checking parameters,
33/// or sanitizing inputs, or handling different results in different ways.
34///
35/// # Module macros
36///
37/// * [`assert_is_match`](macro@crate::assert_is_match)
38/// * [`assert_is_match_as_result`](macro@crate::assert_is_match_as_result)
39/// * [`debug_assert_is_match`](macro@crate::debug_assert_is_match)
40///
41#[macro_export]
42macro_rules! assert_is_match_as_result {
43 ($matcher:expr, $matchee:expr $(,)?) => {{
44 match (&$matcher, &$matchee) {
45 (matcher, matchee) => {
46 if matcher.is_match(matchee) {
47 Ok(())
48 } else {
49 Err(
50 format!(
51 concat!(
52 "assertion failed: `assert_is_match!(matcher, matchee)`\n",
53 "https://docs.rs/assertables/9.5.0/assertables/macro.assert_is_match.html\n",
54 " matcher label: `{}`,\n",
55 " matcher debug: `{:?}`,\n",
56 " matchee label: `{}`,\n",
57 " matchee debug: `{:?}`",
58 ),
59 stringify!($matcher),
60 matcher,
61 stringify!($matchee),
62 matchee,
63 )
64 )
65 }
66 }
67 }
68 }};
69}
70
71#[cfg(test)]
72mod test_assert_is_match_as_result {
73 use regex::Regex;
74
75 #[test]
76 fn success() {
77 let a = Regex::new(r"lf").expect("regex");
78 let b = "alfa";
79 let actual = assert_is_match_as_result!(a, b);
80 assert_eq!(actual.unwrap(), ());
81 }
82
83 #[test]
84 fn failure() {
85 let a = Regex::new(r"lf").expect("regex");
86 let b = "bravo";
87 let actual = assert_is_match_as_result!(a, b);
88 let message = concat!(
89 "assertion failed: `assert_is_match!(matcher, matchee)`\n",
90 "https://docs.rs/assertables/9.5.0/assertables/macro.assert_is_match.html\n",
91 " matcher label: `a`,\n",
92 " matcher debug: `Regex(\"lf\")`,\n",
93 " matchee label: `b`,\n",
94 " matchee debug: `\"bravo\"`"
95 );
96 assert_eq!(actual.unwrap_err(), message);
97 }
98}
99
100/// Assert a matcher is a match for an expression.
101///
102/// Pseudocode:<br>
103/// a.is_match(b)
104///
105/// * If true, return `()`.
106///
107/// * Otherwise, call [`panic!`] with a message and the values of the
108/// expressions with their debug representations.
109///
110/// # Examples
111///
112/// ```rust
113/// use assertables::*;
114/// # use std::panic;
115/// use regex::Regex;
116///
117/// # fn main() {
118/// let a = Regex::new(r"lf").expect("regex");
119/// let b = "alfa";
120/// assert_is_match!(a, b);
121///
122/// # let result = panic::catch_unwind(|| {
123/// // This will panic
124/// let a = Regex::new(r"lf").expect("regex");
125/// let b = "bravo";
126/// assert_is_match!(a, b);
127/// # });
128/// // assertion failed: `assert_is_match!(matcher, matchee)`
129/// // https://docs.rs/assertables/9.5.0/assertables/macro.assert_is_match.html
130/// // matcher label: `a`,
131/// // matcher debug: `Regex(\"lf\")`,
132/// // matchee label: `b`,
133/// // matchee debug: `\"bravo\"`
134/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
135/// # let message = concat!(
136/// # "assertion failed: `assert_is_match!(matcher, matchee)`\n",
137/// # "https://docs.rs/assertables/9.5.0/assertables/macro.assert_is_match.html\n",
138/// # " matcher label: `a`,\n",
139/// # " matcher debug: `Regex(\"lf\")`,\n",
140/// # " matchee label: `b`,\n",
141/// # " matchee debug: `\"bravo\"`"
142/// # );
143/// # assert_eq!(actual, message);
144/// # }
145/// ```
146///
147/// # Module macros
148///
149/// * [`assert_is_match`](macro@crate::assert_is_match)
150/// * [`assert_is_match_as_result`](macro@crate::assert_is_match_as_result)
151/// * [`debug_assert_is_match`](macro@crate::debug_assert_is_match)
152///
153#[macro_export]
154macro_rules! assert_is_match {
155 ($matcher:expr, $matchee:expr $(,)?) => {{
156 match $crate::assert_is_match_as_result!($matcher, $matchee) {
157 Ok(()) => (),
158 Err(err) => panic!("{}", err),
159 }
160 }};
161 ($matcher:expr, $matchee:expr, $($message:tt)+) => {{
162 match $crate::assert_is_match_as_result!($matcher, $matchee) {
163 Ok(()) => (),
164 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
165 }
166 }};
167}
168
169#[cfg(test)]
170mod test_assert_is_match {
171 use regex::Regex;
172 use std::panic;
173
174 #[test]
175 fn success() {
176 let a = Regex::new(r"lf").expect("regex");
177 let b = "alfa";
178 let actual = assert_is_match!(a, b);
179 assert_eq!(actual, ());
180 }
181
182 #[test]
183 fn failure() {
184 let result = panic::catch_unwind(|| {
185 let a = Regex::new(r"lf").expect("regex");
186 let b = "bravo";
187 let _actual = assert_is_match!(a, b);
188 });
189 let message = concat!(
190 "assertion failed: `assert_is_match!(matcher, matchee)`\n",
191 "https://docs.rs/assertables/9.5.0/assertables/macro.assert_is_match.html\n",
192 " matcher label: `a`,\n",
193 " matcher debug: `Regex(\"lf\")`,\n",
194 " matchee label: `b`,\n",
195 " matchee debug: `\"bravo\"`"
196 );
197 assert_eq!(
198 result
199 .unwrap_err()
200 .downcast::<String>()
201 .unwrap()
202 .to_string(),
203 message
204 );
205 }
206}
207
208/// Assert a matcher is a match for an expression.
209///
210/// Pseudocode:<br>
211/// a.is_match(b)
212///
213/// This macro provides the same statements as [`assert_is_match`](macro.assert_is_match.html),
214/// except this macro's statements are only enabled in non-optimized
215/// builds by default. An optimized build will not execute this macro's
216/// statements unless `-C debug-assertions` is passed to the compiler.
217///
218/// This macro is useful for checks that are too expensive to be present
219/// in a release build but may be helpful during development.
220///
221/// The result of expanding this macro is always type checked.
222///
223/// An unchecked assertion allows a program in an inconsistent state to
224/// keep running, which might have unexpected consequences but does not
225/// introduce unsafety as long as this only happens in safe code. The
226/// performance cost of assertions, however, is not measurable in general.
227/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
228/// after thorough profiling, and more importantly, only in safe code!
229///
230/// This macro is intended to work in a similar way to
231/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
232///
233/// # Module macros
234///
235/// * [`assert_is_match`](macro@crate::assert_is_match)
236/// * [`assert_is_match`](macro@crate::assert_is_match)
237/// * [`debug_assert_is_match`](macro@crate::debug_assert_is_match)
238///
239#[macro_export]
240macro_rules! debug_assert_is_match {
241 ($($arg:tt)*) => {
242 if $crate::cfg!(debug_assertions) {
243 $crate::assert_is_match!($($arg)*);
244 }
245 };
246}