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