1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{parse_macro_input, ItemFn};
4
5#[proc_macro_attribute]
6pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream {
7 expand_test_or_bench(item, quote! {::satchel::TestKind::Unit }, "__SATCHEL_TEST_")
8}
9
10#[proc_macro_attribute]
11pub fn bench(_attr: TokenStream, item: TokenStream) -> TokenStream {
12 expand_test_or_bench(
13 item,
14 quote! { ::satchel::TestKind::Benchmark },
15 "__SATCHEL_BENCH_",
16 )
17}
18
19fn expand_test_or_bench(
20 input: TokenStream,
21 kind: quote::__private::TokenStream,
22 prefix: &str,
23) -> TokenStream {
24 let input_fn = parse_macro_input!(input as ItemFn);
25 let fn_name = &input_fn.sig.ident;
26 let fn_name_str = fn_name.to_string();
27 let static_name = format_ident!("{}{}", prefix, fn_name_str.to_uppercase());
28
29 let expanded = quote! {
30 #[linkme::distributed_slice(::satchel::test_harness::TESTS)]
31 static #static_name: ::satchel::test_harness::TestCase = ::satchel::test_harness::TestCase {
32 name: #fn_name_str,
33 module_path: ::std::module_path!(),
34 kind: #kind,
35 test_fn: #fn_name,
36 };
37
38 #input_fn
39 };
40
41 TokenStream::from(expanded)
42}