use once_cell::sync::Lazy;
use rand::{distributions::Alphanumeric, Rng};
use rand_seeder::Seeder;
use std::{cell::RefCell, io::Write, path::Path};
pub type TestRng = rand_chacha::ChaCha12Rng;
static SEED: Lazy<String> = Lazy::new(|| {
if let Ok(seed) = std::env::var("TEST_RNG_SEED") {
println!("EnvVar test seed is \"{seed}\".");
seed
} else {
let mut rng = rand::thread_rng();
let seed: String = (&mut rng)
.sample_iter(Alphanumeric)
.take(7)
.map(char::from)
.collect();
println!("Generated test seed is \"{seed}\".");
seed
}
});
static RNG: Lazy<TestRng> = Lazy::new(|| {
let seed = SEED.clone();
Seeder::from(seed).make_rng()
});
thread_local! {
static RNG_ALREADY_USED: RefCell<bool> = const { RefCell::new(false) };
}
pub fn get() -> TestRng {
if RNG_ALREADY_USED.with_borrow(|b| *b) {
panic!("RNG should only be got once per test.");
}
RNG_ALREADY_USED.with_borrow_mut(|b| *b = true);
println!("The seed is {}.", SEED.as_str());
RNG.clone()
}
pub fn save_to_file(rng: &TestRng, path: impl AsRef<Path>) {
let data = bincode::serialize(rng).unwrap();
let mut file = std::fs::File::create(path).unwrap();
file.write_all(&data).unwrap();
}
pub fn load_from_file(path: impl AsRef<Path>) -> TestRng {
let data = std::fs::read(path).unwrap();
bincode::deserialize(&data).unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn cannot_be_called_twice() {
get();
get();
}
}