clickhouse_testing_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{ItemFn, parse_macro_input};
4
5#[proc_macro_attribute]
6pub fn test(_args: TokenStream, input: TokenStream) -> TokenStream {
7 let func = parse_macro_input!(input as ItemFn);
8 let func_name = &func.sig.ident;
9 let func_name_str = func_name.to_string();
10 let func_vis = &func.vis;
11 let func_attrs = &func.attrs;
12 let func_inputs = &func.sig.inputs;
13 let func_output = &func.sig.output;
14 let func_block = &func.block;
15
16 let inner_name = syn::Ident::new(&format!("__{}_inner", func_name), func_name.span());
17
18 let handle_result = match func_output {
19 syn::ReturnType::Type(_, ty) if matches!(ty.as_ref(), syn::Type::Path(type_path) if type_path.path.segments.last().is_some_and(|seg| seg.ident == "Result")) =>
20 {
21 quote! {
22 match test_result {
23 Ok(val) => {
24 if let Err(e) = clickhouse_testing::cleanup_test(&client).await {
25 panic!("Failed to cleanup test {:?} data: {:?}", #func_name_str, e);
26 }
27 val
28 }
29 Err(e) => panic!("Test {:?} failed: {:?}", #func_name_str, e),
30 }
31 }
32 }
33 _ => quote! {
34 let val = test_result;
35 if let Err(e) = clickhouse_testing::cleanup_test(&client).await {
36 panic!("Failed to cleanup test {:?} data: {:?}", #func_name_str, e);
37 }
38 val
39 },
40 };
41
42 let expanded = quote! {
43 #(#func_attrs)*
44 #[tokio::test]
45 #func_vis async fn #func_name() {
46 let module_path = module_path!();
47 let client = match clickhouse_testing::init_test(module_path, #func_name_str).await {
48 Ok(c) => c,
49 Err(e) => panic!("Failed to setup test {:?} client: {:?}", #func_name_str, e),
50 };
51
52 let test_result = #inner_name(client.clone()).await;
53 #handle_result
54 }
55
56 async fn #inner_name(#func_inputs) #func_output #func_block
57 };
58
59 expanded.into()
60}