use super::TestOutputDisplay;
use crate::reporter::events::CancelReason;
use serde::Deserialize;
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize)]
#[cfg_attr(test, derive(test_strategy::Arbitrary))]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum StatusLevel {
None,
Fail,
Retry,
Slow,
Leak,
Pass,
Skip,
All,
}
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize)]
#[cfg_attr(test, derive(test_strategy::Arbitrary))]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum FinalStatusLevel {
None,
Fail,
#[serde(alias = "retry")]
Flaky,
Slow,
Skip,
Leak,
Pass,
All,
}
pub(crate) struct StatusLevels {
pub(crate) status_level: StatusLevel,
pub(crate) final_status_level: FinalStatusLevel,
}
impl StatusLevels {
pub(super) fn compute_output_on_test_finished(
&self,
display: TestOutputDisplay,
cancel_status: Option<CancelReason>,
test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) -> OutputOnTestFinished {
let write_status_line = self.status_level >= test_status_level;
let is_immediate = display.is_immediate();
let is_final = display.is_final() || self.final_status_level >= test_final_status_level;
let show_immediate = is_immediate && cancel_status <= Some(CancelReason::Signal);
let store_final = if is_final && cancel_status < Some(CancelReason::Signal)
|| !is_immediate && is_final && cancel_status == Some(CancelReason::Signal)
{
OutputStoreFinal::Yes {
display_output: display.is_final(),
}
} else if is_immediate && is_final && cancel_status == Some(CancelReason::Signal) {
OutputStoreFinal::Yes {
display_output: false,
}
} else {
OutputStoreFinal::No
};
OutputOnTestFinished {
write_status_line,
show_immediate,
store_final,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub(super) struct OutputOnTestFinished {
pub(super) write_status_line: bool,
pub(super) show_immediate: bool,
pub(super) store_final: OutputStoreFinal,
}
#[derive(Debug, PartialEq, Eq)]
pub(super) enum OutputStoreFinal {
No,
Yes { display_output: bool },
}
#[cfg(test)]
mod tests {
use super::*;
use test_strategy::proptest;
#[proptest(cases = 64)]
fn on_test_finished_dont_write_status_line(
display: TestOutputDisplay,
cancel_status: Option<CancelReason>,
#[filter(StatusLevel::Pass < #test_status_level)] test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
display,
cancel_status,
test_status_level,
test_final_status_level,
);
assert!(!actual.write_status_line);
}
#[proptest(cases = 64)]
fn on_test_finished_write_status_line(
display: TestOutputDisplay,
cancel_status: Option<CancelReason>,
#[filter(StatusLevel::Pass >= #test_status_level)] test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
display,
cancel_status,
test_status_level,
test_final_status_level,
);
assert!(actual.write_status_line);
}
#[proptest(cases = 64)]
fn on_test_finished_with_interrupt(
display: TestOutputDisplay,
test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
display,
Some(CancelReason::Interrupt),
test_status_level,
test_final_status_level,
);
assert!(!actual.show_immediate);
assert_eq!(actual.store_final, OutputStoreFinal::No);
}
#[proptest(cases = 64)]
fn on_test_finished_dont_show_immediate(
#[filter(!#display.is_immediate())] display: TestOutputDisplay,
cancel_status: Option<CancelReason>,
test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
display,
cancel_status,
test_status_level,
test_final_status_level,
);
assert!(!actual.show_immediate);
}
#[proptest(cases = 64)]
fn on_test_finished_show_immediate(
#[filter(#display.is_immediate())] display: TestOutputDisplay,
#[filter(#cancel_status <= Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
display,
cancel_status,
test_status_level,
test_final_status_level,
);
assert!(actual.show_immediate);
}
#[proptest(cases = 64)]
fn on_test_finished_dont_store_final(
#[filter(!#display.is_final())] display: TestOutputDisplay,
cancel_status: Option<CancelReason>,
test_status_level: StatusLevel,
#[filter(FinalStatusLevel::Fail < #test_final_status_level)]
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
display,
cancel_status,
test_status_level,
test_final_status_level,
);
assert_eq!(actual.store_final, OutputStoreFinal::No);
}
#[proptest(cases = 64)]
fn on_test_finished_store_final_1(
#[filter(#cancel_status <= Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
TestOutputDisplay::Final,
cancel_status,
test_status_level,
test_final_status_level,
);
assert_eq!(
actual.store_final,
OutputStoreFinal::Yes {
display_output: true
}
);
}
#[proptest(cases = 64)]
fn on_test_finished_store_final_2(
#[filter(#cancel_status < Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
TestOutputDisplay::ImmediateFinal,
cancel_status,
test_status_level,
test_final_status_level,
);
assert_eq!(
actual.store_final,
OutputStoreFinal::Yes {
display_output: true
}
);
}
#[proptest(cases = 64)]
fn on_test_finished_store_final_3(
test_status_level: StatusLevel,
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
TestOutputDisplay::ImmediateFinal,
Some(CancelReason::Signal),
test_status_level,
test_final_status_level,
);
assert_eq!(
actual.store_final,
OutputStoreFinal::Yes {
display_output: false,
}
);
}
#[proptest(cases = 64)]
fn on_test_finished_store_final_4(
#[filter(!#display.is_final())] display: TestOutputDisplay,
#[filter(#cancel_status <= Some(CancelReason::Signal))] cancel_status: Option<CancelReason>,
test_status_level: StatusLevel,
#[filter(FinalStatusLevel::Fail >= #test_final_status_level)]
test_final_status_level: FinalStatusLevel,
) {
let status_levels = StatusLevels {
status_level: StatusLevel::Pass,
final_status_level: FinalStatusLevel::Fail,
};
let actual = status_levels.compute_output_on_test_finished(
display,
cancel_status,
test_status_level,
test_final_status_level,
);
assert_eq!(
actual.store_final,
OutputStoreFinal::Yes {
display_output: false,
}
);
}
}