satchel_macro/
lib.rs

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}