matrix_sdk_test_macros/
lib.rs

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