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
//! Procedural macros for the loggy framework.
//!
//! If/when Rust allows placing procedural macros inside a library crate, this crate should be merged into the overall
//! loggy crate.
#![deny(missing_docs)]
extern crate syn;
use proc_macro::TokenStream;
use quote::quote;
use syn::parse_macro_input;
use syn::parse_quote;
use syn::ItemFn;
use syn::Stmt;
/// Create a test case using `loggy`.
///
/// To use this, prefix the test with `[#loggy]`. In the test, invoke one of [`assert_logged`],
/// [`assert_logged_panics`], [`assert_panics`] or, if you wish to ignore the captured log
/// altogether, [`ignore_log`].
///
/// Since `loggy` collects messages from all threads, `test_loggy!` tests must be run with
/// `RUST_TEST_THREADS=1`, otherwise "bad things will happen". However, such tests may freely spawn
/// multiple new threads.
///
/// If the environment variable `LOGGY_MIRROR_TO_STDERR` is set to any non empty value, then all
/// log messages will be mirrored to the standard error stream, in addition to being captured. This
/// places the `Level::Debug` messages in the context of the other log messages, to help in
/// debugging.
#[proc_macro_attribute]
pub fn loggy(attributes: TokenStream, stream: TokenStream) -> TokenStream {
assert!(attributes.is_empty(), "unexpected arguments");
let mut input = parse_macro_input!(stream as ItemFn);
let prefix: Stmt = parse_quote! { loggy::before_test(); };
let suffix: Stmt = parse_quote! { loggy::after_test(); };
input.block.stmts.insert(0, prefix);
input.block.stmts.push(suffix);
let output = quote! { #input };
output.into()
}