From bed54cf85457d76f479fcd406f07b39c5e8abb12 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 28 Jun 2019 10:31:27 -0500 Subject: [PATCH 1/2] rustdoc: set cfg(doctest) when collecting doctests --- src/doc/rustdoc/src/unstable-features.md | 30 +++++++++++++++++++ src/librustdoc/config.rs | 3 ++ src/libsyntax/feature_gate.rs | 4 +++ src/libsyntax_pos/symbol.rs | 2 ++ src/test/rustdoc-ui/cfg-test.rs | 10 +++++++ src/test/rustdoc-ui/cfg-test.stdout | 7 +++-- src/test/rustdoc/cfg-doctest.rs | 8 +++++ .../feature-gate/feature-gate-cfg_doctest.rs | 4 +++ .../feature-gate-cfg_doctest.stderr | 12 ++++++++ 9 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/cfg-doctest.rs create mode 100644 src/test/ui/feature-gate/feature-gate-cfg_doctest.rs create mode 100644 src/test/ui/feature-gate/feature-gate-cfg_doctest.stderr diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 3938df1a682..1d9510c9aac 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -212,6 +212,36 @@ pub struct BigX; Then, when looking for it through the `rustdoc` search, if you enter "x" or "big", search will show the `BigX` struct first. +### Include items only when collecting doctests + +Rustdoc's [documentation tests] can do some things that regular unit tests can't, so it can +sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in +documentation. To this end, Rustdoc allows you to have certain items only appear when it's +collecting doctests, so you can utilize doctest functionality without forcing the test to appear in +docs, or to find an arbitrary private item to include it on. + +If you add `#![feature(cfg_doctest)]` to your crate, Rustdoc will set `cfg(doctest)` when collecting +doctests. Note that they will still link against only the public items of your crate; if you need to +test private items, unit tests are still the way to go. + +In this example, we're adding doctests that we know won't compile, to verify that our struct can +only take in valid data: + +```rust +#![feature(cfg_doctest)] + +/// We have a struct here. Remember it doesn't accept negative numbers! +pub struct MyStruct(usize); + +/// ```compile_fail +/// let x = my_crate::MyStruct(-5); +/// ``` +#[cfg(doctest)] +pub struct MyStructOnlyTakesUsize; +``` + +[documentation tests]: documentation-tests.html + ## Unstable command-line arguments These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 67ca7f407d8..9fae246155e 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -351,6 +351,9 @@ impl Options { .unwrap_or_else(|| PathBuf::from("doc")); let mut cfgs = matches.opt_strs("cfg"); cfgs.push("rustdoc".to_string()); + if should_test { + cfgs.push("doctest".to_string()); + } let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2b242a71ad4..c1a794a0d00 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -577,6 +577,9 @@ declare_features! ( // Allows `async || body` closures. (active, async_closure, "1.37.0", Some(62290), None), + // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests + (active, cfg_doctest, "1.37.0", Some(62210), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -1592,6 +1595,7 @@ const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), + (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)), ]; #[derive(Debug)] diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 410f4b36b67..bfcb1857852 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -170,6 +170,7 @@ symbols! { cfg, cfg_attr, cfg_attr_multi, + cfg_doctest, cfg_target_feature, cfg_target_has_atomic, cfg_target_thread_local, @@ -235,6 +236,7 @@ symbols! { doc_keyword, doc_masked, doc_spotlight, + doctest, document_private_items, dotdoteq_in_patterns, dotdot_in_tuple_patterns, diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs index 4dcf512d286..5360354d77a 100644 --- a/src/test/rustdoc-ui/cfg-test.rs +++ b/src/test/rustdoc-ui/cfg-test.rs @@ -5,6 +5,8 @@ // Crates like core have doctests gated on `cfg(not(test))` so we need to make // sure `cfg(test)` is not active when running `rustdoc --test`. +#![feature(cfg_doctest)] + /// this doctest will be ignored: /// /// ``` @@ -20,3 +22,11 @@ pub struct Foo; /// ``` #[cfg(not(test))] pub struct Foo; + +/// this doctest will be tested, but will not appear in documentation: +/// +/// ``` +/// assert!(true) +/// ``` +#[cfg(doctest)] +pub struct Bar; diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout index 67873870e89..de7e6097fb7 100644 --- a/src/test/rustdoc-ui/cfg-test.stdout +++ b/src/test/rustdoc-ui/cfg-test.stdout @@ -1,6 +1,7 @@ -running 1 test -test $DIR/cfg-test.rs - Foo (line 18) ... ok +running 2 tests +test $DIR/cfg-test.rs - Foo (line 20) ... ok +test $DIR/cfg-test.rs - Bar (line 28) ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/src/test/rustdoc/cfg-doctest.rs b/src/test/rustdoc/cfg-doctest.rs new file mode 100644 index 00000000000..fca6d1029f9 --- /dev/null +++ b/src/test/rustdoc/cfg-doctest.rs @@ -0,0 +1,8 @@ +#![feature(cfg_doctest)] + +// @!has cfg_doctest/struct.SomeStruct.html +// @!has cfg_doctest/index.html '//a/@href' 'struct.SomeStruct.html' + +/// Sneaky, this isn't actually part of docs. +#[cfg(doctest)] +pub struct SomeStruct; diff --git a/src/test/ui/feature-gate/feature-gate-cfg_doctest.rs b/src/test/ui/feature-gate/feature-gate-cfg_doctest.rs new file mode 100644 index 00000000000..308f68bd52a --- /dev/null +++ b/src/test/ui/feature-gate/feature-gate-cfg_doctest.rs @@ -0,0 +1,4 @@ +#[cfg(doctest)] //~ ERROR +pub struct SomeStruct; + +fn main() {} diff --git a/src/test/ui/feature-gate/feature-gate-cfg_doctest.stderr b/src/test/ui/feature-gate/feature-gate-cfg_doctest.stderr new file mode 100644 index 00000000000..aa1d18a6f75 --- /dev/null +++ b/src/test/ui/feature-gate/feature-gate-cfg_doctest.stderr @@ -0,0 +1,12 @@ +error[E0658]: `cfg(doctest)` is experimental and subject to change + --> $DIR/feature-gate-cfg_doctest.rs:1:7 + | +LL | #[cfg(doctest)] + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/62210 + = help: add #![feature(cfg_doctest)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From cff6ce667fd8c5002f789a55f75ba70b67be42f7 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 2 Jul 2019 13:30:54 -0500 Subject: [PATCH 2/2] force single-threaded text execution --- src/test/rustdoc-ui/cfg-test.rs | 2 +- src/test/rustdoc-ui/cfg-test.stdout | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs index 5360354d77a..e88ddfb9e2a 100644 --- a/src/test/rustdoc-ui/cfg-test.rs +++ b/src/test/rustdoc-ui/cfg-test.rs @@ -1,5 +1,5 @@ // build-pass (FIXME(62277): could be check-pass?) -// compile-flags:--test +// compile-flags:--test --test-args --test-threads=1 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // Crates like core have doctests gated on `cfg(not(test))` so we need to make diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout index de7e6097fb7..86141aed5c3 100644 --- a/src/test/rustdoc-ui/cfg-test.stdout +++ b/src/test/rustdoc-ui/cfg-test.stdout @@ -1,7 +1,7 @@ running 2 tests -test $DIR/cfg-test.rs - Foo (line 20) ... ok test $DIR/cfg-test.rs - Bar (line 28) ... ok +test $DIR/cfg-test.rs - Foo (line 20) ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out