extern crate syn;
#[macro_use]
extern crate quote;
extern crate proc_macro;
use syn::{parse_macro_input, parse_quote, ItemFn};
use proc_macro::TokenStream;
fn create_content_block(block: Box<syn::Block>) -> syn::Stmt {
let wrap_body = quote!{
let result = ::std::panic::catch_unwind(|| {
#block;
});
};
let stmt: syn::Stmt = parse_quote! {
#wrap_body
};
stmt
}
fn create_setup_call() -> syn::Stmt {
let set_up_call = quote!(set_up(););
let stmt: syn::Stmt = parse_quote! {
#set_up_call
};
stmt
}
fn create_tear_down_call() -> syn::Stmt {
let tear_down_call = quote!(tear_down(););
let stmt: syn::Stmt = parse_quote! {
#tear_down_call
};
stmt
}
fn create_result_check() -> syn::Stmt {
let result_check = quote!{
if let Err(err) = result {
::std::panic::resume_unwind(err);
};
};
let stmt: syn::Stmt = parse_quote! {
#result_check
};
stmt
}
#[proc_macro_attribute]
pub fn integration_test(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut input_test_function = parse_macro_input!(input as ItemFn);
let block = input_test_function.block.clone();
let content_block = create_content_block(block);
let setup_call = create_setup_call();
let tear_down_call = create_tear_down_call();
let result_check = create_result_check();
let call_vector: Vec<syn::Stmt> = vec![
setup_call, content_block,
tear_down_call, result_check
];
input_test_function.block.stmts = call_vector;
quote!(#input_test_function).to_string().parse().unwrap()
}