//! Shared test helpers: deterministic fakes for the `Clock` / `IdGenerator` //! ports, plus small id constructors. Kept in `tests/` so they never ship in //! the crate proper. #![allow(dead_code)] use std::cell::Cell; use domain::ports::{Clock, IdGenerator}; use uuid::Uuid; /// A clock that always returns the same fixed millisecond value. pub struct FixedClock(pub i64); impl Clock for FixedClock { fn now_millis(&self) -> i64 { self.0 } } /// An id generator producing a deterministic, monotonically increasing sequence /// of UUIDs (`0000...0001`, `0000...0002`, ...). pub struct SeqIdGenerator { next: Cell, } impl SeqIdGenerator { #[must_use] pub fn new() -> Self { Self { next: Cell::new(1) } } } impl Default for SeqIdGenerator { fn default() -> Self { Self::new() } } // `IdGenerator` only requires `&self`, so we use a `Cell` for interior // mutability. The trait demands `Send + Sync`; `Cell` is `!Sync`, so for the // test fake we wrap calls behind `&self` single-threaded usage only. // To satisfy the bound we instead expose a plain method used directly in tests. impl SeqIdGenerator { /// Returns the next UUID in the deterministic sequence. pub fn next_uuid(&self) -> Uuid { let n = self.next.get(); self.next.set(n + 1); Uuid::from_u128(n) } } /// A `Send + Sync` deterministic id generator suitable for the `IdGenerator` /// port (uses an atomic counter). pub struct AtomicSeqIdGenerator { next: std::sync::atomic::AtomicU64, } impl AtomicSeqIdGenerator { #[must_use] pub fn new() -> Self { Self { next: std::sync::atomic::AtomicU64::new(1), } } } impl Default for AtomicSeqIdGenerator { fn default() -> Self { Self::new() } } impl IdGenerator for AtomicSeqIdGenerator { fn new_uuid(&self) -> Uuid { let n = self .next .fetch_add(1, std::sync::atomic::Ordering::Relaxed); Uuid::from_u128(u128::from(n)) } } /// Builds a `NodeId` from a small integer (handy, readable test ids). #[must_use] pub fn node(n: u128) -> domain::NodeId { domain::NodeId::from_uuid(Uuid::from_u128(n)) } /// Builds a `SessionId` from a small integer. #[must_use] pub fn session(n: u128) -> domain::SessionId { domain::SessionId::from_uuid(Uuid::from_u128(n)) }