use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use std::iter;
#[proc_macro]
pub fn build_ident(input: TokenStream) -> TokenStream {
let mut ident_name = String::new();
for token in input.into_iter() {
match token {
TokenTree::Ident(ident) => ident_name += &ident.to_string(),
TokenTree::Group(group) => {
if let Some(ident) = group.stream().into_iter().last() {
ident_name += &ident.to_string();
}
}
_ => (),
}
}
TokenStream::from(TokenTree::Ident(Ident::new(&ident_name, Span::call_site())))
}
#[proc_macro]
pub fn make_test_fn(input: TokenStream) -> TokenStream {
let mut tokens = input.into_iter();
let mut ts = TokenStream::new();
let func = tokens.next().unwrap();
let _ = tokens.next().unwrap();
let suffix = tokens.next().unwrap();
let _ = tokens.next().unwrap();
let args = tokens.next().unwrap();
let _ = tokens.next().unwrap();
let expected = tokens.next().unwrap();
let ts_attr = TokenStream::from_iter([
TokenTree::from(Punct::new('#', Spacing::Alone)),
TokenTree::from(Group::new(
Delimiter::Bracket,
TokenStream::from(TokenTree::from(Ident::new("test", Span::call_site()))),
)),
]);
ts.extend(ts_attr);
ts.extend(iter::once(TokenTree::from(Ident::new(
"fn",
Span::call_site(),
))));
let ts_name = TokenStream::from_iter([
TokenTree::from(Ident::new("test_", Span::call_site())),
func.clone(),
suffix,
]);
let name = build_ident(ts_name);
ts.extend(iter::once(name));
ts.extend(iter::once(TokenTree::from(Group::new(
Delimiter::Parenthesis,
TokenStream::new(),
))));
let mut ts_body = TokenStream::new();
if let TokenTree::Group(g_args) = args {
ts_body.extend([
TokenTree::from(Ident::new("assert_eq", Span::call_site())),
TokenTree::from(Punct::new('!', Spacing::Alone)),
TokenTree::from(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter([
func,
TokenTree::from(Group::new(
Delimiter::Parenthesis,
g_args.stream()
)),
TokenTree::from(Punct::new(',', Spacing::Alone)),
expected,
]),
)),
TokenTree::from(Punct::new(';', Spacing::Alone)),
]);
}
ts.extend(iter::once(TokenTree::from(Group::new(
Delimiter::Brace,
ts_body,
))));
ts
}