Cannot find function in doc test

When I run rustdoc --test src/main.rs where the following code is in src/main.rs I get the error "cannot find function average in the crate root". What do I need to put in front of average in the assert_eq! call to make this work?

/// ```
/// assert_eq!(average(vec![1, 2, 3, 4]), 2.5);
/// ```
pub fn average(numbers: Vec<f64>) -> f64 {
    let sum: f64 = numbers.iter().sum();
    return sum / numbers.len() as f64;
}

fn main() {
    let scores = vec![1.0, 2.0, 3.0, 4.0];
    let avg = average(scores);
    println!("average = {}", avg);
}

Doc tests are compiled like external programs, so you'll need to use main::average; where main is the crate name, inferred from the file name in this case. But this will also require you to build the file as a library first using rustc, and pass that to rustdoc --extern or -L path, if you're running this manually.

Thanks! What is the command to build it as a library?

rustc --crate-type lib src/main.rs

Okay, that created the file libmain.rlib.
Then I entered rustdoc -L libmain.rlib --test src/main.rs.
I got "error[E0463]: can't find crate for main".

Here is the content of src/main/rs:

/// ```
/// assert_eq!(main::average(vec![1, 2, 3, 4]), 2.5);
/// ```
pub fn average(numbers: Vec<f64>) -> f64 {
    let sum: f64 = numbers.iter().sum();
    return sum / numbers.len() as f64;
}

Sorry, I meant -L takes a directory path where it should search for library crates, or you can specify the library exactly using --extern main=/path/to/libmain.rlib.

Note that literals like 1 are strictly integers, so that example code will need floats like 1. or 1.0, depending on your style preference.

Ah, so this worked: rustdoc -L . --test src/main.rs.
I'm just learning about all these commands.
Can I also use the cargo command to build the library and run the doc tests?

Yes, cargo test will include doc tests, but only for libraries, whereas main.rs is interpreted as a binary. So if you had that function in src/lib.rs, with the example using your_crate_name::average, it should just work.

Is there something special about the filename src/lib.rs?
I moved the function definition and its doc test to src/math.rs which looks like this:

/// ```
/// assert_eq!(math::average(vec![1.0, 2.0, 3.0, 4.0]), 2.5);
/// ```
pub fn average(numbers: Vec<f64>) -> f64 {
    let sum: f64 = numbers.iter().sum();
    return sum / numbers.len() as f64;
}

My src/main.rs file now looks like this:

mod math;

fn main() {
    let scores = vec![1.0, 2.0, 3.0, 4.0];
    let avg = math::average(scores);
    println!("average = {}", avg);
}

When I enter cargo run it runs the code in src/main.rs and everything works as expected.

But when I enter cargo test it says "running 0 tests".

Cargo won't build that as a library, only as a module in your main binary. It only runs doc tests for library crates. You can think of mod math; as if the file was inlined mod math { pub fn average(...){...} }, rather than a separate compilation unit.

See also: Cargo Targets - The Cargo Book

2 Likes

Yes, lib.rs is special. This is a known problem in rustdoc:

https://github.com/rust-lang/rust/issues/50784

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.