1
use rand::RngCore;
2
use rand::SeedableRng;
3
use rand::rngs::StdRng;
4

            
5
use crate::test_logger;
6

            
7
/// Constructs a random number generator that should be used in random tests. Prints its seed to the console for reproducibility.
8
53
pub fn random_test<F>(iterations: usize, mut test_function: F)
9
53
where
10
53
    F: FnMut(&mut StdRng),
11
{
12
53
    test_logger();
13

            
14
53
    if let Ok(seed_str) = std::env::var("MERC_SEED") {
15
        let seed = seed_str.parse::<u64>().expect("MERC_SEED must be a valid u64");
16
        println!("seed: {seed} (fixed by MERC_SEED)");
17
        let mut rng = StdRng::seed_from_u64(seed);
18
        for _ in 0..iterations {
19
            test_function(&mut rng);
20
        }
21
        return;
22
53
    }
23

            
24
53
    let seed: u64 = rand::random();
25
53
    println!("random seed: {seed} (use MERC_SEED=<seed> to set fixed seed)");
26
53
    let mut rng = StdRng::seed_from_u64(seed);
27

            
28
6120
    for _ in 0..iterations {
29
6120
        test_function(&mut rng);
30
6120
    }
31
53
}
32

            
33
/// Can be used to run a random test with a specific seed for reproducibility.
34
pub fn random_test_seeded<F>(seed: u64, iterations: usize, mut test_function: F)
35
where
36
    F: FnMut(&mut StdRng),
37
{
38
    test_logger();
39

            
40
    println!("seed: {seed}");
41
    let mut rng = StdRng::seed_from_u64(seed);
42

            
43
    for _ in 0..iterations {
44
        test_function(&mut rng);
45
    }
46
}
47

            
48
1
pub fn random_test_threads<C, F, G>(iterations: usize, num_threads: usize, init_function: G, test_function: F)
49
1
where
50
1
    C: Send + 'static,
51
1
    F: Fn(&mut StdRng, &mut C) + Copy + Send + Sync + 'static,
52
1
    G: Fn() -> C,
53
{
54
1
    test_logger();
55

            
56
1
    let mut threads = vec![];
57

            
58
1
    let seed: u64 = rand::random();
59
1
    println!("seed: {seed}");
60
1
    let mut rng = StdRng::seed_from_u64(seed);
61

            
62
1
    for _ in 0..num_threads {
63
20
        let mut rng = StdRng::seed_from_u64(rng.next_u64());
64
20
        let mut init = init_function();
65
20
        threads.push(std::thread::spawn(move || {
66
100000
            for _ in 0..iterations {
67
100000
                test_function(&mut rng, &mut init);
68
100000
            }
69
20
        }));
70
    }
71

            
72
20
    for thread in threads {
73
20
        let _ = thread.join();
74
20
    }
75
1
}