1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Helpers which assist in testing applications based on lifeline.

/// Blocks on the future, using a new async runtime.
/// This is helpful in doctests
#[cfg(feature = "tokio-executor")]
pub fn block_on<Fut: std::future::Future<Output = Out>, Out>(fut: Fut) -> Out {
    use tokio::runtime::Builder;

    let runtime = Builder::new_current_thread()
        .build()
        .expect("doctest runtime creation failed");
    runtime.block_on(fut)
}

// forked from https://github.com/tokio-rs/tokio/pull/2522/files
// thank you https://github.com/RadicalZephyr !!
// this was just what Lifeline needs.

/// Asserts that the expression completes within a given number of milliseconds.
///
/// This will invoke the `panic!` macro if the provided future
/// expression fails to complete within the given number of
/// milliseconds. This macro expands to an `await` and must be
/// invoked inside an async context.
///
/// A default timeout of 50ms is used if no duration is passed.
///
/// # Examples
///
/// ```rust
/// use lifeline::assert_completes;
/// use tokio::time::sleep;
///
/// # let fut =
/// async {
///     // Succeeds because default time is longer than delay.
///     assert_completes!(sleep(Duration::from_millis(5)));
/// }
/// # ;
/// # let mut runtime = tokio::runtime::Runtime::new().unwrap();
/// # runtime.block_on(fut);
///```
///
/// ```rust,should_panic
/// use lifeline::assert_completes;
/// use tokio::time::sleep;
///
/// # let fut =
/// async {
///     // Fails because timeout is shorter than delay.
///     assert_completes!(sleep(Duration::from_millis(250)), 10);
/// }
/// # ;
/// # let mut runtime = tokio::runtime::Runtime::new().unwrap();
/// # runtime.block_on(fut);
/// ```
#[macro_export]
macro_rules! assert_completes {
    ($e:expr) => {
        $crate::assert_completes!($e, 50)
    };
    ($e:expr, $time:literal) => {{
        use std::time::Duration;
        use tokio::time::timeout;
        match timeout(Duration::from_millis($time), $e).await {
            Ok(ret) => ret,
            Err(_) => panic!(
                "assertion failed: {} timed out after {} ms",
                stringify!($e),
                $time,
            ),
        }
    }};
}

/// Asserts that the expression does not complete within a given number of milliseconds.
///
/// This will invoke the `panic!` macro if the provided future
/// expression completes within the given number of milliseconds.
/// This macro expands to an `await` and must be invoked inside an
/// async context.
///
///A default timeout of 50ms is used if no duration is passed.
///
/// # Examples
///
/// ```rust,should_panic
/// use lifeline::assert_times_out;
/// use tokio::time::sleep;
///
/// # let fut =
/// async {
///     // Fails because default time is longer than delay.
///     assert_times_out!(sleep(Duration::from_millis(5)));
/// }
/// # ;
/// # let mut runtime = tokio::runtime::Runtime::new().unwrap();
/// # runtime.block_on(fut);
/// ```
///
/// ```rust
/// use lifeline::assert_times_out;
/// use tokio::time::sleep;
///
/// # let fut =
/// async {
///     // Succeeds because timeout is shorter than delay.
///     assert_times_out!(sleep(Duration::from_millis(250)), 10);
/// }
/// # ;
/// # let mut runtime = tokio::runtime::Runtime::new().unwrap();
/// # runtime.block_on(fut);
/// ```

#[macro_export]
macro_rules! assert_times_out {
    ($e:expr) => {
        $crate::assert_times_out!($e, 50)
    };
    ($e:expr, $time:literal) => {{
        use std::time::Duration;
        use tokio::time::timeout;
        match timeout(Duration::from_millis($time), $e).await {
            Ok(_) => panic!(
                "assertion failed: {} completed within {} ms",
                stringify!($e),
                $time,
            ),
            Err(err) => err,
        }
    }};
}