assertables/assert_program_args/
assert_program_args_stderr_string_contains.rs

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