use std::thread;
use std::time::{Duration, Instant, SystemTime};
use super::{CoarseSystemClock, FileTime, PreciseSystemClock};
use crate::{Clock, Ticks, Timeline};
const UNIX_EPOCH_TICKS: u64 = 116_444_736_000_000_000;
const ACROSS_A_TICK: Duration = Duration::from_millis(50);
const WITHIN_A_TICK: Duration = Duration::from_micros(50);
fn spin(duration: Duration) {
let started = Instant::now();
while started.elapsed() < duration {
std::hint::spin_loop();
}
}
fn std_now_ticks() -> u64 {
let since_unix = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("after 1970");
let ticks = Ticks::<FileTime>::from_duration(since_unix).expect("fits");
UNIX_EPOCH_TICKS + ticks.count().unsigned_abs()
}
#[test]
fn a_precise_reading_is_what_std_reads_as_the_time() {
let before = std_now_ticks();
let ours = PreciseSystemClock.now().ticks();
let after = std_now_ticks();
assert!(
before <= ours && ours <= after,
"{before} <= {ours} <= {after}"
);
}
#[test]
fn a_coarse_reading_is_a_precise_one_as_of_the_last_tick() {
let before = PreciseSystemClock.now();
let coarse = CoarseSystemClock.now();
let after = PreciseSystemClock.now();
assert!(coarse <= after, "{coarse:?} is ahead of {after:?}");
let lag = before - coarse;
assert!(
lag < Ticks::from_duration(Duration::from_millis(20)).unwrap(),
"{lag:?} behind"
);
}
#[test]
fn the_precise_clock_advances_within_a_fraction_of_a_tick() {
for window in 0..20 {
let before = PreciseSystemClock.now();
spin(WITHIN_A_TICK);
let after = PreciseSystemClock.now();
assert!(after > before, "window {window}: still at {before:?}");
}
}
#[test]
fn the_coarse_clock_advances_across_a_tick() {
let before = CoarseSystemClock.now();
thread::sleep(ACROSS_A_TICK);
assert!(CoarseSystemClock.now() > before);
}
#[test]
fn an_interval_measures_what_instant_measures() {
const RATE_SLACK: Duration = Duration::from_millis(2);
let outer_start = Instant::now();
let start = PreciseSystemClock.now();
let inner_start = Instant::now();
thread::sleep(Duration::from_millis(100));
let inner = inner_start.elapsed();
let end = PreciseSystemClock.now();
let outer = outer_start.elapsed();
let measured = (end - start).to_duration().expect("forwards");
assert!(
inner <= measured + RATE_SLACK,
"{measured:?} is shorter than {inner:?} inside it"
);
assert!(
measured <= outer + RATE_SLACK,
"{measured:?} is longer than {outer:?} around it"
);
}
#[test]
fn system_time_ticks_every_100_nanoseconds() {
assert_eq!(FileTime::ticks_per_second().get(), 10_000_000);
}
#[test]
fn a_clock_is_a_zero_sized_value() {
assert_eq!(size_of::<CoarseSystemClock>(), 0);
assert_eq!(size_of::<PreciseSystemClock>(), 0);
}
#[test]
fn both_halves_of_a_filetime_reach_the_count() {
use windows_sys::Win32::Foundation::FILETIME;
let time = FILETIME {
dwLowDateTime: 0x8765_4321,
dwHighDateTime: 0x0123_4567,
};
assert_eq!(super::point(time).ticks(), 0x0123_4567_8765_4321);
}