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