/// This is just a huge hack to make a test runner (with no test cases) /// look as if it's running a bunch of (async) test cases. #[macro_export] macro_rules! async_tests { ( $runner:ident { $( $name:ident : async $eval:block, )* } ) => { #[allow(dead_code)] fn $runner(_: &[()]) { env_logger::init(); std::process::exit({ let rt = tokio::runtime::Runtime::new() .expect("Failed to create runtime."); let (_, errs) = rt.block_on(async { println!(); println!("running tests"); println!(); #[allow(unused_mut)] let mut oks: u32 = 0; #[allow(unused_mut)] let mut errs: u32 = 0; $( let $name = async { let result: std::result::Result<(), String> = async { $eval }.await; result }; let $name = tokio::spawn($name); )* $( let $name = $name.await.expect("Failed to spawn."); )* $( print!("test {} ... ", stringify!($name)); match $name { Ok(_) => { println!("{}", "ok".green()); oks += 1; } Err(msg) => { println!("{}", "error".bright_red()); println!("{}", msg); errs += 1; } } )* println!(); print!("test result: {}. ", if errs > 0 { "error".bright_red() } else { "ok".green() }); println!("{} passed; {} failed; 0 ignored; 0 measured; 0 filtered out", oks, errs); println!(); (oks, errs) }); // Just returns #errs as exit code. errs as i32 }); } }; } #[macro_export] macro_rules! rassert { ( $x:expr ) => { { if $x { Ok(()) } else { Err(stringify!($x)) }? } }; ( $x:expr, $format:expr $(, $arg:expr)* ) => { { if $x { Ok(()) } else { Err( format!($format, $( $arg )* ) ) }? } }; } #[macro_export] macro_rules! rassert_eq { ( $a:expr, $b:expr ) => { rassert!($a == $b) }; ( $a:expr, $b:expr, $format:expr $(, $arg:expr)* ) => { rassert!($a == $b, $format $(, $arg )* ) }; } #[macro_export] macro_rules! rassert_ne { ( $a:expr, $b:expr ) => { rassert!($a != $b) }; ( $a:expr, $b:expr, $format:expr $(, $arg:expr)* ) => { rassert!($a != $b, $format $(, $arg )* ) }; }