use crate::context::Host;
pub struct Random<'a> {
host: &'a dyn Host,
}
impl<'a> Random<'a> {
#[must_use]
pub(crate) fn new(host: &'a dyn Host) -> Self {
Self { host }
}
#[must_use]
pub fn bytes(&self, n: usize) -> Vec<u8> {
self.host.random_bytes(n)
}
#[must_use]
pub fn uuid(&self) -> String {
let mut b = self.host.random_bytes(16);
b.resize(16, 0); b[6] = (b[6] & 0x0f) | 0x40; b[8] = (b[8] & 0x3f) | 0x80; format!(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
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]
)
}
}
#[cfg(test)]
mod tests {
use crate::Context;
use crate::testing::MockHost;
#[test]
fn bytes_passthrough_returns_requested_length() {
let host = MockHost::new().with_random(&[1, 2, 3]);
let ctx = Context::new(&host, "/w".into(), "s".into());
assert_eq!(ctx.random().bytes(5), vec![1, 2, 3, 1, 2]); }
#[test]
fn uuid_is_v4_formatted_and_deterministic_under_mock() {
let host = MockHost::new().with_random(&[0xab]); let ctx = Context::new(&host, "/w".into(), "s".into());
let u = ctx.random().uuid();
assert_eq!(u, "abababab-abab-4bab-abab-abababababab");
assert_eq!(u, ctx.random().uuid(), "deterministic under a fixed mock seed");
}
}