Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I conditionally execute a module-level doctest based on a feature flag?

I am writing documentation for a module that has some options controlled by a Cargo feature flag. I'd like to always show this documentation so that consumers of the crate know that it's available, but I need to only run the example when the feature is enabled.

lib.rs

//! This crate has common utility functions
//!
//! ```
//! assert_eq!(2, featureful::add_one(1));
//! ```
//!
//! You may also want to use the feature flag `solve_halting_problem`:
//!
//! ```
//! assert!(featureful::is_p_equal_to_np());
//! ```

pub fn add_one(a: i32) -> i32 {
    a + 1
}

#[cfg(feature = "solve_halting_problem")]
pub fn is_p_equal_to_np() -> bool {
    true
}

Cargo.toml

[package]
name = "featureful"
version = "0.1.0"
authors = ["An Devloper <[email protected]>"]

[features]
solve_halting_problem = []

[dependencies]

Running with the feature enabled runs both doctests as expected:

$ cargo test --features=solve_halting_problem
   Doc-tests featureful

running 2 tests
test src/lib.rs -  (line 7) ... ok
test src/lib.rs -  (line 3) ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Running without the feature has an error:

$ cargo test
   Doc-tests featureful

running 2 tests
test src/lib.rs -  (line 7) ... FAILED
test src/lib.rs -  (line 3) ... ok

failures:

---- src/lib.rs -  (line 7) stdout ----
    error[E0425]: cannot find function `is_p_equal_to_np` in module `featureful`
 --> src/lib.rs:8:21
  |
4 | assert!(featureful::is_p_equal_to_np());
  |                     ^^^^^^^^^^^^^^^^ not found in `featureful`

Both the ```ignore and ```no_run modifiers apply when the feature is enabled or not, so they don't seem to be useful.


How would one achieve conditional compilation with Rust projects that have doctests? is close, but the answer focuses on functions that change with conditional compilation, not on documentation of modules.

like image 467
Shepmaster Avatar asked May 13 '18 02:05

Shepmaster


2 Answers

This works, too, and I think is much cleaner:

//! This crate has common utility functions
//!
//! ```
//! assert_eq!(2, featureful::add_one(1));
//! ```
//!
#![cfg_attr(
    not(feature = "solve_halting_problem"),
    doc = "You may also want to use the feature flag `solve_halting_problem`:"
)]
#![cfg_attr(
    feature = "solve_halting_problem",
    doc = "This example works because the `solve_halting_problem` feature flag is enabled:"
)]
//!
#![cfg_attr(not(feature = "solve_halting_problem"), doc = "```ignore")]
#![cfg_attr(feature = "solve_halting_problem", doc = "```")]
//! assert!(featureful::is_p_equal_to_np());
//! ```
like image 187
Yotam Ofek Avatar answered Oct 10 '22 04:10

Yotam Ofek


I only see one solution: put the #[cfg] inside the test:

//! ```
//! #[cfg(feature = "solve_halting_problem")]
//! assert!(featureful::is_p_equal_to_np());
//! ```

This will count as a test but it will be empty when the feature is not enabled. You can pair this with the ability to hide portions of the example and the fact that you can put the #[cfg] attribute on entire blocks as well:

//! ```
//! # #[cfg(feature = "solve_halting_problem")] {
//! assert!(featureful::is_p_equal_to_np());
//! // Better double check
//! assert!(featureful::is_p_equal_to_np());
//! # }
//! ```

As a note, maybe you could use #![feature(doc_cfg)] like this:

/// This function is super useful
///
/// ```
/// assert!(featureful::is_p_equal_to_np());
/// ```
#[cfg(any(feature = "solve_halting_problem", feature = "dox"))]
#[doc(cfg(feature = "solve_halting_problem"))]
pub fn is_p_equal_to_np() -> bool {
    true
}

This will not run the test when the feature is disabled but this will generate the doc with cargo doc --features dox.

like image 30
Stargateur Avatar answered Oct 10 '22 04:10

Stargateur