diff options
Diffstat (limited to 'third_party/rust/tokio-timer/tests/support/mod.rs')
-rw-r--r-- | third_party/rust/tokio-timer/tests/support/mod.rs | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/third_party/rust/tokio-timer/tests/support/mod.rs b/third_party/rust/tokio-timer/tests/support/mod.rs new file mode 100644 index 0000000000..244d56b819 --- /dev/null +++ b/third_party/rust/tokio-timer/tests/support/mod.rs @@ -0,0 +1,261 @@ +#![allow(unused_macros, unused_imports, dead_code, deprecated)] + +use tokio_executor::park::{Park, Unpark}; +use tokio_timer::clock::Now; +use tokio_timer::timer::Timer; + +use futures::future::{lazy, Future}; + +use std::marker::PhantomData; +use std::rc::Rc; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; + +macro_rules! assert_ready { + ($f:expr) => {{ + use ::futures::Async::*; + + match $f.poll().unwrap() { + Ready(v) => v, + NotReady => panic!("NotReady"), + } + }}; + ($f:expr, $($msg:expr),+) => {{ + use ::futures::Async::*; + + match $f.poll().unwrap() { + Ready(v) => v, + NotReady => { + let msg = format!($($msg),+); + panic!("NotReady; {}", msg) + } + } + }} +} + +macro_rules! assert_ready_eq { + ($f:expr, $expect:expr) => { + assert_eq!($f.poll().unwrap(), ::futures::Async::Ready($expect)); + }; +} + +macro_rules! assert_not_ready { + ($f:expr) => {{ + let res = $f.poll().unwrap(); + assert!(!res.is_ready(), "actual={:?}", res) + }}; + ($f:expr, $($msg:expr),+) => {{ + let res = $f.poll().unwrap(); + if res.is_ready() { + let msg = format!($($msg),+); + panic!("actual={:?}; {}", res, msg); + } + }}; +} + +macro_rules! assert_elapsed { + ($f:expr) => { + assert!($f.poll().unwrap_err().is_elapsed()); + }; +} + +#[derive(Debug)] +pub struct MockTime { + inner: Inner, + _p: PhantomData<Rc<()>>, +} + +#[derive(Debug)] +pub struct MockNow { + inner: Inner, +} + +#[derive(Debug)] +pub struct MockPark { + inner: Inner, + _p: PhantomData<Rc<()>>, +} + +#[derive(Debug)] +pub struct MockUnpark { + inner: Inner, +} + +type Inner = Arc<Mutex<State>>; + +#[derive(Debug)] +struct State { + base: Instant, + advance: Duration, + unparked: bool, + park_for: Option<Duration>, +} + +pub fn ms(num: u64) -> Duration { + Duration::from_millis(num) +} + +pub trait IntoTimeout { + fn into_timeout(self) -> Option<Duration>; +} + +impl IntoTimeout for Option<Duration> { + fn into_timeout(self) -> Self { + self + } +} + +impl IntoTimeout for Duration { + fn into_timeout(self) -> Option<Duration> { + Some(self) + } +} + +/// Turn the timer state once +pub fn turn<T: IntoTimeout>(timer: &mut Timer<MockPark>, duration: T) { + timer.turn(duration.into_timeout()).unwrap(); +} + +/// Advance the timer the specified amount +pub fn advance(timer: &mut Timer<MockPark>, duration: Duration) { + let inner = timer.get_park().inner.clone(); + let deadline = inner.lock().unwrap().now() + duration; + + while inner.lock().unwrap().now() < deadline { + let dur = deadline - inner.lock().unwrap().now(); + turn(timer, dur); + } +} + +pub fn mocked<F, R>(f: F) -> R +where + F: FnOnce(&mut Timer<MockPark>, &mut MockTime) -> R, +{ + mocked_with_now(Instant::now(), f) +} + +pub fn mocked_with_now<F, R>(now: Instant, f: F) -> R +where + F: FnOnce(&mut Timer<MockPark>, &mut MockTime) -> R, +{ + let mut time = MockTime::new(now); + let park = time.mock_park(); + let now = ::tokio_timer::clock::Clock::new_with_now(time.mock_now()); + + let mut enter = ::tokio_executor::enter().unwrap(); + + ::tokio_timer::clock::with_default(&now, &mut enter, |enter| { + let mut timer = Timer::new(park); + let handle = timer.handle(); + + ::tokio_timer::with_default(&handle, enter, |_| { + lazy(|| Ok::<_, ()>(f(&mut timer, &mut time))) + .wait() + .unwrap() + }) + }) +} + +impl MockTime { + pub fn new(now: Instant) -> MockTime { + let state = State { + base: now, + advance: Duration::default(), + unparked: false, + park_for: None, + }; + + MockTime { + inner: Arc::new(Mutex::new(state)), + _p: PhantomData, + } + } + + pub fn mock_now(&self) -> MockNow { + let inner = self.inner.clone(); + MockNow { inner } + } + + pub fn mock_park(&self) -> MockPark { + let inner = self.inner.clone(); + MockPark { + inner, + _p: PhantomData, + } + } + + pub fn now(&self) -> Instant { + self.inner.lock().unwrap().now() + } + + /// Returns the total amount of time the time has been advanced. + pub fn advanced(&self) -> Duration { + self.inner.lock().unwrap().advance + } + + pub fn advance(&self, duration: Duration) { + let mut inner = self.inner.lock().unwrap(); + inner.advance(duration); + } + + /// The next call to park_timeout will be for this duration, regardless of + /// the timeout passed to `park_timeout`. + pub fn park_for(&self, duration: Duration) { + self.inner.lock().unwrap().park_for = Some(duration); + } +} + +impl Park for MockPark { + type Unpark = MockUnpark; + type Error = (); + + fn unpark(&self) -> Self::Unpark { + let inner = self.inner.clone(); + MockUnpark { inner } + } + + fn park(&mut self) -> Result<(), Self::Error> { + let mut inner = self.inner.lock().map_err(|_| ())?; + + let duration = inner.park_for.take().expect("call park_for first"); + + inner.advance(duration); + Ok(()) + } + + fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> { + let mut inner = self.inner.lock().unwrap(); + + if let Some(duration) = inner.park_for.take() { + inner.advance(duration); + } else { + inner.advance(duration); + } + + Ok(()) + } +} + +impl Unpark for MockUnpark { + fn unpark(&self) { + if let Ok(mut inner) = self.inner.lock() { + inner.unparked = true; + } + } +} + +impl Now for MockNow { + fn now(&self) -> Instant { + self.inner.lock().unwrap().now() + } +} + +impl State { + fn now(&self) -> Instant { + self.base + self.advance + } + + fn advance(&mut self, duration: Duration) { + self.advance += duration; + } +} |