24
24
//! Cargo. Instead, we put our tests in a `pytests` directory, although the name `pytests` is just
25
25
//! a convention.
26
26
//!
27
- //! We'll also want to provide the test's main function. It's highly recommended that you use the
28
- //! [`pyo3_asyncio::testing::test_main!`](pyo3_asyncio_macros::test_main) macro as it will take all of the tests marked with
29
- //! [`#[pyo3_asyncio::tokio::test]`](crate::tokio::test) or
30
- //! [`#[pyo3_asyncio::async_std::test]`](crate::async_std::test) and run them automatically.
27
+ //! We'll also want to provide the test's main function. Most of the functionality that the test
28
+ //! harness needs is packed in this module's [`main`](crate::testing::main) function. It will parse
29
+ //! the test's CLI arguments, collect and pass the functions marked with
30
+ //! [`#[pyo3_asyncio::async_std::test]`](crate::async_std::test) or
31
+ //! [`#[pyo3_asyncio::tokio::test]`](crate::tokio::test) and pass them into the test harness for
32
+ //! running and filtering.
31
33
//!
32
34
//! `pytests/test_example.rs` for the `tokio` runtime:
33
- //! ```ignore
35
+ //! ```
34
36
//! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
35
- //! pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::tokio::main], "Example Test Suite");
37
+ //! #[pyo3_asyncio::tokio::main]
38
+ //! async fn main() -> pyo3::PyResult<()> {
39
+ //! pyo3_asyncio::testing::main().await
40
+ //! }
36
41
//! ```
37
42
//!
38
43
//! `pytests/test_example.rs` for the `async-std` runtime:
39
- //! ```ignore
44
+ //! ```
40
45
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
41
- //! pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::async_std::main], "Example Test Suite");
46
+ //! #[pyo3_asyncio::async_std::main]
47
+ //! async fn main() -> pyo3::PyResult<()> {
48
+ //! pyo3_asyncio::testing::main().await
49
+ //! }
42
50
//! ```
43
51
//!
44
52
//! ### Cargo Configuration
64
72
//!
65
73
//! ### Adding Tests to the PyO3 Asyncio Test Harness
66
74
//!
75
+ //! We can add tests anywhere in the test crate with the runtime's corresponding `#[test]` attribute:
76
+ //!
67
77
//! For `async-std` use the [`pyo3_asyncio::async_std::test`](crate::async_std::test) attribute:
68
78
//! ```
69
79
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
70
- //! # mod tests {
71
- //! use std::{time::Duration, thread};
80
+ //! mod tests {
81
+ //! use std::{time::Duration, thread};
72
82
//!
73
- //! use pyo3::prelude::*;
83
+ //! use pyo3::prelude::*;
74
84
//!
75
- //! #[pyo3_asyncio::async_std::test]
76
- //! async fn test_async_sleep() -> PyResult<()> {
77
- //! async_std::task::sleep(Duration::from_secs(1)).await;
78
- //! Ok(())
79
- //! }
85
+ //! #[pyo3_asyncio::async_std::test]
86
+ //! async fn test_async_sleep() -> PyResult<()> {
87
+ //! async_std::task::sleep(Duration::from_secs(1)).await;
88
+ //! Ok(())
89
+ //! }
80
90
//!
81
- //! #[pyo3_asyncio::async_std::test]
82
- //! fn test_blocking_sleep() -> PyResult<()> {
83
- //! thread::sleep(Duration::from_secs(1));
84
- //! Ok(())
91
+ //! #[pyo3_asyncio::async_std::test]
92
+ //! fn test_blocking_sleep() -> PyResult<()> {
93
+ //! thread::sleep(Duration::from_secs(1));
94
+ //! Ok(())
95
+ //! }
85
96
//! }
86
- //! # }
87
97
//!
88
- //! // ...
89
- //! #
90
- //! # // Doctests don't detect main fn when using the test_main!() macro, so we expand it into the
91
- //! # // components of that macro instead.
92
- //! #
93
98
//! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
94
- //! # use pyo3::prelude::*;
95
- //! #
96
- //! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
97
- //! # #[pyo3_asyncio::async_std::main]
98
- //! # async fn main() -> pyo3::PyResult<()> {
99
- //! # pyo3_asyncio::testing::main("Example Test Suite").await
100
- //! # }
99
+ //! #[pyo3_asyncio::async_std::main]
100
+ //! async fn main() -> pyo3::PyResult<()> {
101
+ //! pyo3_asyncio::testing::main().await
102
+ //! }
101
103
//! # #[cfg(not(all(feature = "async-std-runtime", feature = "attributes")))]
102
104
//! # fn main() {}
103
105
//! ```
104
106
//!
105
107
//! For `tokio` use the [`pyo3_asyncio::tokio::test`](crate::tokio::test) attribute:
106
108
//! ```
107
109
//! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
108
- //! # mod tests {
109
- //! use std::{time::Duration, thread};
110
+ //! mod tests {
111
+ //! use std::{time::Duration, thread};
110
112
//!
111
- //! use pyo3::prelude::*;
113
+ //! use pyo3::prelude::*;
112
114
//!
113
- //! #[pyo3_asyncio::tokio::test]
114
- //! async fn test_async_sleep() -> PyResult<()> {
115
- //! tokio::time::sleep(Duration::from_secs(1)).await;
116
- //! Ok(())
117
- //! }
115
+ //! #[pyo3_asyncio::tokio::test]
116
+ //! async fn test_async_sleep() -> PyResult<()> {
117
+ //! tokio::time::sleep(Duration::from_secs(1)).await;
118
+ //! Ok(())
119
+ //! }
118
120
//!
119
- //! #[pyo3_asyncio::tokio::test]
120
- //! fn test_blocking_sleep() -> PyResult<()> {
121
- //! thread::sleep(Duration::from_secs(1));
122
- //! Ok(())
121
+ //! #[pyo3_asyncio::tokio::test]
122
+ //! fn test_blocking_sleep() -> PyResult<()> {
123
+ //! thread::sleep(Duration::from_secs(1));
124
+ //! Ok(())
125
+ //! }
123
126
//! }
124
- //! # }
125
127
//!
126
- //! // ...
127
- //! #
128
- //! # // Doctests don't detect main fn when using the test_main!() macro, so we expand it into the
129
- //! # // components of that macro instead.
130
128
//! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
131
- //! # use pyo3::prelude::*;
132
- //! #
133
- //! # #[cfg(all(feature = "tokio-runtime", feature = "attributes"))]
134
- //! # #[pyo3_asyncio::tokio::main]
135
- //! # async fn main() -> PyResult<()> {
136
- //! # pyo3_asyncio::testing::main("Example Test Suite").await
137
- //! # }
129
+ //! #[pyo3_asyncio::tokio::main]
130
+ //! async fn main() -> pyo3::PyResult<()> {
131
+ //! pyo3_asyncio::testing::main().await
132
+ //! }
138
133
//! # #[cfg(not(all(feature = "tokio-runtime", feature = "attributes")))]
139
134
//! # fn main() {}
140
135
//! ```
180
175
//!
181
176
//! # fn main() {}
182
177
//! ```
183
- //!
184
- //! ### Expanding `test_main!()` for Doc Tests
185
- //!
186
- //! This is probably a pretty niche topic, and there's really no reason you would _need_ to do this
187
- //! since usually you'd probably just want to use the `#[main]` attributes for your doc tests like we
188
- //! mentioned at the beginning of this page. But since we had to do it for _this particular module_
189
- //! of the docs, it's probably worth mentioning as a footnote.
190
- //!
191
- //! For some reason, doc tests don't interpret the `test_main!()` macro as providing `fn main()` and
192
- //! will wrap the test body in another `fn main()`. To get around this, we can instead expand
193
- //! `test_main!()` into its components for the doc test:
194
- //!
195
- //! The following `test_main!()` macro:
196
- //!
197
- //! ```ignore
198
- //! pyo3_asyncio::testing::test_main!(#[pyo3_asyncio::async_std::main], "Example Test Suite");
199
- //! ```
200
- //!
201
- //! Is equivalent to this expansion:
202
- //!
203
- //! ```
204
- //! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
205
- //! use pyo3::prelude::*;
206
- //!
207
- //! # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
208
- //! #[pyo3_asyncio::async_std::main]
209
- //! async fn main() -> PyResult<()> {
210
- //! pyo3_asyncio::testing::main("Example Test Suite").await
211
- //! }
212
- //! # #[cfg(not(all(feature = "async-std-runtime", feature = "attributes")))]
213
- //! # fn main() {}
214
- //! ```
215
178
216
179
use clap:: { App , Arg } ;
217
180
use futures:: stream:: { self , StreamExt } ;
218
181
use pyo3:: prelude:: * ;
219
182
220
- /// <span class="module-item stab portability" style="display: inline; border-radius: 3px; padding: 2px; font-size: 80%; line-height: 1.2;"><code>attributes</code></span>
221
- /// Provides the boilerplate for the `pyo3-asyncio` test harness in one line
222
- #[ cfg( feature = "attributes" ) ]
223
- pub use pyo3_asyncio_macros:: test_main;
224
-
225
183
/// Args that should be provided to the test program
226
184
///
227
185
/// These args are meant to mirror the default test harness's args.
@@ -251,13 +209,13 @@ impl Default for Args {
251
209
/// Running the following function:
252
210
/// ```
253
211
/// # use pyo3_asyncio::testing::parse_args;
254
- /// let args = parse_args("PyO3 Asyncio Example Test Suite" );
212
+ /// let args = parse_args();
255
213
/// ```
256
214
///
257
215
/// Produces the following usage string:
258
216
///
259
217
/// ```bash
260
- /// Pyo3 Asyncio Example Test Suite
218
+ /// Pyo3 Asyncio Test Suite
261
219
/// USAGE:
262
220
/// test_example [TESTNAME]
263
221
///
@@ -268,8 +226,8 @@ impl Default for Args {
268
226
/// ARGS:
269
227
/// <TESTNAME> If specified, only run tests containing this string in their names
270
228
/// ```
271
- pub fn parse_args ( suite_name : & str ) -> Args {
272
- let matches = App :: new ( suite_name )
229
+ pub fn parse_args ( ) -> Args {
230
+ let matches = App :: new ( "PyO3 Asyncio Test Suite" )
273
231
. arg (
274
232
Arg :: with_name ( "TESTNAME" )
275
233
. help ( "If specified, only run tests containing this string in their names" ) ,
@@ -345,13 +303,13 @@ pub async fn test_harness(tests: Vec<Test>, args: Args) -> PyResult<()> {
345
303
/// # #[cfg(all(feature = "async-std-runtime", feature = "attributes"))]
346
304
/// #[pyo3_asyncio::async_std::main]
347
305
/// async fn main() -> PyResult<()> {
348
- /// pyo3_asyncio::testing::main("Example Test Suite" ).await
306
+ /// pyo3_asyncio::testing::main().await
349
307
/// }
350
308
/// # #[cfg(not(all(feature = "async-std-runtime", feature = "attributes")))]
351
309
/// fn main() { }
352
310
/// ```
353
- pub async fn main ( suite_name : & str ) -> PyResult < ( ) > {
354
- let args = parse_args ( suite_name ) ;
311
+ pub async fn main ( ) -> PyResult < ( ) > {
312
+ let args = parse_args ( ) ;
355
313
356
314
test_harness (
357
315
inventory:: iter :: < Test > ( ) . map ( |test| test. clone ( ) ) . collect ( ) ,
0 commit comments