use std::time::{Duration, SystemTime};
pub trait Clock: Send + Sync {
fn now(&self) -> SystemTime;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SystemClock;
impl Clock for SystemClock {
fn now(&self) -> SystemTime {
SystemTime::now()
}
}
pub trait Sleeper: Send + Sync {
fn sleep(&self, duration: Duration) -> impl std::future::Future<Output = ()> + Send;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct TokioSleeper;
impl Sleeper for TokioSleeper {
async fn sleep(&self, duration: Duration) {
tokio::time::sleep(duration).await;
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct InstantSleeper;
impl Sleeper for InstantSleeper {
async fn sleep(&self, _duration: Duration) {
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration;
struct MockClock {
secs: AtomicU64,
}
impl MockClock {
fn new(initial_secs: u64) -> Self {
Self {
secs: AtomicU64::new(initial_secs),
}
}
fn advance(&self, secs: u64) {
self.secs.fetch_add(secs, Ordering::SeqCst);
}
}
impl Clock for MockClock {
fn now(&self) -> SystemTime {
SystemTime::UNIX_EPOCH + Duration::from_secs(self.secs.load(Ordering::SeqCst))
}
}
#[test]
fn system_clock_returns_current_time() {
let clock = SystemClock;
let before = SystemTime::now();
let result = clock.now();
let after = SystemTime::now();
assert!(result >= before);
assert!(result <= after);
}
#[test]
fn system_clock_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<SystemClock>();
}
fn assert_default<T: Default>() {}
#[test]
fn system_clock_is_default() {
assert_default::<SystemClock>();
}
#[test]
fn system_clock_is_copy() {
let clock1 = SystemClock;
let clock2 = clock1;
let _ = clock1.now();
let _ = clock2.now();
}
#[test]
fn mock_clock_returns_controlled_time() {
let clock = MockClock::new(1_000_000);
let expected = SystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000);
assert_eq!(clock.now(), expected);
}
#[test]
fn mock_clock_can_advance() {
let clock = MockClock::new(0);
assert_eq!(clock.now(), SystemTime::UNIX_EPOCH);
clock.advance(100);
assert_eq!(
clock.now(),
SystemTime::UNIX_EPOCH + Duration::from_secs(100)
);
clock.advance(50);
assert_eq!(
clock.now(),
SystemTime::UNIX_EPOCH + Duration::from_secs(150)
);
}
#[test]
fn mock_clock_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<MockClock>();
}
#[tokio::test]
async fn tokio_sleeper_completes() {
let sleeper = TokioSleeper;
sleeper.sleep(Duration::from_millis(1)).await;
}
#[test]
fn tokio_sleeper_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<TokioSleeper>();
}
#[test]
fn tokio_sleeper_is_default() {
assert_default::<TokioSleeper>();
}
#[test]
fn tokio_sleeper_is_copy() {
let sleeper1 = TokioSleeper;
let sleeper2 = sleeper1;
let _ = sleeper1;
let _ = sleeper2;
}
#[tokio::test]
async fn instant_sleeper_returns_immediately() {
let sleeper = InstantSleeper;
let start = std::time::Instant::now();
sleeper.sleep(Duration::from_secs(1000)).await;
assert!(start.elapsed() < Duration::from_millis(100));
}
#[test]
fn instant_sleeper_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<InstantSleeper>();
}
#[test]
fn instant_sleeper_is_default() {
assert_default::<InstantSleeper>();
}
#[test]
fn instant_sleeper_is_copy() {
let sleeper1 = InstantSleeper;
let sleeper2 = sleeper1;
let _ = sleeper1;
let _ = sleeper2;
}
}