11#![ doc = include_str ! ( "../README.md" ) ]
22use proc_macro2:: { Ident , Span , TokenStream } ;
33use quote:: { format_ident, quote} ;
4+ use syn:: token:: Async ;
45use std:: collections:: { HashMap , HashSet } ;
56use std:: ffi:: OsString ;
67use std:: path:: { Path , PathBuf } ;
@@ -15,6 +16,7 @@ struct TestEachArgs {
1516 function : Expr ,
1617 extensions : Vec < String > ,
1718 attributes : Vec < Meta > ,
19+ async_fn : Option < Async > ,
1820}
1921
2022macro_rules! abort {
@@ -32,7 +34,7 @@ macro_rules! abort_token_stream {
3234impl Parse for TestEachArgs {
3335 fn parse ( input : ParseStream ) -> syn:: Result < Self > {
3436 // Optionally parse attributes if `#` is used. Aborts if none are given.
35- let attributes = input
37+ let attributes: Vec < Meta > = input
3638 . parse :: < Token ! [ #] > ( )
3739 . and_then ( |_| {
3840 let content;
@@ -45,6 +47,19 @@ impl Parse for TestEachArgs {
4547 } )
4648 . unwrap_or_default ( ) ;
4749
50+ // Optionally mark as async.
51+ // The async keyword is the error span if we did not specify an attribute.
52+ let async_span = input. span ( ) ;
53+ let async_fn = match input. parse :: < Token ! [ async ] > ( ) {
54+ Ok ( token) => {
55+ if attributes. is_empty ( ) {
56+ abort ! ( async_span, "Expected at least one attribute (e.g., `#[tokio::test]`) when `async` is given." ) ;
57+ }
58+ Some ( token)
59+ } ,
60+ Err ( _) => None ,
61+ } ;
62+
4863 // Optionally parse extensions if the keyword `for` is used. Aborts if none are given.
4964 let extensions = input
5065 . parse :: < Token ! [ for ] > ( )
@@ -97,6 +112,7 @@ impl Parse for TestEachArgs {
97112 function,
98113 extensions,
99114 attributes,
115+ async_fn,
100116 } )
101117 }
102118}
@@ -248,12 +264,23 @@ fn generate_from_tree(
248264 } ) ;
249265 }
250266
251- stream. extend ( quote ! {
252- #[ test]
253- fn #file_name( ) {
254- ( #function) ( #arguments)
255- }
256- } ) ;
267+ if let Some ( async_keyword) = & parsed. async_fn {
268+ // For async functions, we'd need something like `#[tokio::test]` instead of `#[test]`.
269+ // Here we assume the user will have already provided that in the list of attributes.
270+ stream. extend ( quote ! {
271+ #async_keyword fn #file_name( ) {
272+ ( #function) ( #arguments) . await
273+ }
274+ } ) ;
275+ } else {
276+ // Default, non-async test.
277+ stream. extend ( quote ! {
278+ #[ test]
279+ fn #file_name( ) {
280+ ( #function) ( #arguments)
281+ }
282+ } ) ;
283+ }
257284 }
258285
259286 Ok ( ( ) )
0 commit comments