In the Rust programming language, maintaining both high-quality documentation and code examples is integral to building robust and user-friendly libraries or applications. Rust facilitates this with a powerful tool known as doctests. Doctests allow developers to embed code samples directly into their API documentation in a way that is not only illustrative but also executable. This ensures that code examples remain correct and up-to-date with the rest of the codebase.
What Are Rust Doctests?
Rust's doctests are tests from snippets of code written within documentation comments. These comments are situated above functions, structs, or modules and are written using markdown syntax. The code snippets get automatically extracted and tested alongside your unit and integration tests. By embedding examples directly with documentation, you simultaneously enhance human readability and ensure that code samples are always functional.
Writing a Simple Doctest
To write a doctest, you'd typically start by crafting a documentation comment. Consider the following function, which we will document with a doctest:
/// Adds two numbers together.
///
/// # Examples
///
/// ```
/// let sum = add(2, 3);
/// assert_eq!(sum, 5);
/// ```
///
/// # Panics
///
/// Panics if the sum exceeds a certain threshold.
fn add(a: i32, b: i32) -> i32 {
a + b
}
Here's what's happening:
- The triple slash notation (
///
) indicates a documentation comment. - Within these comments, the
# Examples
section is provided in markdown syntax. - The code block within a triple backticks segment (
```
) illustrates a small Rust program snippet that explains how to use the function.
When you run cargo test
, Rust will extract these examples, compile the snippets, and check to see if they execute correctly, aiding in catching code that might break over time.
Why Use Doctests?
- Ensure Accuracy: By linking documentation directly to your codebase, you can verify that each piece of usage documentation is correctly demonstrating your API's expected behavior.
- Easy Maintenance: When you modify code functionality, there’s a reduced risk of diverging from the documentation since doctests will fail if they become outdated.
- Readability: Enhance understanding for new developers who read your code, providing immediate context on expected behavior and usage.
Advanced Doctest Features
Doctests offer advanced features which can be utilized for more complex scenarios like including external crates or working with hidden pieces of setup code. Let’s look at an example that necessitates importing external dependencies:
/// Uses the regex crate to find patterns in a string.
///
/// # Examples
///
/// ```rust
/// extern crate regex;
/// use regex::Regex;
///
/// let re = Regex::new("^[0-9]{4}-[0-9]{2}-[0-9]{2}$").unwrap();
/// assert!(re.is_match("2014-01-01"));
/// assert!(!re.is_match("01/01/2014"));
/// ```
fn find_date() {
// Function implementation
}
Here, you’re demonstrating how to include external crates within your doctests by explicitly stating dependencies as part of the example.
Running Doctests
Executing your doctests is straightforward: simply run cargo test
at the root of your Rust project. This command will handle both your normal test functions and any documentation tests you have included throughout your codebase. Following the execution of cargo test
, any issues in your doctests will be reported along with normal test failures.
Conclusion
Rust's integration of doctests into documentation is a valuable addition to any developer's toolkit. By concurrently documenting and validating your code, it's possible to produce clearer, more reliable documentation that benefits both creators and consumers of your Rust-based software. Make use of Rust’s doctests to ensure that all samples provide accurate guidance and serve as an actionable part of maintaining high code quality.