use super::{EventBuffer, StepKey};
use crate::{
events::StepOutcome,
spec::{EngineSpec, GenericSpec},
};
use std::{fmt, sync::Arc, time::Duration};
#[derive(Clone, Debug)]
pub enum CompletionReason {
StepCompleted(Arc<CompletionInfo>),
SubsequentStarted {
later_step: StepKey,
root_total_elapsed: Duration,
},
ParentCompleted {
parent_step: StepKey,
parent_info: Arc<CompletionInfo>,
},
}
impl CompletionReason {
pub fn step_completed_info(&self) -> Option<&Arc<CompletionInfo>> {
match self {
Self::StepCompleted(info) => Some(info),
Self::SubsequentStarted { .. } | Self::ParentCompleted { .. } => {
None
}
}
}
}
#[derive(Clone, Debug)]
pub struct CompletionInfo {
pub attempt: usize,
pub outcome: StepOutcome<GenericSpec>,
pub root_total_elapsed: Duration,
pub leaf_total_elapsed: Duration,
pub step_elapsed: Duration,
pub attempt_elapsed: Duration,
}
#[derive(Clone, Debug)]
pub enum FailureReason {
StepFailed(Arc<FailureInfo>),
ParentFailed {
parent_step: StepKey,
parent_info: Arc<FailureInfo>,
},
}
impl FailureReason {
pub fn step_failed_info(&self) -> Option<&Arc<FailureInfo>> {
match self {
Self::StepFailed(info) => Some(info),
Self::ParentFailed { .. } => None,
}
}
pub fn message_display<'a, S: EngineSpec>(
&'a self,
buffer: &'a EventBuffer<S>,
) -> FailureMessageDisplay<'a, S> {
FailureMessageDisplay::new(self, buffer)
}
}
#[derive(Clone, Debug)]
pub struct FailureInfo {
pub total_attempts: usize,
pub message: String,
pub causes: Vec<String>,
pub root_total_elapsed: Duration,
pub leaf_total_elapsed: Duration,
pub step_elapsed: Duration,
pub attempt_elapsed: Duration,
}
#[derive(Clone, Debug)]
pub enum AbortReason {
StepAborted(Arc<AbortInfo>),
ParentAborted {
parent_step: StepKey,
parent_info: Arc<AbortInfo>,
},
}
impl AbortReason {
pub fn step_aborted_info(&self) -> Option<&Arc<AbortInfo>> {
match self {
Self::StepAborted(info) => Some(info),
Self::ParentAborted { .. } => None,
}
}
pub fn message_display<'a, S: EngineSpec>(
&'a self,
buffer: &'a EventBuffer<S>,
) -> AbortMessageDisplay<'a, S> {
AbortMessageDisplay::new(self, buffer)
}
}
#[derive(Clone, Debug)]
pub enum WillNotBeRunReason {
PreviousStepFailed {
step: StepKey,
},
ParentStepFailed {
step: StepKey,
},
PreviousStepAborted {
step: StepKey,
},
ParentAborted {
step: StepKey,
},
}
#[derive(Clone, Debug)]
pub struct AbortInfo {
pub attempt: usize,
pub message: String,
pub root_total_elapsed: Duration,
pub leaf_total_elapsed: Duration,
pub step_elapsed: Duration,
pub attempt_elapsed: Duration,
}
pub struct AbortMessageDisplay<'a, S: EngineSpec> {
reason: &'a AbortReason,
buffer: &'a EventBuffer<S>,
}
impl<'a, S: EngineSpec> AbortMessageDisplay<'a, S> {
pub fn new(reason: &'a AbortReason, buffer: &'a EventBuffer<S>) -> Self {
Self { reason, buffer }
}
}
impl<S: EngineSpec> fmt::Display for AbortMessageDisplay<'_, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.reason {
AbortReason::StepAborted(info) => {
write!(f, "{}", info.message)
}
AbortReason::ParentAborted { parent_step, parent_info } => {
let parent_description =
if let Some(step) = self.buffer.get(parent_step) {
&step.step_info().description
} else {
"unknown step"
};
write!(
f,
"parent step \"{}\" aborted with: {}",
parent_description, parent_info.message
)
}
}
}
}
pub struct FailureMessageDisplay<'a, S: EngineSpec> {
reason: &'a FailureReason,
buffer: &'a EventBuffer<S>,
}
impl<'a, S: EngineSpec> FailureMessageDisplay<'a, S> {
pub(crate) fn new(
reason: &'a FailureReason,
buffer: &'a EventBuffer<S>,
) -> Self {
Self { reason, buffer }
}
}
impl<S: EngineSpec> fmt::Display for FailureMessageDisplay<'_, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.reason {
FailureReason::StepFailed(info) => {
write_message_and_causes(f, &info.message, &info.causes)
}
FailureReason::ParentFailed { parent_step, parent_info } => {
let parent_description =
if let Some(step) = self.buffer.get(parent_step) {
&step.step_info().description
} else {
"unknown step"
};
write!(
f,
"parent step \"{parent_description}\" failed with: "
)?;
write_message_and_causes(
f,
&parent_info.message,
&parent_info.causes,
)
}
}
}
}
fn write_message_and_causes(
f: &mut fmt::Formatter<'_>,
message: &str,
causes: &[String],
) -> fmt::Result {
write!(f, "{message}")?;
for cause in causes {
write!(f, ": {cause}")?;
}
Ok(())
}