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