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
#![warn(clippy::pedantic)] #![recursion_limit = "4096"] extern crate proc_macro; use proc_macro::TokenStream; use proc_macro2::Span; use quote::quote; use syn::{parse_macro_input, parse_quote, Ident, Item, Visibility}; #[proc_macro_attribute] pub fn async_test(params: TokenStream, input: TokenStream) -> TokenStream { assert!( params.is_empty(), "the #[async_test] attribute currently does not take parameters" ); let mut inner = parse_macro_input!(input as Item); let mut outer = inner.clone(); if let (&mut Item::Fn(ref mut inner_fn), &mut Item::Fn(ref mut outer_fn)) = (&mut inner, &mut outer) { inner_fn.sig.ident = Ident::new( &("_inner_".to_string() + &inner_fn.sig.ident.to_string()), Span::call_site(), ); let inner_ident = &inner_fn.sig.ident; inner_fn.vis = Visibility::Inherited; inner_fn.attrs.clear(); assert!( outer_fn.sig.asyncness.take().is_some(), "#[async_test] can only be applied to async functions" ); outer_fn.attrs.push(parse_quote!(#[test])); outer_fn.block = Box::new(parse_quote!({ ::futures_await_test::reexport::LocalPool::new().run_until(#inner_ident()) })); } else { panic!("#[async_test] can only be applied to async functions") } quote!( #inner #outer ) .into() }