1use crate::error::CommandExtError;
4use std::process::{Command, Output};
5
6pub trait CommandExtCheck {
8 type Error;
10
11 fn check(&mut self) -> Result<Output, Self::Error>;
14}
15
16impl CommandExtCheck for Command {
17 type Error = CommandExtError;
18
19 fn check(&mut self) -> Result<Output, Self::Error> {
22 self.output().map_err(CommandExtError::from).and_then(|r| {
23 r.status
24 .success()
25 .then_some(r.clone())
26 .ok_or_else(|| CommandExtError::Check {
27 status: r.status,
28 stdout: String::from_utf8_lossy(&r.stdout).to_string(),
29 stderr: String::from_utf8_lossy(&r.stderr).to_string(),
30 })
31 })
32 }
33}
34
35#[cfg(test)]
36mod test {
37 use std::process::Command;
38
39 use crate::{CommandExtCheck, CommandExtError};
40
41 #[test]
42 #[cfg_attr(miri, ignore)]
43 fn test_success() {
45 let output = Command::new("echo").arg("x").check();
46 match output {
47 Ok(output) => assert_eq!(
48 String::from_utf8_lossy(&output.stdout),
49 "x\n",
50 "Output mismatch"
51 ),
52 Err(e) => panic!("Unexpected error from command: {}", e),
53 };
54 }
55
56 #[test]
57 #[cfg_attr(miri, ignore)]
58 fn test_nocmd() {
60 let output = Command::new("asdfasdfasdfasdfjkljkljkl").check();
61
62 match output {
63 Ok(output) => panic!("Unexpected success from command: {:?}", output),
64 Err(e) => assert!(matches!(e, CommandExtError::StdIoError(_))),
65 }
66 }
67
68 #[test]
69 #[cfg_attr(miri, ignore)]
70 fn test_failure() {
72 let output = Command::new("false").check();
73
74 match output {
75 Ok(output) => panic!("Unexpected success from command: {:?}", output),
76 Err(e) => assert!(matches!(
77 e,
78 CommandExtError::Check {
79 status: _,
80 stdout: _,
81 stderr: _
82 }
83 )),
84 }
85 }
86}