use std::fmt::Debug;
use std::fmt::Display;
use anyhow::anyhow;
use crate::escaping::Escaper;
use crate::output::Output;
#[derive(Debug, PartialEq)]
pub enum ExecutionTimeout {
Index(usize),
Total,
}
#[derive(Debug, Derivative)]
#[derivative(PartialEq)]
pub enum ExecutionError {
FailedExecution {
index: usize,
#[derivative(PartialEq(compare_with = "stringable_cmp"))]
error: anyhow::Error,
},
AbortedExecutions {
#[derivative(PartialEq(compare_with = "stringable_cmp"))]
error: anyhow::Error,
output: Option<Output>,
},
Timeout(ExecutionTimeout, Vec<Output>),
Failed(usize, Vec<Output>),
Skipped(usize),
}
fn stringable_cmp<T: ToString>(a: T, b: T) -> bool {
a.to_string() == b.to_string()
}
impl ExecutionError {
pub fn aborted(error: anyhow::Error, output: Option<Output>) -> Self {
Self::AbortedExecutions { error, output }
}
pub fn failed(index: usize, error: anyhow::Error) -> Self {
Self::FailedExecution { index, error }
}
pub(super) fn from_execute(
error: anyhow::Error,
index: Option<usize>,
output: Option<Output>,
) -> Self {
match index {
Some(index) => Self::FailedExecution { index, error },
None => Self::AbortedExecutions { error, output },
}
}
}
impl<E> From<E> for ExecutionError
where
E: std::error::Error + Send + Sync + 'static,
{
fn from(error: E) -> Self {
Self::aborted(anyhow!(error), None)
}
}
impl Display for ExecutionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ExecutionError::FailedExecution { index, error } => {
write!(f, "error in execution with index={index}: {error}")
}
ExecutionError::AbortedExecutions { error, output } => {
if let Some(output) = output {
writeln!(
f,
"aborted executions with exit code={}: {}",
output.exit_code, error
)?;
writeln!(f, "{}", &output.to_error_string(&Escaper::default()),)?;
} else {
write!(f, "aborted executions: {error}")?;
}
Ok(())
}
ExecutionError::Timeout(timeout, _output) => match timeout {
ExecutionTimeout::Index(idx) => write!(
f,
"timeout in executing shell expression of test {}",
idx + 1
),
ExecutionTimeout::Total => write!(f, "timeout in executing"),
},
ExecutionError::Failed(idx, _output) => {
write!(f, "test {} failed with fail_fast enabled", idx + 1)
}
ExecutionError::Skipped(idx) => write!(f, "skipped test {}", idx + 1),
}
}
}