use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Outcome {
Pass,
Fail,
NotApplicable,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct CheckResult {
pub name: &'static str,
pub outcome: Outcome,
pub detail: String,
}
impl CheckResult {
pub(super) fn pass(name: &'static str, detail: impl Into<String>) -> Self {
Self {
name,
outcome: Outcome::Pass,
detail: detail.into(),
}
}
pub(super) fn fail(name: &'static str, detail: impl Into<String>) -> Self {
Self {
name,
outcome: Outcome::Fail,
detail: detail.into(),
}
}
pub(super) fn skip(name: &'static str, detail: impl Into<String>) -> Self {
Self {
name,
outcome: Outcome::NotApplicable,
detail: detail.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct Report {
pub(super) results: Vec<CheckResult>,
}
impl Report {
#[must_use]
pub fn results(&self) -> &[CheckResult] {
&self.results
}
#[must_use]
pub fn graded(&self) -> usize {
self.results
.iter()
.filter(|r| r.outcome != Outcome::NotApplicable)
.count()
}
#[must_use]
pub fn passed(&self) -> usize {
self.results
.iter()
.filter(|r| r.outcome == Outcome::Pass)
.count()
}
#[must_use]
pub fn failed(&self) -> usize {
self.graded() - self.passed()
}
#[must_use]
pub fn is_pass(&self) -> bool {
self.graded() > 0 && self.failed() == 0
}
pub fn assert_pass(&self) {
assert!(self.is_pass(), "{self}");
}
}
impl fmt::Display for Report {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "executor conformance:")?;
for r in &self.results {
let mark = match r.outcome {
Outcome::Pass => "pass",
Outcome::Fail => "FAIL",
Outcome::NotApplicable => "n/a ",
};
writeln!(f, " {mark} {:<34} {}", r.name, r.detail)?;
}
write!(
f,
" {} of {} graded checks passed, {} not applicable",
self.passed(),
self.graded(),
self.results.len() - self.graded()
)
}
}