test_attr/
lib.rs

1use proc_macro::{TokenStream, TokenTree};
2use quote::quote;
3
4// TODO: try factoring out common stuffs from all these fns.
5
6#[proc_macro_attribute]
7pub fn unit_test(_args: TokenStream, input: TokenStream) -> TokenStream {
8    let mut output: TokenStream = quote! {
9        #[test]
10        #[cfg_attr(not(feature = "unit-test"), ignore)]
11    }
12    .into();
13    output.extend(input.into_iter());
14    output
15}
16
17#[proc_macro_attribute]
18pub fn integration_test(_args: TokenStream, input: TokenStream) -> TokenStream {
19    let mut output: TokenStream = quote! {
20        #[test]
21        #[cfg_attr(not(feature = "integration-test"), ignore)]
22    }
23    .into();
24    output.extend(input.into_iter());
25    output
26}
27
28#[proc_macro_attribute]
29pub fn system_test(_args: TokenStream, input: TokenStream) -> TokenStream {
30    let mut output: TokenStream = quote! {
31        #[test]
32        #[cfg_attr(not(feature = "system-test"), ignore)]
33    }
34    .into();
35    output.extend(input.into_iter());
36    output
37}
38
39#[proc_macro_attribute]
40pub fn tokio_unit_test(_args: TokenStream, input: TokenStream) -> TokenStream {
41    let mut output: TokenStream = quote! {
42        #[tokio::test]
43        #[cfg_attr(not(feature = "unit-test"), ignore)]
44    }
45    .into();
46    output.extend(input.into_iter());
47    output
48}
49
50#[proc_macro_attribute]
51pub fn tokio_integration_test(_args: TokenStream, input: TokenStream) -> TokenStream {
52    let mut output: TokenStream = quote! {
53        #[tokio::test]
54        #[cfg_attr(not(feature = "integration-test"), ignore)]
55    }
56    .into();
57    output.extend(input.into_iter());
58    output
59}
60
61#[proc_macro_attribute]
62pub fn tokio_system_test(_args: TokenStream, input: TokenStream) -> TokenStream {
63    let mut output: TokenStream = quote! {
64        #[tokio::test]
65        #[cfg_attr(not(feature = "system-test"), ignore)]
66    }
67    .into();
68    output.extend(input.into_iter());
69    output
70}
71
72fn partition_at_first_ident(input: TokenStream) -> (TokenStream, TokenStream) {
73    let mut left = TokenStream::new();
74    let mut right = TokenStream::new();
75    let mut input = input.into_iter();
76    for token_tree in input.by_ref() {
77        match token_tree {
78            TokenTree::Ident(_) => {
79                right.extend(TokenStream::from(token_tree));
80                break;
81            }
82            _ => {
83                left.extend(TokenStream::from(token_tree));
84            }
85        }
86    }
87    right.extend(input);
88    (left, right)
89}
90
91#[proc_macro_attribute]
92pub fn tokio_unit_rstest(_args: TokenStream, input: TokenStream) -> TokenStream {
93    let (left, right) = partition_at_first_ident(input);
94    let mut output: TokenStream = quote! {
95        #[rstest]
96    }
97    .into();
98    let center: TokenStream = quote! {
99        #[tokio::test]
100        #[cfg_attr(not(feature = "unit-test"), ignore)]
101    }
102    .into();
103    output.extend(left);
104    output.extend(center);
105    output.extend(right);
106    output
107}
108
109#[proc_macro_attribute]
110pub fn unit_rstest(_args: TokenStream, input: TokenStream) -> TokenStream {
111    let (left, right) = partition_at_first_ident(input);
112    let mut output: TokenStream = quote! {
113        #[rstest]
114    }
115    .into();
116    let center: TokenStream = quote! {
117        #[cfg_attr(not(feature = "unit-test"), ignore)]
118    }
119    .into();
120    output.extend(left);
121    output.extend(center);
122    output.extend(right);
123    output
124}