use std::{
sync::{Arc, RwLock},
time::{Duration, SystemTime, UNIX_EPOCH},
};
const DEFAULT_MILLIS_SINCE_EPOCH: u64 = 1431648000000;
#[derive(Debug, Clone)]
pub struct FakeClock {
clock: Arc<RwLock<SystemTime>>,
}
impl Default for FakeClock {
fn default() -> Self {
Self::from(Duration::from_millis(DEFAULT_MILLIS_SINCE_EPOCH))
}
}
impl FakeClock {
pub fn now(&self) -> SystemTime {
*self.clock.read().unwrap()
}
pub fn advance(&self, duration: Duration) {
let mut clock = self.clock.write().unwrap();
*clock += duration;
}
pub fn unwind(&self, duration: Duration) {
let mut clock = self.clock.write().unwrap();
*clock -= duration;
}
pub fn set(&self, t: SystemTime) {
let mut clock = self.clock.write().unwrap();
*clock = t;
}
}
impl From<Duration> for FakeClock {
fn from(value: Duration) -> Self {
Self::from(UNIX_EPOCH + value)
}
}
impl From<SystemTime> for FakeClock {
fn from(t: SystemTime) -> Self {
Self { clock: Arc::new(RwLock::new(t)) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_system_time() {
let now = SystemTime::now();
let clock = FakeClock::from(now);
assert_eq!(clock.now(), now);
}
#[test]
fn from_duration() {
let now = SystemTime::now();
let since_epoch = now.duration_since(UNIX_EPOCH).unwrap();
let clock = FakeClock::from(since_epoch);
assert_eq!(clock.now(), now);
}
#[test]
fn advance_secs() {
let now = SystemTime::now();
let clock = FakeClock::from(now);
clock.advance(Duration::from_secs(1));
assert_eq!(clock.now(), now + Duration::from_secs(1));
}
#[test]
fn advance_nanos() {
let now = SystemTime::now();
let clock = FakeClock::from(now);
clock.advance(Duration::from_nanos(1));
assert_eq!(clock.now(), now + Duration::from_nanos(1));
}
#[test]
fn unwind_secs() {
let now = SystemTime::now();
let clock = FakeClock::from(now);
clock.unwind(Duration::from_secs(1));
assert_eq!(clock.now(), now - Duration::from_secs(1));
}
#[test]
fn unwind_nanos() {
let now = SystemTime::now();
let clock = FakeClock::from(now);
clock.unwind(Duration::from_nanos(1));
assert_eq!(clock.now(), now - Duration::from_nanos(1));
}
#[test]
fn set_time() {
let clock = FakeClock::default();
let t = SystemTime::now();
assert_ne!(clock.now(), t);
clock.set(t);
assert_eq!(clock.now(), t);
}
}