-
Notifications
You must be signed in to change notification settings - Fork 13.3k
rustdoc doc tests #43812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
rustdoc doc tests #43812
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,239 @@ | ||
# Documentation tests | ||
|
||
Coming soon! | ||
`rustdoc` supports executing your documentation examples as tests. This makes sure | ||
that your tests are up to date and working. | ||
|
||
The basic idea is this: | ||
|
||
```rust,ignore | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// let x = 5; | ||
/// ``` | ||
``` | ||
|
||
The triple backticks start and end code blocks. If this were in a file named `foo.rs`, | ||
running `rustdoc --test foo.rs` will extract this example, and then run it as a test. | ||
|
||
There's some subtlety though! Read on for more details. | ||
|
||
## Pre-processing examples | ||
|
||
In the example above, you'll note something strange: there's no `main` | ||
function! Forcing you to write `main` for every example, no matter how small, | ||
adds friction. So `rustdoc` processes your examples slightly before | ||
running them. Here's the full algorithm rustdoc uses to preprocess examples: | ||
|
||
1. Any leading `#![foo]` attributes are left intact as crate attributes. | ||
2. Some common `allow` attributes are inserted, including | ||
`unused_variables`, `unused_assignments`, `unused_mut`, | ||
`unused_attributes`, and `dead_code`. Small examples often trigger | ||
these lints. | ||
3. If the example does not contain `extern crate`, then `extern crate | ||
<mycrate>;` is inserted (note the lack of `#[macro_use]`). | ||
4. Finally, if the example does not contain `fn main`, the remainder of the | ||
text is wrapped in `fn main() { your_code }`. | ||
|
||
For more about that caveat in rule 3, see "Documeting Macros" below. | ||
|
||
## Hiding portions of the example | ||
|
||
Sometimes, you need some setup code, or other things that would distract | ||
from your example, but are important to make the tests work. Consider | ||
an example block that looks like this: | ||
|
||
```text | ||
/// Some documentation. | ||
# fn foo() {} | ||
``` | ||
|
||
It will render like this: | ||
|
||
```rust | ||
/// Some documentation. | ||
# fn foo() {} | ||
``` | ||
|
||
Yes, that's right: you can add lines that start with `# `, and they will | ||
be hidden from the output, but will be used when compiling your code. You | ||
can use this to your advantage. In this case, documentation comments need | ||
to apply to some kind of function, so if I want to show you just a | ||
documentation comment, I need to add a little function definition below | ||
it. At the same time, it's only there to satisfy the compiler, so hiding | ||
it makes the example more clear. You can use this technique to explain | ||
longer examples in detail, while still preserving the testability of your | ||
documentation. | ||
|
||
For example, imagine that we wanted to document this code: | ||
|
||
```rust | ||
let x = 5; | ||
let y = 6; | ||
println!("{}", x + y); | ||
``` | ||
|
||
We might want the documentation to end up looking like this: | ||
|
||
> First, we set `x` to five: | ||
> | ||
> ```rust | ||
> let x = 5; | ||
> # let y = 6; | ||
> # println!("{}", x + y); | ||
> ``` | ||
> | ||
> Next, we set `y` to six: | ||
> | ||
> ```rust | ||
> # let x = 5; | ||
> let y = 6; | ||
> # println!("{}", x + y); | ||
> ``` | ||
> | ||
> Finally, we print the sum of `x` and `y`: | ||
> | ||
> ```rust | ||
> # let x = 5; | ||
> # let y = 6; | ||
> println!("{}", x + y); | ||
> ``` | ||
|
||
To keep each code block testable, we want the whole program in each block, but | ||
we don't want the reader to see every line every time. Here's what we put in | ||
our source code: | ||
|
||
```text | ||
First, we set `x` to five: | ||
|
||
```rust | ||
let x = 5; | ||
# let y = 6; | ||
# println!("{}", x + y); | ||
``` | ||
|
||
Next, we set `y` to six: | ||
|
||
```rust | ||
# let x = 5; | ||
let y = 6; | ||
# println!("{}", x + y); | ||
``` | ||
|
||
Finally, we print the sum of `x` and `y`: | ||
|
||
```rust | ||
# let x = 5; | ||
# let y = 6; | ||
println!("{}", x + y); | ||
``` | ||
``` | ||
|
||
By repeating all parts of the example, you can ensure that your example still | ||
compiles, while only showing the parts that are relevant to that part of your | ||
explanation. | ||
|
||
Another case where the use of `#` is handy is when you want to ignore | ||
error handling. Lets say you want the following, | ||
|
||
```rust,ignore | ||
/// use std::io; | ||
/// let mut input = String::new(); | ||
/// io::stdin().read_line(&mut input)?; | ||
``` | ||
|
||
The problem is that `?` returns a `Result<T, E>` and test functions | ||
don't return anything so this will give a mismatched types error. | ||
|
||
```rust,ignore | ||
/// A doc test using ? | ||
/// | ||
/// ``` | ||
/// use std::io; | ||
/// # fn foo() -> io::Result<()> { | ||
/// let mut input = String::new(); | ||
/// io::stdin().read_line(&mut input)?; | ||
/// # Ok(()) | ||
/// # } | ||
/// ``` | ||
# fn foo() {} | ||
``` | ||
|
||
You can get around this by wrapping the code in a function. This catches | ||
and swallows the `Result<T, E>` when running tests on the docs. This | ||
pattern appears regularly in the standard library. | ||
|
||
### Documenting macros | ||
|
||
Here’s an example of documenting a macro: | ||
|
||
```rust | ||
/// Panic with a given message unless an expression evaluates to true. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// # #[macro_use] extern crate foo; | ||
/// # fn main() { | ||
/// panic_unless!(1 + 1 == 2, “Math is broken.”); | ||
/// # } | ||
/// ``` | ||
/// | ||
/// ```rust,should_panic | ||
/// # #[macro_use] extern crate foo; | ||
/// # fn main() { | ||
/// panic_unless!(true == false, “I’m broken.”); | ||
/// # } | ||
/// ``` | ||
#[macro_export] | ||
macro_rules! panic_unless { | ||
($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } }); | ||
} | ||
# fn main() {} | ||
``` | ||
|
||
You’ll note three things: we need to add our own `extern crate` line, so that | ||
we can add the `#[macro_use]` attribute. Second, we’ll need to add our own | ||
`main()` as well (for reasons discussed above). Finally, a judicious use of | ||
`#` to comment out those two things, so they don’t show up in the output. | ||
|
||
## Attributes | ||
|
||
There are a few annotations that are useful to help `rustdoc` do the right | ||
thing when testing your code: | ||
|
||
```rust | ||
/// ```ignore | ||
/// fn foo() { | ||
/// ``` | ||
# fn foo() {} | ||
``` | ||
|
||
The `ignore` directive tells Rust to ignore your code. This is almost never | ||
what you want, as it's the most generic. Instead, consider annotating it | ||
with `text` if it's not code, or using `#`s to get a working example that | ||
only shows the part you care about. | ||
|
||
```rust | ||
/// ```should_panic | ||
/// assert!(false); | ||
/// ``` | ||
# fn foo() {} | ||
``` | ||
|
||
`should_panic` tells `rustdoc` that the code should compile correctly, but | ||
not actually pass as a test. | ||
|
||
```rust | ||
/// ```no_run | ||
/// loop { | ||
/// println!("Hello, world"); | ||
/// } | ||
/// ``` | ||
# fn foo() {} | ||
``` | ||
|
||
The `no_run` attribute will compile your code, but not run it. This is | ||
important for examples such as "Here's how to retrieve a web page," | ||
which you would want to ensure compiles, but might be run in a test | ||
environment that has no network access. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one really threw me for a loop just reading the source here before i realized that putting different tags on the code blocks triggers the "hide lines with
#
" behavior>_>