use std::time::{SystemTime, UNIX_EPOCH};
pub const NO_FIX: &[&str] = &[
"nothing to fix here. that one's all you.",
"got nothing. that one might be on the computer.",
"no idea, honestly. try it again slower?",
"drawing a blank on that one.",
];
pub const NOTHING_TO_FIX: &str = "nothing to fix yet. go break something first.";
pub const ABORTED: &str = "fair enough.";
pub const AFTER_FIX: &[&str] = &[
"happens to the best of us.",
"classic.",
"muscle memory, huh.",
"we don't talk about this one.",
"fixed. nobody saw anything.",
"your secret's safe.",
];
pub fn seed() -> u64 {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|time| time.subsec_nanos())
.unwrap_or(0);
u64::from(nanos) ^ u64::from(std::process::id())
}
pub fn pick<'a>(lines: &[&'a str], seed: u64) -> &'a str {
lines[(seed % lines.len() as u64) as usize]
}
pub fn after_fix(seed: u64, quiet: bool) -> Option<&'static str> {
if quiet || !seed.is_multiple_of(5) {
return None;
}
Some(pick(AFTER_FIX, seed / 5))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn picks_every_line() {
let picked: std::collections::BTreeSet<_> =
(0..20).map(|seed| pick(NO_FIX, seed)).collect();
assert_eq!(picked.len(), NO_FIX.len());
}
#[test]
fn after_fix_is_occasional() {
let spoken = (0..1000)
.filter(|seed| after_fix(*seed, false).is_some())
.count();
assert_eq!(spoken, 200);
}
#[test]
fn quiet_says_nothing() {
assert!((0..1000).all(|seed| after_fix(seed, true).is_none()));
}
#[test]
fn lines_stay_lowercase_and_short() {
for line in NO_FIX
.iter()
.chain(AFTER_FIX)
.chain([&NOTHING_TO_FIX, &ABORTED])
{
assert_eq!(*line, line.to_lowercase(), "{line}");
assert!(line.len() <= 50, "{line}");
}
}
}