Browse Source
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
1 changed files with 19 additions and 93 deletions
@ -1,113 +1,39 @@
@@ -1,113 +1,39 @@
|
||||
//! Macros for working with test runners.
|
||||
|
||||
// Use a neat little trick with cfg(doctest) to make code fences appear in
|
||||
// rustdoc output, but still compile normally when doctesting. This raises warnings
|
||||
// for invalid code though, so we also silence that lint here.
|
||||
// We use a little trick with cfg(doctest) to make code fences appear in
|
||||
// rustdoc output, but compile without them when doctesting. This raises warnings
|
||||
// for invalid code, though, so silence that lint here.
|
||||
#[cfg_attr(not(doctest), allow(rustdoc::invalid_rust_codeblocks))] |
||||
/// Helper macro for writing doctests using this runner. Wrap this macro around
|
||||
/// your normal doctest to enable running it with this crate's
|
||||
/// [`GdbRunner`](crate::GdbRunner).
|
||||
///
|
||||
/// You may use any of the various
|
||||
/// [`fn main()`](https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html#using--in-doc-tests)
|
||||
/// signatures allowed by documentation tests.
|
||||
/// Helper macro for writing doctests using this runner. Call this macro at the
|
||||
/// beginning of a doctest enables output from failing tests using this crate's
|
||||
/// [`GdbRunner`](crate::GdbRunner). Without `setup_doctest!()`, doctests will
|
||||
/// still fail on panic, but they won't display anything written to `stdout` or
|
||||
/// `stderr`.
|
||||
///
|
||||
/// # 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 = "````")] |
||||
/// ```
|
||||
/// #![allow(unused)]
|
||||
///
|
||||
/// 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! {
|
||||
/// test_runner::setup_doctest!();
|
||||
/// assert_eq!(2 + 2, 4);
|
||||
/// }
|
||||
/// Ok::<(), std::io::Error>(())
|
||||
/// ```
|
||||
#[cfg_attr(not(doctest), doc = "````")] |
||||
///
|
||||
#[cfg_attr(not(doctest), doc = "````")] |
||||
/// ```should_panic
|
||||
/// test_runner::doctest! {
|
||||
/// assert_eq!(2 + 2, 4);
|
||||
/// Err::<(), &str>("uh oh")
|
||||
/// }
|
||||
/// test_runner::setup_doctest!();
|
||||
/// assert_eq!(2 + 2, 5);
|
||||
/// ```
|
||||
#[cfg_attr(not(doctest), doc = "````")] |
||||
#[macro_export] |
||||
macro_rules! doctest { |
||||
(@_@ $($body:tt)*) => { |
||||
fn main() -> impl std::process::Termination { |
||||
#[allow(unused_imports)] |
||||
macro_rules! setup_doctest { |
||||
() => { |
||||
use $crate::TestRunner as _; |
||||
|
||||
let mut _runner = $crate::GdbRunner::default(); |
||||
_runner.setup(); |
||||
|
||||
// Luckily, Rust allows $body to define an inner shadowing main()
|
||||
// and call it, without resulting in infinite recursion.
|
||||
let _result = { $($body)* }; |
||||
let mut runner = $crate::GdbRunner::default(); |
||||
runner.setup(); |
||||
|
||||
_runner.cleanup(_result) |
||||
} |
||||
}; |
||||
( $($body:tt)* ) => { |
||||
$crate::doctest! { @_@ $($body)* } |
||||
}; |
||||
( $($attrs:meta)* $($items:item)* ) => { |
||||
$(attrs)* |
||||
$crate::doctest! { @_@ |
||||
$($items)* |
||||
main() |
||||
} |
||||
// We don't bother with cleanup here, since the macro is meant to be used
|
||||
// in a doctest context (i.e. `fn main()`, not used as a test runner)
|
||||
}; |
||||
} |
||||
|
Loading…
Reference in new issue