Doc test for macro

Hmm, so I worked my self hard and am so proud my documentation is almost done and all my test and doc tests pass. But then I did a little playing and put in a panic and a test did not fail. My doc tests call a macro and the macro does not get invoked. So I read and after a bit I find this nice little piece I read before and ignored.
Documentation tests - The rustdoc book and I see some simple answers.

/// # #[macro_use] extern crate foo;
/// # fn main() {
/// panic_unless!(1 + 1 == 2, “Math is broken.”);
/// # }

and the explanation of course I read and kind of understand. Sounds easy. But the macro I am writing a doc test for is a macro that writes a main function. Of course this makes things complicated. I am hopeful that someone else has written a macro that creates a main function and written a doc test for it. Maybe a pointer in some direction.
Minimal example
src/lib.rs

/// ```
/// #[macro_use] extern crate macrotest;
/// macrotest::write_main!(prog, Opt);
///
/// struct Opt {
/// }
///
/// fn prog(options: &Opt) {
///     panic!("passes");
/// }
///```

#[macro_export]
macro_rules! write_main {
    ($prog_name:ident, $opt_name:ident) => {
        fn main() {
            let options = $opt_name{};
            $prog_name(&options);
        }
    };
}

src/main

macrotest::write_main!(prog, Opt);

struct Opt {}

fn prog(_options: &Opt) {
    panic!("passes");
}

Run panics because it should.

$ cargo r
   Compiling macrotest v0.1.0 (/home/js/learn/rust/macrotest)
    Finished dev [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/macrotest`
thread 'main' panicked at 'passes', src/main.rs:6:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Testing passes because it does not run macro.

$ cargo test
   Compiling macrotest v0.1.0 (/home/js/learn/rust/macrotest)
    Finished test [unoptimized + debuginfo] target(s) in 0.51s
     Running unittests (target/debug/deps/macrotest-7edb55e78be315e5)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running unittests (target/debug/deps/macrotest-18d71e2f7194f236)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests macrotest

running 1 test
test src/lib.rs - write_main (line 2) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.24s

I think what might be going on here is that rustdoc cannot "see" any main function (since it's hidden inside a macro), so it wraps everything inside of a main function for you.

I don't really understand the remarks in the rustdoc book, both regarding the "need" for a #[macro_use] extern crate or the "need" for adding a main function yourself when testing macros. The latter can easily be tested by just adding a line

/// # main();

that calls the main function at the end of your code; and you might also want to try skipping the (in my eyes redundant) extern crate.

I'm on mobile right now, so I can't easily test this myself.

Edit: Actually, I can test it in the playground... looks like I guessed correctly Rust Playground

Edit2: If you don't like having a "main" function inside a main function, you can apparently also trick rustdoc into thinking that it can see a main function after all, with something like this: Rust Playground

Well sir, thank you very much.

Works very well as does

/// # /* fn main() {} */

I did try

/// # fn main() {}

and got the "previous definition of the value main" error. I don't know why this style with // comments does not work

/// # // fn main()  {}

but wrapping it in /* */ does work.

I do not know if this is a corner I want to spend more time looking into? (dark corners are fractal) I do wonder how did you know to comment out the main function in that manner so it would still be seen? And this style of function declaration, without the 'fn' before it. Can you explain?

/// # main();

It's not a declaration but a function call. Your code basically expands to

fn main() {
    fn main() { ... }
    struct Opt { ... } 
    fn prog() { ... }
    main();
}

in this case, I. e. as I mentioned, rustdoc will wrap the doctest into another main function because it couldn't see there already was one. So there's a function called main inside of the main function. That's also why without such a main(); call, the code did nothing when executed and the test didn't fail.

The heuristic that rustdoc uses to determine whether or not a main function is present in the doctest apparently just seems not to support /* */ style comments (i. e. it doesn't ignore their contents when scanning for fn main). I don't know whether that's intentional or a bug, but even if it's a bug, it might never be fixed because the fix could cause more harm than good.

Oh, that is very understandable. Thank you, my brain just absorbed and the confusion went away.

So I put the

/// # main();

line in my doc tests and now they run and most of them fail because they have mistakes I did not notice.
But today I have 'real life' so code must wait.