#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Verdict {
Aligned,
Drifting,
Diverged,
}
const ALIGNED: &str = "aligned";
const DRIFTING: &str = "drifting";
const DIVERGED: &str = "diverged";
impl Verdict {
pub(crate) fn token(self) -> &'static str {
match self {
Self::Aligned => ALIGNED,
Self::Drifting => DRIFTING,
Self::Diverged => DIVERGED,
}
}
pub fn parse(token: &str) -> Option<Self> {
match token.trim().to_ascii_lowercase().as_str() {
ALIGNED => Some(Self::Aligned),
DRIFTING => Some(Self::Drifting),
DIVERGED => Some(Self::Diverged),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Reply {
pub verdict: Verdict,
pub reason: String,
}
pub fn read(text: &str) -> Option<Reply> {
let line = text.lines().map(str::trim).find(|l| !l.is_empty())?;
let (head, rest) = match line.split_once(':') {
Some(split) => split,
None => line.split_once(char::is_whitespace).unwrap_or((line, "")),
};
Some(Reply {
verdict: Verdict::parse(head)?,
reason: rest.trim().trim_start_matches(['-', '—']).trim().to_owned(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_token_round_trips() {
for verdict in [Verdict::Aligned, Verdict::Drifting, Verdict::Diverged] {
assert_eq!(Verdict::parse(verdict.token()), Some(verdict));
}
assert_eq!(Verdict::parse("ALIGNED "), Some(Verdict::Aligned));
assert_eq!(Verdict::parse("mostly aligned"), None);
}
#[test]
fn the_verdicts_order_by_divergence() {
assert!(Verdict::Aligned < Verdict::Drifting && Verdict::Drifting < Verdict::Diverged);
}
#[test]
fn the_asked_for_shape_reads() {
assert_eq!(
read("diverged: it is refactoring an unrelated crate\n"),
Some(Reply {
verdict: Verdict::Diverged,
reason: "it is refactoring an unrelated crate".to_owned(),
})
);
}
#[test]
fn a_missing_colon_a_dash_and_leading_blanks_still_read() {
assert_eq!(
read("\n\n aligned — writing the tests it was asked for \nand more\n").expect("read"),
Reply {
verdict: Verdict::Aligned,
reason: "writing the tests it was asked for".to_owned(),
},
"the first non-empty line is the whole answer"
);
assert_eq!(
read("drifting").expect("read").reason,
"",
"a bare verdict is a verdict with no sentence, not a failure"
);
}
#[test]
fn an_unreadable_reply_is_not_a_verdict() {
assert_eq!(read(""), None);
assert_eq!(read("I cannot judge this.\n"), None);
assert_eq!(read(" \n"), None);
}
}