Reputation: 5820
I'm writing a library in rust, which exposes a function which uses a private module. Now, I can render the documentation of this private module using the following command:
cargo doc --document-private-items
Now, I have a module named reader
, which contains a struct with some functions in it.
The module itself is imported using mod reader
from the lib.rs
file and has a type which is used like: use reader::BufferedOpenTypeFontReader;
Now, I want to add some documentation to the BufferedOpenTypeFontReader
struct, so this it it's implementation:
/// A buffered `&[u8]` reader for reading an OpenType Font (OTF).
pub struct BufferedOpenTypeFontReader<'a> {
reader: BufReader<&'a [u8]>,
}
//# The basic implementation of the `OpenTypeFontByteSliceReader` struct.
impl<'a> BufferedOpenTypeFontReader<'a> {
//# Defines the constants which are required in this `impl` block.
const U32_SIZE: usize = 4; // The amount of bytes in a `u32`.
/// Create a new `BufferedOpenTypeFontReader<'a>` implementation which reads from the given `&[u8]`.
///
/// # Examples:
/// ```
/// use otfdecode::reader::BufferedOpenTypeFontReader;
///
/// let otf_bytes = [];
/// let otf_reader = BufferedOpenTypeFontReader::new(otf_bytes);
/// ```
pub fn new(data: &'a [u8]) -> Self {
Self {
reader: BufReader::new(data),
}
}
pub fn read_u32(&mut self) -> u32 {
let mut buffer = [0u8; Self::U32_SIZE];
self.reader.read_exact(&mut buffer).unwrap();
u32::from_be_bytes(buffer)
}
}
However, when I run cargo test
, I have the following issue:
failures:
---- src\reader.rs - reader::BufferedOpenTypeFontReader::new (line 42) stdout ----
error[E0603]: module `reader` is private
--> src\reader.rs:43:16
|
4 | use otfdecode::reader::BufferedOpenTypeFontReader;
| ^^^^^^ private module
|
note: the module `reader` is defined here
--> C:\Users\kevin\Development\github.com\kdeconinck\OTFDecode\app\src\lib.rs:30:1
|
30 | mod reader;
|
How can I write documentation tests for the function new
without making the module reader
public?
Upvotes: 7
Views: 1734
Reputation: 3050
At the time of this writing, this is not (yet) possible in Rust. I did some research on this issue and these are my conclusions:
Doctests are compiled as separate, external units. First your library is compiled, and then the doctest compilation unit is linked against your library. When the doctest is being compiled, the library behaves exactly like an external library would. Not even pub(crate)
works, since it really is a separate library according to the compiler.
This makes some philosophical sense if you see the documentation as a product to help people use your library. They will be using your library as an external, so it makes sense to make the library behave as it would for them. The downside of this is that it kind of discourages writing (good) documentation for that other purpose: To make the library itself more easily maintainable in the long run.
There are voices that want to change this. In particular, see this issue. But it's not getting a lot of traction yet as of this writing.
There are no good workarounds, really. These are the workarounds people have come up with, but none are satisfying:
ignore
to the doctests that use private symbols. This has the disadvantage that you're unsure of whether the documented example still works if you later make changes (unless you duplicate the code to a unit test, but then you have duplicate code). Like so:/// Computes the sum of two numbers.
///
/// # Examples
/// ```ignore
/// use calculator::adder::private_adder;
/// assert_eq!(5, private_adder(2, 3));
/// ```
fn private_adder(left: i32, right: i32) { left + right }
detail
or private
submodule so that it's sort of clear to the users of your library that it shouldn't be used. This has the disadvantage that it still allows users of the library to discover and use these functions, thinking they are smart, and then possibly breaking stuff. It also clutters up your public API and possibly reveals more about the secret business logic inside of your library if that is something you're concerned about.doctest_privates
feature to the command: cargo test --doc --features doctest_privates
. However this requires adding the following attribute to each and every one of your private symbols (or at least, all the modules, classes and functions that you'd like to use in a doctest):/// Computes the sum of two numbers.
///
/// # Examples
/// ```
/// use calculator::adder::private_adder;
/// assert_eq!(5, private_adder(2, 3));
/// ```
#[cfg_attr(feature = "document_privates", visibility::make(pub))]
fn private_adder(left: i32, right: i32) { left + right }
Upvotes: 8
Reputation: 26717
From documentations tests documentation:
Note that they will still link against only the public items of your crate; if you need to test private items, you need to write a unit test. https://doc.rust-lang.org/rustdoc/documentation-tests.html
Upvotes: 4