use std::{
sync::{Arc, RwLock},
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
};
const RUST1_EPOCH: Duration = Duration::from_secs(1431648000);
#[derive(Debug, Clone)]
pub struct FakeClock(Arc<RwLock<SystemTime>>);
impl Default for FakeClock {
fn default() -> Self {
Self::from(RUST1_EPOCH)
}
}
impl FakeClock {
pub fn now(&self) -> SystemTime {
*self.0.read().unwrap()
}
pub fn advance(&self, duration: Duration) {
let mut clock = self.0.write().unwrap();
*clock += duration;
}
pub fn unwind(&self, duration: Duration) {
let mut clock = self.0.write().unwrap();
*clock -= duration;
}
pub fn set(&self, t: SystemTime) {
let mut clock = self.0.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(Arc::new(RwLock::new(t)))
}
}
#[derive(Debug, Clone)]
pub struct FakeMonotonicClock(Arc<RwLock<Instant>>);
impl Default for FakeMonotonicClock {
fn default() -> Self {
Self::from(Instant::now())
}
}
impl FakeMonotonicClock {
pub fn now(&self) -> Instant {
*self.0.read().unwrap()
}
pub fn advance(&self, duration: Duration) {
let mut clock = self.0.write().unwrap();
*clock += duration;
}
pub fn set(&self, t: Instant) {
let mut clock = self.0.write().unwrap();
*clock = t;
}
}
impl From<Instant> for FakeMonotonicClock {
fn from(value: Instant) -> Self {
Self(Arc::new(RwLock::new(value)))
}
}
#[cfg(test)]
mod tests {
use super::*;
mod simple {
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);
}
}
mod monotonic {
use super::*;
#[test]
fn from_instant() {
let now = Instant::now();
let clock = FakeMonotonicClock::from(now);
assert_eq!(clock.now(), now);
}
#[test]
fn advance_secs() {
let now = Instant::now();
let clock = FakeMonotonicClock::from(now);
clock.advance(Duration::from_secs(1));
assert_eq!(clock.now(), now + Duration::from_secs(1));
}
#[test]
fn advance_nanos() {
let now = Instant::now();
let clock = FakeMonotonicClock::from(now);
clock.advance(Duration::from_nanos(1));
assert_eq!(clock.now(), now + Duration::from_nanos(1));
}
#[test]
fn set_time() {
let clock = FakeMonotonicClock::default();
let t = Instant::now();
assert_ne!(clock.now(), t);
clock.set(t);
assert_eq!(clock.now(), t);
}
}
}