1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
//! # serial_test_derive
//! `serial_test_derive` allows for the creation of serialised Rust tests using the [serial](attr.serial.html) attribute
//! e.g.
//! ````
//! #[test]
//! #[serial]
//! fn test_serial_one() {
//! // Do things
//! }
//!
//! #[test]
//! #[serial]
//! fn test_serial_another() {
//! // Do things
//! }
//! ````
//! Multiple tests with the [serial](attr.serial.html) attribute are guaranteed to be executed in serial. Ordering
//! of the tests is not guaranteed however.
extern crate proc_macro;
use proc_macro::{TokenStream, TokenTree};
use quote::quote;
use syn;
/// Allows for the creation of serialised Rust tests
/// ````
/// #[test]
/// #[serial]
/// fn test_serial_one() {
/// // Do things
/// }
///
/// #[test]
/// #[serial]
/// fn test_serial_another() {
/// // Do things
/// }
/// ````
/// Multiple tests with the [serial](attr.serial.html) attribute are guaranteed to be executed in serial. Ordering
/// of the tests is not guaranteed however. If you want different subsets of tests to be serialised with each
/// other, but not depend on other subsets, you can add an argument to [serial](attr.serial.html), and all calls
/// with identical arguments will be called in serial. e.g.
/// ````
/// #[test]
/// #[serial(something)]
/// fn test_serial_one() {
/// // Do things
/// }
///
/// #[test]
/// #[serial(something)]
/// fn test_serial_another() {
/// // Do things
/// }
///
/// #[test]
/// #[serial(other)]
/// fn test_serial_third() {
/// // Do things
/// }
///
/// #[test]
/// #[serial(other)]
/// fn test_serial_fourth() {
/// // Do things
/// }
/// ````
/// `test_serial_one` and `test_serial_another` will be executed in serial, as will `test_serial_third` and `test_serial_fourth`
/// but neither sequence will be blocked by the other
#[proc_macro_attribute]
pub fn serial(attr: TokenStream, input: TokenStream) -> TokenStream {
let attrs = attr.into_iter().collect::<Vec<TokenTree>>();
let key = match attrs.len() {
0 => "".to_string(),
1 => {
if let TokenTree::Ident(id) = &attrs[0] {
id.to_string()
} else {
panic!("Expected a single name as argument");
}
}
_ => {
panic!("Expected either 0 or 1 arguments");
}
};
let ast: syn::ItemFn = syn::parse(input).unwrap();
let name = ast.ident;
let block = ast.block;
let attrs = ast.attrs;
let gen = quote! {
#(#attrs)
*
fn #name () {
serial_test::serial_core(#key, || {
#block
});
}
};
return gen.into();
}