1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
//! Extension trait to check the output of a command
use crate::error::CommandExtError;
use std::process::{Command, Output};
/// Extension trait for [`std::process::Command`] to check the output of a command
pub trait CommandExtCheck {
/// The error type for the result of checking for an error status
type Error;
/// Check the result of a command, returning an error containing the output and
/// error stream content if the status is not success
fn check(&mut self) -> Result<Output, Self::Error>;
}
impl CommandExtCheck for Command {
type Error = CommandExtError;
/// Check the result of a command, returning an error containing the status, output
/// and error stream content if the status is not success
fn check(&mut self) -> Result<Output, Self::Error> {
self.output().map_err(CommandExtError::from).and_then(|r| {
r.status
.success()
.then_some(r.clone())
.ok_or_else(|| CommandExtError::Check {
status: r.status,
stdout: String::from_utf8_lossy(&r.stdout).to_string(),
stderr: String::from_utf8_lossy(&r.stderr).to_string(),
})
})
}
}
#[cfg(test)]
mod test {
use std::process::Command;
use crate::{CommandExtCheck, CommandExtError};
#[test]
#[cfg_attr(miri, ignore)]
/// Check that a successful command returns a success output
fn test_success() {
let output = Command::new("echo").arg("x").check();
match output {
Ok(output) => assert_eq!(
String::from_utf8_lossy(&output.stdout),
"x\n",
"Output mismatch"
),
Err(e) => panic!("Unexpected error from command: {}", e),
};
}
#[test]
#[cfg_attr(miri, ignore)]
/// Test that a command that doesn't exist returns a wrapped IO error
fn test_nocmd() {
let output = Command::new("asdfasdfasdfasdfjkljkljkl").check();
match output {
Ok(output) => panic!("Unexpected success from command: {:?}", output),
Err(e) => assert!(matches!(e, CommandExtError::StdIoError(_))),
}
}
#[test]
#[cfg_attr(miri, ignore)]
/// Test that a command which fails by returning a nonzero status code returns a check error
fn test_failure() {
let output = Command::new("false").check();
match output {
Ok(output) => panic!("Unexpected success from command: {:?}", output),
Err(e) => assert!(matches!(
e,
CommandExtError::Check {
status: _,
stdout: _,
stderr: _
}
)),
}
}
}