use super::*;
use crate::template::{GitRunner, RealGit};
use crate::workspace::fixture;
struct Fixed(u64);
impl Rng for Fixed {
fn next_u64(&self) -> u64 {
self.0
}
}
fn set(names: &[&str]) -> HashSet<String> {
names.iter().map(|s| (*s).to_owned()).collect()
}
const ABC: &[&str] = &["ash", "bay", "cove"];
type Case = (
&'static [&'static str],
u64,
&'static [&'static str],
Result<&'static str, MintError>,
);
#[test]
fn mint_scans_from_the_draw_and_retries_past_collisions() {
let cases: &[Case] = &[
(ABC, 0, &[], Ok("ash")),
(ABC, 2, &[], Ok("cove")),
(ABC, 5, &[], Ok("cove")),
(ABC, 0, &["ash"], Ok("bay")),
(ABC, 2, &["cove", "ash"], Ok("bay")),
(
&["ash", "bay"],
0,
&["ash", "bay"],
Err(MintError::Exhausted(2)),
),
(&[], 0, &[], Err(MintError::Exhausted(0))),
];
for (words, draw, taken, expect) in cases {
let got = mint_from(words, &Fixed(*draw), &set(taken));
let want = expect.clone().map(str::to_owned);
assert_eq!(got, want, "words={words:?} draw={draw} taken={taken:?}");
}
}
#[test]
fn exhaustion_is_loud_at_both_altitudes() {
let err = MintError::Exhausted(2);
assert_eq!(
err.to_string(),
"name pool exhausted: all 2 words are occupied"
);
assert_eq!(Unavailable::from(err.clone()).to_string(), err.to_string());
}
mod corpus;
#[test]
fn mint_over_the_embedded_list_is_deterministic_and_avoids_the_occupied_set() {
let name = mint(&SplitMix64::from_seed(7), &HashSet::new()).unwrap();
let again = mint(&SplitMix64::from_seed(7), &HashSet::new()).unwrap();
assert_eq!(name, again);
assert!(!name.contains('-'));
assert!(wordlist().contains(&name.as_str()));
let next = mint(&SplitMix64::from_seed(7), &set(&[&name])).unwrap();
assert_ne!(next, name);
}
#[test]
fn splitmix64_advances_and_seeds_from_entropy() {
let rng = SplitMix64::from_seed(0);
let draws: HashSet<u64> = (0..64).map(|_| rng.next_u64()).collect();
assert_eq!(draws.len(), 64, "generator repeated within 64 draws");
assert_ne!(
SplitMix64::from_entropy().next_u64(),
SplitMix64::from_seed(0).next_u64()
);
}
#[test]
fn preflight_validates_a_supplied_name_and_mints_on_omission() {
let (_h, ws) = fixture::workspace();
let git = RealGit::new();
let wt = fixture::spawn_root(&ws, "20260101T000000Z-aaaaaaaa");
super::super::settle(&wt, Some("pale-otter"), &git).unwrap();
git.run(&wt, &["commit", "-m", "settle name"]).unwrap();
assert_eq!(
preflight(&ws, Some("brook"), &git, &Fixed(0)).unwrap(),
"brook"
);
assert!(matches!(
preflight(&ws, Some("pale-otter"), &git, &Fixed(0)),
Err(Unavailable::Taken { .. })
));
let minted = preflight(&ws, None, &git, &SplitMix64::from_seed(7)).unwrap();
assert_eq!(
minted,
preflight(&ws, None, &git, &SplitMix64::from_seed(7)).unwrap()
);
assert!(wordlist().contains(&minted.as_str()));
assert_ne!(minted, "pale-otter");
assert!(matches!(
preflight(Path::new("/nonexistent"), None, &git, &Fixed(0)),
Err(Unavailable::Scan(_))
));
}