use std::cell::Cell;
use std::time::{Duration, Instant};
pub trait Clock {
fn now(&self) -> Instant;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SystemClock;
impl Clock for SystemClock {
fn now(&self) -> Instant {
Instant::now()
}
}
#[derive(Debug)]
pub struct MockClock {
now: Cell<Instant>,
}
impl MockClock {
pub fn new() -> Self {
Self {
now: Cell::new(Instant::now()),
}
}
pub fn advance(&self, dur: Duration) {
self.now.set(self.now.get() + dur);
}
pub fn advance_ms(&self, ms: u64) {
self.advance(Duration::from_millis(ms));
}
}
impl Default for MockClock {
fn default() -> Self {
Self::new()
}
}
impl Clock for MockClock {
fn now(&self) -> Instant {
self.now.get()
}
}
impl<C: Clock + ?Sized> Clock for &C {
fn now(&self) -> Instant {
(**self).now()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mock_clock_advances_only_on_demand() {
let c = MockClock::new();
let t0 = c.now();
assert_eq!(c.now(), t0, "does not advance on its own");
c.advance(Duration::from_millis(250));
assert_eq!(c.now().duration_since(t0), Duration::from_millis(250));
c.advance_ms(750);
assert_eq!(c.now().duration_since(t0), Duration::from_millis(1000));
}
#[test]
fn mock_clock_default_matches_new() {
let c = MockClock::default();
let t0 = c.now();
c.advance_ms(5);
assert!(c.now() > t0);
}
#[test]
fn system_clock_is_monotonic_nondecreasing() {
let c = SystemClock;
let a = c.now();
let b = c.now();
assert!(b >= a);
let r: &dyn Clock = &c;
assert!(r.now() >= a);
}
}