Rust's Documentation Test doesn't works

Hi. I'm new to Rust. Since documentation inside the source code is one of the main selling point of Rust, I'm trying to use it.

Rust 1.5 Windows. The project was built with cargo new

main.rs:

/// # Examples
/// ```
/// let x = 5;
/// assert_eq(x, 5);
/// ```
fn do_something() {}
fn main() {
    println!("Hello, world!");
    do_something();
}

the documentation is detected by VSCode, VSCode displays documentation for do_something correctly.
But cargo test unable to detect or even test the assert line inside the doc. Why is it doesn't work ?

$ cargo test
   Compiling test-docs v0.1.0 (E:\Works\Experimentals\rust-testing\test-docs)
    Finished test [unoptimized + debuginfo] target(s) in 0.29s
     Running target\debug\deps\test_docs-5b0c9e788dc2a00c.exe

running 0 tests

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

How to create a tested documentation in Rust ?

Doc tests are run to ensure the doc comment is synced with the implementation. Doc comment is to add explanation to auto-generated API document. API document is to help users of the library. That's why the doc tests uses the current crate as a user like the one specified the crate's name into its Cargo.toml.

Since you don't have the lib.rs, there's no library, there's no API document, the doc tests are not run.

OK. I rewrite the code into this. While it works for lib.rs, why it doesn't for the others.rs file ?

mod lib;
mod others;

fn main() {
    println!("Hello, world!");
    lib::do_something();           // <--- this works, the cargo test runs just for this file
    others::do_something_else();   // <--- this doesn't. The cargo test doesn't run any doc-test here
}

Well, you should never write the mod lib;. The src/lib.rs and the src/main.rs is the special file names the cargo knows. The lib.rs becomes the root module of the library, while the main.rs becomes the root module of the default binary.

https://doc.rust-lang.org/cargo/guide/project-layout.html

With the snippet, the mod others; is declared within the main.rs. So it's part of the binary crate, not library crate.

1 Like

To clarify a bit (hopefully), if you have a lib.rs and a main.rs, two different crates get compiled, a library crate and a binary crate. The binary crate is linked with the library crate. The library crate is what's running your doc tests.

When you write mod lib; (which you should never do), lib.rs gets compiled into both your library crate and your binary crate. But again, only the library crate runs doc tests. And the library crate is still linked with your binary crate, so you have two versions of that compiled file in your binary, one of the reasons to never do this.

Below is an example to illustrate two versions of lib.rs from the two crates ending up in the binary:

Project name: example.

Contents of src/lib.rs:

pub const WHOAMI: &'static str = "Library crate";

pub fn foo() {
    println!("{}", crate::WHOAMI);
}

Contents of src/main.rs:

mod lib;
pub const WHOAMI: &'static str = "main.rs crate";

fn main() {
    example::foo();
    lib::foo();
}

Output of the program:

Library crate
main.rs crate
2 Likes

OK Thank you. It's clearer now. Since main.rs is the main entry point, then all function, struct, and constants should be defined within lib.rs. Only then, I can use the cargo doc and test docs that are in lib.rs and its dependencies.

1 Like