Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ambient-randomness

Level: warn · Article: Tests

What it checks

rand::random(), rand::thread_rng(), rand::rng(), StdRng::from_entropy() and friends, anywhere but main. A global generator makes the code correct on average and impossible to replay when it is not.

Don’t

#![allow(unused)]
fn main() {
fn pick_winner(entries: &[Entry]) -> &Entry {
    &entries[rand::thread_rng().gen_range(0..entries.len())]
}
}

The bug report says “the same person won twice”. You cannot reproduce it.

Do

fn pick_winner<'a>(entries: &'a [Entry], rng: &mut impl Rng) -> &'a Entry {
    &entries[rng.gen_range(0..entries.len())]
}

fn main() {
    // one generator, seeded once, handed down to everything that draws
    let mut rng = StdRng::from_entropy();
    Raffle::open(&mut rng).run();
}

#[test]
fn the_draw_is_reproducible() {
    // the same seed, the same winner, every run
    let entries = [Entry::new("ada"), Entry::new("grace")];
    let mut rng = StdRng::seed_from_u64(42);
    assert_eq!(pick_winner(&entries, &mut rng).name(), "grace");
}

Silence it

#![allow(unused)]
fn main() {
// rabot: allow(ambient-randomness) jitter on a retry delay; the exact value never matters
let jitter = rand::random::<u64>() % 50;
}