7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | use proc_macro::TokenStream; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | use quote::{ToTokens, format_ident, quote}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | use syn::parse_macro_input; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | /// Attribute to use `wasm_bindgen_test` for wasm32 targets and `tokio::test` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | /// for everything else with async-support and custom result-types |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | #[proc_macro_attribute] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | pub fn async_test(_attr: TokenStream, item: TokenStream) -> TokenStream { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | let fun = parse_macro_input!(item as syn::ItemFn); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | if !fun.sig.ident.to_string().starts_with("test_") { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | panic!("test function names must start with test_"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | // on the regular return-case, we can just use cfg_attr and quit early |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | if fun.sig.output == syn::ReturnType::Default { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | let attrs = r#" |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | #[cfg_attr(not(target_family = "wasm"), tokio::test)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test::wasm_bindgen_test)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | "#; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | let mut out: TokenStream = attrs.parse().expect("Static works"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | let inner: TokenStream = fun.into_token_stream().into(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | out.extend(inner); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | return out; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | // on the more complicated case, where we have some `->`-Result-Arrow |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | // `wasm_bindgen_test` doesn't yet support |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | // - see https://github.com/rustwasm/wasm-bindgen/issues/2565 - |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | // we split the attribution into to functions: one with the original |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | // to be attributed for non-wasm, and then a second outer-wrapper function |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | // that calls the first in wasm32 cases. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | let attrs = r#" |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | #[cfg_attr(not(target_family = "wasm"), tokio::test)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | "#; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | let mut out: TokenStream = attrs.parse().expect("Static works."); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | let mut outer = fun.clone(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | let fn_name = fun.sig.ident.clone(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | let fn_call: TokenStream = if fun.sig.asyncness.is_some() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | quote! { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | let res = #fn_name().await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | assert!(res.is_ok(), "{:?}", res); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | } else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | quote! { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | let res = #fn_name(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | assert!(res.is_ok(), "{:?}", res); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | .into(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | outer.sig.output = syn::ReturnType::Default; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | outer.sig.ident = format_ident!("{}_outer", fun.sig.ident); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | outer.block = Box::new(parse_macro_input!(fn_call as syn::Block)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | let inner: TokenStream = fun.into_token_stream().into(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | out.extend(inner); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | let attrs = r#" |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | #[cfg(target_family = "wasm")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | #[wasm_bindgen_test::wasm_bindgen_test] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | "#; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | let outer_attrs: TokenStream = attrs.parse().expect("Static works."); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | let of: TokenStream = outer.into_token_stream().into(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | out.extend(outer_attrs); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | out.extend(of); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | out |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | } |