use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
use std::process::ExitStatus;
use crate::execution::Capture;
use crate::invocation::Invocation;
#[derive(Clone, Eq, PartialEq, Debug)]
#[non_exhaustive]
pub enum RequireSuccessError {
#[non_exhaustive]
UnsuccessfulCommand {
invocation: Box<Invocation>,
status: ExitStatus,
stderr: Capture,
},
}
impl Display for RequireSuccessError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
match self {
Self::UnsuccessfulCommand {
invocation,
status,
stderr,
} => {
write!(formatter, "the command `{invocation}` ended with {status}")?;
let text = stderr.to_string_lossy();
let reason = text.trim();
if reason.is_empty() {
formatter.write_str(", and it wrote nothing to its standard error")
} else {
write!(formatter, ", and it wrote `{reason}` to its standard error")
}
}
}
}
}
impl Error for RequireSuccessError {}
#[cfg(test)]
mod tests {
#![allow(clippy::missing_panics_doc)]
use super::*;
#[test]
fn require_success_error_is_send_and_sync() {
fn assert_send_and_sync<T: Send + Sync>() {}
assert_send_and_sync::<RequireSuccessError>();
}
#[test]
fn require_success_error_stays_small() {
assert!(size_of::<RequireSuccessError>() <= 6 * size_of::<usize>());
}
}