rustest_macro/
lib.rs

1mod fixture;
2mod test;
3mod utils;
4
5use fixture::{FixtureAttr, fixture_impl};
6use proc_macro::TokenStream;
7use quote::quote;
8use std::sync::atomic::Ordering;
9use syn::{ItemFn, parse_macro_input};
10use test::{TEST_COUNT, TestAttr, test_impl};
11
12#[proc_macro_attribute]
13pub fn test(args: TokenStream, input: TokenStream) -> TokenStream {
14    let input = parse_macro_input!(input as ItemFn);
15    let args = parse_macro_input!(args as TestAttr);
16    match test_impl(args, input) {
17        Ok(output) => output,
18        Err(output) => output,
19    }
20    .into()
21}
22
23#[proc_macro_attribute]
24pub fn fixture(args: TokenStream, input: TokenStream) -> TokenStream {
25    let input = parse_macro_input!(input as ItemFn);
26    let args = parse_macro_input!(args as FixtureAttr);
27    match fixture_impl(args, input) {
28        Ok(output) => output,
29        Err(output) => output,
30    }
31    .into()
32}
33
34#[proc_macro_attribute]
35pub fn main(_args: TokenStream, _input: TokenStream) -> TokenStream {
36    let test_count = TEST_COUNT.load(Ordering::Relaxed);
37    (quote! {
38        static mut TEST_GENERATORS: [Option<::rustest::TestGeneratorFn>; #test_count] = [None; #test_count];
39
40        fn main() -> std::process::ExitCode {
41            // SAFETY: TEST_CTORS is filled only by functions run from outside of main.
42            // So when we are here, no one is modifying (neither read) it.
43            let test_registers = unsafe { TEST_GENERATORS.iter().map(|r| r.expect("Slot should be filled")).collect::<Vec<_>>() };
44            ::rustest::run_tests(&test_registers)
45        }
46    })
47    .into()
48}