1use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
2use std::iter;
3
4#[proc_macro]
5pub fn build_ident(input: TokenStream) -> TokenStream {
6 let mut ident_name = String::new();
7 for token in input.into_iter() {
8 match token {
9 TokenTree::Ident(ident) => ident_name += &ident.to_string(),
10 TokenTree::Group(group) => {
11 if let Some(ident) = group.stream().into_iter().last() {
12 ident_name += &ident.to_string();
13 }
14 }
15 _ => (),
16 }
17 }
18 TokenStream::from(TokenTree::Ident(Ident::new(&ident_name, Span::call_site())))
19}
20
21#[proc_macro]
22pub fn make_test_fn(input: TokenStream) -> TokenStream {
23 let mut tokens = input.into_iter();
24 let mut ts = TokenStream::new();
25
26 let func = tokens.next().unwrap();
28 let _ = tokens.next().unwrap();
29 let suffix = tokens.next().unwrap();
30 let _ = tokens.next().unwrap();
31 let args = tokens.next().unwrap();
32 let _ = tokens.next().unwrap();
33 let expected = tokens.next().unwrap();
34
35 let ts_attr = TokenStream::from_iter([
37 TokenTree::from(Punct::new('#', Spacing::Alone)),
38 TokenTree::from(Group::new(
39 Delimiter::Bracket,
40 TokenStream::from(TokenTree::from(Ident::new("test", Span::call_site()))),
41 )),
42 ]);
43 ts.extend(ts_attr);
44
45 ts.extend(iter::once(TokenTree::from(Ident::new(
47 "fn",
48 Span::call_site(),
49 ))));
50
51 let ts_name = TokenStream::from_iter([
53 TokenTree::from(Ident::new("test_", Span::call_site())),
54 func.clone(),
55 suffix,
56 ]);
57 let name = build_ident(ts_name);
58 ts.extend(iter::once(name));
59
60 ts.extend(iter::once(TokenTree::from(Group::new(
62 Delimiter::Parenthesis,
63 TokenStream::new(),
64 ))));
65
66 let mut ts_body = TokenStream::new();
68 if let TokenTree::Group(g_args) = args {
69 ts_body.extend([
70 TokenTree::from(Ident::new("assert_eq", Span::call_site())),
71 TokenTree::from(Punct::new('!', Spacing::Alone)),
72 TokenTree::from(Group::new(
73 Delimiter::Parenthesis,
74 TokenStream::from_iter([
75 func,
76 TokenTree::from(Group::new(
77 Delimiter::Parenthesis,
78 g_args.stream()
79 )),
80 TokenTree::from(Punct::new(',', Spacing::Alone)),
81 expected,
82 ]),
83 )),
84 TokenTree::from(Punct::new(';', Spacing::Alone)),
85 ]);
86 }
87
88 ts.extend(iter::once(TokenTree::from(Group::new(
89 Delimiter::Brace,
90 ts_body,
91 ))));
92
93 ts
94}