integration_test/
lib.rs

1extern crate syn;
2
3#[macro_use]
4extern crate quote;
5
6extern crate proc_macro;
7
8use syn::{parse_macro_input, parse_quote, ItemFn};
9use proc_macro::TokenStream;
10
11fn create_content_block(block: Box<syn::Block>) -> syn::Stmt {
12    // Method created context block with catch_unwind
13    // Reason why it creates test body with catch_unwind
14    // is raise panic after tear_down complete.
15    let wrap_body = quote!{
16        let result = ::std::panic::catch_unwind(|| {
17            #block;
18        });
19    };
20    let stmt: syn::Stmt = parse_quote! {
21        #wrap_body
22    };
23    stmt
24}
25
26fn create_setup_call() -> syn::Stmt {
27    // Method creates set_up hook
28    let set_up_call = quote!(set_up(););
29    let stmt: syn::Stmt = parse_quote! {
30        #set_up_call
31    };
32    stmt
33}
34
35fn create_tear_down_call() -> syn::Stmt {
36    // Method creates tear_down hook
37    let tear_down_call = quote!(tear_down(););
38    let stmt: syn::Stmt = parse_quote! {
39        #tear_down_call
40    };
41    stmt
42}
43
44fn create_result_check() -> syn::Stmt {
45    // Method should create result check
46    let result_check = quote!{
47        if let Err(err) = result {
48            ::std::panic::resume_unwind(err);
49        };
50    };
51    let stmt: syn::Stmt = parse_quote! {
52        #result_check
53    };
54    stmt
55}
56
57/// Integration test macros
58/// Usage:
59/// If you want add hooks to you integaration test,
60/// which need to create something before test, or remove something after test
61/// need add #[integration_test] macro after #[test] macro.
62/// If you add #[integration_test] you must add set_up(), and tear_down() hooks
63///
64/// Example:
65///
66/// #[cfg(test)]
67/// pub mod some_test {
68///    use super::*;
69///
70///  fn set_up() {
71///      println!("Set up");
72///  }
73///  fn tear_down() {
74///      println!("Tear down");
75///  }
76///
77///  #[test]
78///  #[integration_test]
79///  fn my_shiney_integration_test() {
80///      asserteq!(1, 2);
81///  }
82/// }
83/// Output order is:
84///  "Set up",
85///  panic!() -> is going to show after tear_down finish
86///  "Tear down"
87
88#[proc_macro_attribute]
89pub fn integration_test(_args: TokenStream, input: TokenStream) -> TokenStream {
90    /* Macros add tear_down and set_up hooks to choosen test 
91       TODO Add unittests!!!!!
92       unitests should have state for control execution
93    */
94
95    let mut input_test_function = parse_macro_input!(input as ItemFn);
96    // TODO, at next iteration need add manager for down methods
97    // this should be structure IntegrationTest, with exists logic
98    // for maintaine it in easy way
99    let block = input_test_function.block.clone();
100    let content_block = create_content_block(block);
101    let setup_call = create_setup_call();
102    let tear_down_call = create_tear_down_call();
103    let result_check = create_result_check();
104
105    let call_vector: Vec<syn::Stmt> = vec![
106        setup_call, content_block,
107        tear_down_call, result_check
108    ];
109
110    input_test_function.block.stmts = call_vector;
111    quote!(#input_test_function).to_string().parse().unwrap()
112}