1use crate::context::Host;
4
5pub struct Random<'a> {
7 host: &'a dyn Host,
8}
9
10impl<'a> Random<'a> {
11 #[must_use]
12 pub(crate) fn new(host: &'a dyn Host) -> Self {
13 Self { host }
14 }
15 #[must_use]
17 pub fn bytes(&self, n: usize) -> Vec<u8> {
18 self.host.random_bytes(n)
19 }
20 #[must_use]
22 pub fn uuid(&self) -> String {
23 let mut b = self.host.random_bytes(16);
24 b.resize(16, 0); b[6] = (b[6] & 0x0f) | 0x40; b[8] = (b[8] & 0x3f) | 0x80; format!(
28 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
29 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]
30 )
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use crate::Context;
37 use crate::testing::MockHost;
38
39 #[test]
40 fn bytes_passthrough_returns_requested_length() {
41 let host = MockHost::new().with_random(&[1, 2, 3]);
42 let ctx = Context::new(&host, "/w".into(), "s".into());
43 assert_eq!(ctx.random().bytes(5), vec![1, 2, 3, 1, 2]); }
45
46 #[test]
47 fn uuid_is_v4_formatted_and_deterministic_under_mock() {
48 let host = MockHost::new().with_random(&[0xab]); let ctx = Context::new(&host, "/w".into(), "s".into());
50 let u = ctx.random().uuid();
51 assert_eq!(u, "abababab-abab-4bab-abab-abababababab");
53 assert_eq!(u, ctx.random().uuid(), "deterministic under a fixed mock seed");
54 }
55}