xerv_core/testing/providers/
rng.rs1use parking_lot::Mutex;
6use rand::rngs::StdRng;
7use rand::{Rng, SeedableRng};
8use std::time::{SystemTime, UNIX_EPOCH};
9
10pub trait RngProvider: Send + Sync {
12 fn next_u64(&self) -> u64;
14
15 fn next_f64(&self) -> f64;
17
18 fn fill_bytes(&self, dest: &mut [u8]);
20
21 fn gen_bool(&self, probability: f64) -> bool {
23 self.next_f64() < probability
24 }
25
26 fn gen_range(&self, low: u64, high: u64) -> u64 {
28 low + (self.next_u64() % (high - low))
29 }
30
31 fn is_mock(&self) -> bool;
33}
34
35pub struct RealRng {
39 rng: Mutex<StdRng>,
40}
41
42impl RealRng {
43 pub fn new() -> Self {
45 let seed = SystemTime::now()
47 .duration_since(UNIX_EPOCH)
48 .expect("System time before UNIX epoch")
49 .as_nanos() as u64;
50
51 Self {
52 rng: Mutex::new(StdRng::seed_from_u64(seed)),
53 }
54 }
55}
56
57impl Default for RealRng {
58 fn default() -> Self {
59 Self::new()
60 }
61}
62
63impl RngProvider for RealRng {
64 fn next_u64(&self) -> u64 {
65 self.rng.lock().r#gen()
66 }
67
68 fn next_f64(&self) -> f64 {
69 self.rng.lock().r#gen()
70 }
71
72 fn fill_bytes(&self, dest: &mut [u8]) {
73 self.rng.lock().fill(dest);
74 }
75
76 fn is_mock(&self) -> bool {
77 false
78 }
79}
80
81pub struct MockRng {
99 rng: Mutex<StdRng>,
100 seed: u64,
101}
102
103impl MockRng {
104 pub fn seeded(seed: u64) -> Self {
106 Self {
107 rng: Mutex::new(StdRng::seed_from_u64(seed)),
108 seed,
109 }
110 }
111
112 pub fn seed(&self) -> u64 {
114 self.seed
115 }
116
117 pub fn reset(&self) {
119 *self.rng.lock() = StdRng::seed_from_u64(self.seed);
120 }
121}
122
123impl RngProvider for MockRng {
124 fn next_u64(&self) -> u64 {
125 self.rng.lock().r#gen()
126 }
127
128 fn next_f64(&self) -> f64 {
129 self.rng.lock().r#gen()
130 }
131
132 fn fill_bytes(&self, dest: &mut [u8]) {
133 self.rng.lock().fill(dest);
134 }
135
136 fn is_mock(&self) -> bool {
137 true
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn mock_rng_is_deterministic() {
147 let rng1 = MockRng::seeded(12345);
148 let rng2 = MockRng::seeded(12345);
149
150 let values1: Vec<u64> = (0..10).map(|_| rng1.next_u64()).collect();
151 let values2: Vec<u64> = (0..10).map(|_| rng2.next_u64()).collect();
152
153 assert_eq!(values1, values2);
154 }
155
156 #[test]
157 fn mock_rng_reset() {
158 let rng = MockRng::seeded(42);
159 let first_run: Vec<u64> = (0..5).map(|_| rng.next_u64()).collect();
160
161 rng.reset();
162 let second_run: Vec<u64> = (0..5).map(|_| rng.next_u64()).collect();
163
164 assert_eq!(first_run, second_run);
165 }
166
167 #[test]
168 fn mock_rng_different_seeds_different_values() {
169 let rng1 = MockRng::seeded(1);
170 let rng2 = MockRng::seeded(2);
171
172 let v1 = rng1.next_u64();
173 let v2 = rng2.next_u64();
174
175 assert_ne!(v1, v2);
176 }
177
178 #[test]
179 fn mock_rng_gen_range() {
180 let rng = MockRng::seeded(42);
181
182 for _ in 0..100 {
183 let v = rng.gen_range(10, 20);
184 assert!(v >= 10 && v < 20);
185 }
186 }
187
188 #[test]
189 fn mock_rng_fill_bytes() {
190 let rng = MockRng::seeded(42);
191
192 let mut buf1 = [0u8; 16];
193 let mut buf2 = [0u8; 16];
194
195 rng.fill_bytes(&mut buf1);
196 rng.reset();
197 rng.fill_bytes(&mut buf2);
198
199 assert_eq!(buf1, buf2);
200 }
201}