#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ReviewMode {
#[default]
Now,
Later,
Auto,
}
impl ReviewMode {
pub fn name(self) -> &'static str {
match self {
ReviewMode::Now => "now",
ReviewMode::Later => "later",
ReviewMode::Auto => "auto",
}
}
pub fn parse(s: &str) -> Option<ReviewMode> {
match s.trim().to_ascii_lowercase().as_str() {
"now" => Some(ReviewMode::Now),
"later" => Some(ReviewMode::Later),
"auto" => Some(ReviewMode::Auto),
_ => None,
}
}
pub fn describe(self) -> &'static str {
match self {
ReviewMode::Now => "drafts a run stages are offered for review when it finishes",
ReviewMode::Later => "drafts wait in the outbox until you get to them",
ReviewMode::Auto => {
"untainted drafts a run stages release when it finishes cleanly — \
tainted drafts still stop for review, and an errored or \
early-stopped run releases nothing"
}
}
}
}
pub fn auto_releases(mode: ReviewMode, tainted: bool, finished_clean: bool) -> bool {
mode == ReviewMode::Auto && !tainted && finished_clean
}
#[cfg(test)]
mod tests {
use super::*;
const MODES: [ReviewMode; 3] = [ReviewMode::Now, ReviewMode::Later, ReviewMode::Auto];
#[test]
fn tainted_drafts_never_auto_release_whatever_the_mode() {
for mode in MODES {
assert!(
!auto_releases(mode, true, true),
"{mode:?} must not release a tainted draft"
);
}
assert!(auto_releases(ReviewMode::Auto, false, true));
assert!(!auto_releases(ReviewMode::Now, false, true));
assert!(!auto_releases(ReviewMode::Later, false, true));
}
#[test]
fn an_early_stopped_run_releases_nothing_in_any_mode() {
for mode in MODES {
for tainted in [true, false] {
assert!(
!auto_releases(mode, tainted, false),
"{mode:?}/tainted={tainted} must hold an early-stopped run's drafts"
);
}
}
}
#[test]
fn the_mode_words_parse_exactly_and_typos_are_refused() {
assert_eq!(ReviewMode::parse("now"), Some(ReviewMode::Now));
assert_eq!(ReviewMode::parse(" LATER "), Some(ReviewMode::Later));
assert_eq!(ReviewMode::parse("Auto"), Some(ReviewMode::Auto));
for typo in ["always", "sometimes", "on", "", "auto now"] {
assert_eq!(ReviewMode::parse(typo), None, "{typo:?}");
}
assert_eq!(ReviewMode::default(), ReviewMode::Now, "the safe direction");
}
#[test]
fn every_mode_names_itself_and_what_it_does() {
for mode in MODES {
assert_eq!(ReviewMode::parse(mode.name()), Some(mode));
assert!(!mode.describe().is_empty());
}
let auto = ReviewMode::Auto.describe();
assert!(auto.contains("tainted"), "{auto}");
assert!(
auto.contains("early-stopped") || auto.contains("errored"),
"{auto}"
);
}
}