use rand::rngs::OsRng;
use rand::seq::SliceRandom as _;
use std::sync::OnceLock;
const WORDLIST_RAW: &str = include_str!("../../data/eff-wordlist.txt");
fn words() -> &'static [&'static str] {
static WORDS: OnceLock<Vec<&'static str>> = OnceLock::new();
WORDS.get_or_init(|| {
WORDLIST_RAW
.lines()
.filter_map(|line| line.split_whitespace().nth(1))
.collect()
})
}
pub fn suggest_passphrase(word_count: usize) -> String {
let w = words();
let mut rng = OsRng;
let chosen: Vec<&str> = (0..word_count)
.map(|_| *w.choose(&mut rng).expect("word list must not be empty"))
.collect();
chosen.join(" ")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn wordlist_has_7776_entries() {
assert_eq!(words().len(), 7776);
}
#[test]
fn suggest_4_words_has_3_spaces() {
assert_eq!(suggest_passphrase(4).matches(' ').count(), 3);
}
#[test]
fn suggest_is_non_empty() {
assert!(!suggest_passphrase(4).is_empty());
}
#[test]
fn two_suggestions_differ() {
assert_ne!(suggest_passphrase(4), suggest_passphrase(4));
}
}