Browse Source

Simplify macro a ton and don't bother tearing down

We don't actually need to do teardown for the gdb runner to work, but
redirecting output streams still works if the runner is in scope for the
whole test.
pull/10/head
Ian Chamberlain 1 year ago
parent
commit
439a5f2cdd
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 108
      test-runner/src/macros.rs

108
test-runner/src/macros.rs

@ -1,113 +1,39 @@
//! Macros for working with test runners. //! Macros for working with test runners.
// Use a neat little trick with cfg(doctest) to make code fences appear in // We use a little trick with cfg(doctest) to make code fences appear in
// rustdoc output, but still compile normally when doctesting. This raises warnings // rustdoc output, but compile without them when doctesting. This raises warnings
// for invalid code though, so we also silence that lint here. // for invalid code, though, so silence that lint here.
#[cfg_attr(not(doctest), allow(rustdoc::invalid_rust_codeblocks))] #[cfg_attr(not(doctest), allow(rustdoc::invalid_rust_codeblocks))]
/// Helper macro for writing doctests using this runner. Wrap this macro around /// Helper macro for writing doctests using this runner. Call this macro at the
/// your normal doctest to enable running it with this crate's /// beginning of a doctest enables output from failing tests using this crate's
/// [`GdbRunner`](crate::GdbRunner). /// [`GdbRunner`](crate::GdbRunner). Without `setup_doctest!()`, doctests will
/// /// still fail on panic, but they won't display anything written to `stdout` or
/// You may use any of the various /// `stderr`.
/// [`fn main()`](https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html#using--in-doc-tests)
/// signatures allowed by documentation tests.
/// ///
/// # Examples /// # Examples
/// ///
/// ## Basic usage
///
#[cfg_attr(not(doctest), doc = "````")]
/// ```
/// test_runner::doctest! {
/// let two = 2;
/// let four = 4;
/// assert_eq!(two + two, four);
/// }
/// ```
#[cfg_attr(not(doctest), doc = "````")]
///
/// ## `should_panic`
///
/// Using `no_run` or `ignore` makes this macro somewhat irrelevant, but
/// `should_panic` is still supported:
///
#[cfg_attr(not(doctest), doc = "````")]
/// ```should_panic
/// test_runner::doctest! {
/// assert_eq!(2 + 2, 5);
/// }
/// ```
#[cfg_attr(not(doctest), doc = "````")]
///
/// ## Custom `fn main`, crate attribute
///
#[cfg_attr(not(doctest), doc = "````")] #[cfg_attr(not(doctest), doc = "````")]
/// ``` /// ```
/// #![allow(unused)] /// test_runner::setup_doctest!();
///
/// use std::error::Error;
///
/// test_runner::doctest! {
/// // imports can be added outside or inside the macro
/// use std::ops::Add;
///
/// fn main() -> Result<(), Box<dyn Error>> {
/// let two = 2;
/// let four = 4;
/// assert_eq!(Add::add(two, two), four);
/// Ok(())
/// }
/// }
/// ```
#[cfg_attr(not(doctest), doc = "````")]
///
/// ## Implicit return type
///
/// Note that for the rustdoc preprocessor to understand the return type, the
/// `Ok(())` expression must be written _outside_ the `doctest!` invocation.
///
#[cfg_attr(not(doctest), doc = "````")]
/// ```
/// test_runner::doctest! {
/// assert_eq!(2 + 2, 4); /// assert_eq!(2 + 2, 4);
/// }
/// Ok::<(), std::io::Error>(())
/// ``` /// ```
#[cfg_attr(not(doctest), doc = "````")] #[cfg_attr(not(doctest), doc = "````")]
/// ///
#[cfg_attr(not(doctest), doc = "````")] #[cfg_attr(not(doctest), doc = "````")]
/// ```should_panic /// ```should_panic
/// test_runner::doctest! { /// test_runner::setup_doctest!();
/// assert_eq!(2 + 2, 4); /// assert_eq!(2 + 2, 5);
/// Err::<(), &str>("uh oh")
/// }
/// ``` /// ```
#[cfg_attr(not(doctest), doc = "````")] #[cfg_attr(not(doctest), doc = "````")]
#[macro_export] #[macro_export]
macro_rules! doctest { macro_rules! setup_doctest {
(@_@ $($body:tt)*) => { () => {
fn main() -> impl std::process::Termination {
#[allow(unused_imports)]
use $crate::TestRunner as _; use $crate::TestRunner as _;
let mut _runner = $crate::GdbRunner::default(); let mut runner = $crate::GdbRunner::default();
_runner.setup(); runner.setup();
// Luckily, Rust allows $body to define an inner shadowing main() // We don't bother with cleanup here, since the macro is meant to be used
// and call it, without resulting in infinite recursion. // in a doctest context (i.e. `fn main()`, not used as a test runner)
let _result = { $($body)* };
_runner.cleanup(_result)
}
};
( $($body:tt)* ) => {
$crate::doctest! { @_@ $($body)* }
};
( $($attrs:meta)* $($items:item)* ) => {
$(attrs)*
$crate::doctest! { @_@
$($items)*
main()
}
}; };
} }

Loading…
Cancel
Save