Skip to main content

assertables/assert_command/
assert_command_stdout_string_contains.rs

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