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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! A library for providing custom setup/teardown for Rust tests without needing a test harness.
//!
//! ```no_run
//! use test_context::{test_context, TestContext};
//!
//! struct MyContext {
//!     value: String
//! }
//!
//! impl TestContext for MyContext {
//!     fn setup() -> MyContext {
//!         MyContext {  value: "Hello, world!".to_string() }
//!     }
//!
//!     fn teardown(self) {
//!         // Perform any teardown you wish.
//!     }
//! }
//!
//! #[test_context(MyContext)]
//! #[test]
//! fn test_works(ctx: &mut MyContext) {
//!     assert_eq!(ctx.value, "Hello, world!");
//! }
//! ```
//!
//! Alternatively, you can use `async` functions in your test context by using the
//! `AsyncTestContext`.
//!
//! ```no_run
//! use test_context::{test_context, AsyncTestContext};
//!
//! struct MyAsyncContext {
//!     value: String
//! }
//!
//! impl AsyncTestContext for MyAsyncContext {
//!     async fn setup() -> MyAsyncContext {
//!         MyAsyncContext { value: "Hello, world!".to_string() }
//!     }
//!
//!     async fn teardown(self) {
//!         // Perform any teardown you wish.
//!     }
//! }
//!
//! #[test_context(MyAsyncContext)]
//! #[test]
//! fn test_works(ctx: &mut MyAsyncContext) {
//!     assert_eq!(ctx.value, "Hello, World!");
//! }
//! ```
//!
//! The `AsyncTestContext` works well with async test wrappers like
//! [`actix_rt::test`](https://docs.rs/actix-rt/1.1.1/actix_rt/attr.test.html) or
//! [`tokio::test`](https://docs.rs/tokio/1.0.2/tokio/attr.test.html).
//!
//! ```no_run
//!  use test_context::{test_context, AsyncTestContext};
//!
//!  struct MyAsyncContext {
//!      value: String
//!  }
//!
//!  impl AsyncTestContext for MyAsyncContext {
//!      async fn setup() -> MyAsyncContext {
//!          MyAsyncContext { value: "Hello, world!".to_string() }
//!      }
//!      async fn teardown(self) {
//!          // Perform any teardown you wish.
//!      }
//!  }
//!
//! #[test_context(MyAsyncContext)]
//! #[tokio::test]
//! async fn test_async_works(ctx: &mut MyAsyncContext) {
//!     assert_eq!(ctx.value, "Hello, World!");
//! }
//! ```
//!
//! # Skipping the teardown execution
//!
//! If what you need is to take full __ownership__ of the context and don't care about the
//! teardown execution for a specific test, you can use the `skip_teardown` keyword on the macro
//! like this:
//!
//! ```no_run
//!  use test_context::{test_context, TestContext};
//!
//!  struct MyContext {}
//!
//!  impl TestContext for MyContext {
//!      fn setup() -> MyContext {
//!          MyContext {}
//!      }
//!  }
//!
//! #[test_context(MyContext, skip_teardown)]
//! #[test]
//! fn test_without_teardown(ctx: MyContext) {
//!   // Perform any operations that require full ownership of your context
//! }
//! ```

// Reimported to allow for use in the macro.
pub use futures;

pub use test_context_macros::test_context;

/// The trait to implement to get setup/teardown functionality for tests.
pub trait TestContext
where
    Self: Sized,
{
    /// Create the context. This is run once before each test that uses the context.
    fn setup() -> Self;

    /// Perform any additional cleanup of the context besides that already provided by
    /// normal "drop" semantics.
    fn teardown(self) {}
}

/// The trait to implement to get setup/teardown functionality for async tests.
pub trait AsyncTestContext
where
    Self: Sized,
{
    /// Create the context. This is run once before each test that uses the context.
    fn setup() -> impl std::future::Future<Output = Self> + Send;

    /// Perform any additional cleanup of the context besides that already provided by
    /// normal "drop" semantics.
    fn teardown(self) -> impl std::future::Future<Output = ()> + Send {
        async {}
    }
}

// Automatically impl TestContext for anything Send that impls AsyncTestContext.
//
// A future improvement may be to use feature flags to enable using a specific runtime
// to run the future synchronously. This is the easiest way to implement it, though, and
// introduces no new dependencies.
impl<T> TestContext for T
where
    T: AsyncTestContext + Send,
{
    fn setup() -> Self {
        futures::executor::block_on(<T as AsyncTestContext>::setup())
    }

    fn teardown(self) {
        futures::executor::block_on(<T as AsyncTestContext>::teardown(self))
    }
}