]> git.proxmox.com Git - rustc.git/blame - src/doc/rustdoc/src/documentation-tests.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / rustdoc / src / documentation-tests.md
CommitLineData
041b39d2
XL
1# Documentation tests
2
3b2f2976 3`rustdoc` supports executing your documentation examples as tests. This makes sure
60c5eb7d 4that examples within your documentation are up to date and working.
3b2f2976
XL
5
6The basic idea is this:
7
6a06907d 8```rust,no_run
3b2f2976
XL
9/// # Examples
10///
11/// ```
12/// let x = 5;
13/// ```
6a06907d 14# fn f() {}
3b2f2976
XL
15```
16
17The triple backticks start and end code blocks. If this were in a file named `foo.rs`,
18running `rustdoc --test foo.rs` will extract this example, and then run it as a test.
19
29967ef6
XL
20Please note that by default, if no language is set for the block code, rustdoc
21assumes it is Rust code. So the following:
ea8adc8c 22
0531ce1d 23``````markdown
ea8adc8c
XL
24```rust
25let x = 5;
26```
0531ce1d 27``````
ea8adc8c
XL
28
29is strictly equivalent to:
30
0531ce1d 31``````markdown
ea8adc8c
XL
32```
33let x = 5;
34```
0531ce1d 35``````
ea8adc8c 36
3b2f2976
XL
37There's some subtlety though! Read on for more details.
38
0531ce1d
XL
39## Passing or failing a doctest
40
41Like regular unit tests, regular doctests are considered to "pass"
42if they compile and run without panicking.
43So if you want to demonstrate that some computation gives a certain result,
44the `assert!` family of macros works the same as other Rust code:
45
46```rust
47let foo = "foo";
0531ce1d
XL
48assert_eq!(foo, "foo");
49```
50
51This way, if the computation ever returns something different,
52the code panics and the doctest fails.
53
3b2f2976
XL
54## Pre-processing examples
55
56In the example above, you'll note something strange: there's no `main`
57function! Forcing you to write `main` for every example, no matter how small,
29967ef6
XL
58adds friction and clutters the output. So `rustdoc` processes your examples
59slightly before running them. Here's the full algorithm `rustdoc` uses to
60preprocess examples:
3b2f2976 61
abe05a73 621. Some common `allow` attributes are inserted, including
3b2f2976
XL
63 `unused_variables`, `unused_assignments`, `unused_mut`,
64 `unused_attributes`, and `dead_code`. Small examples often trigger
65 these lints.
abe05a73
XL
662. Any attributes specified with `#![doc(test(attr(...)))]` are added.
673. Any leading `#![foo]` attributes are left intact as crate attributes.
684. If the example does not contain `extern crate`, and
69 `#![doc(test(no_crate_inject))]` was not specified, then `extern crate
3b2f2976 70 <mycrate>;` is inserted (note the lack of `#[macro_use]`).
abe05a73 715. Finally, if the example does not contain `fn main`, the remainder of the
3b2f2976
XL
72 text is wrapped in `fn main() { your_code }`.
73
ff7c6d11 74For more about that caveat in rule 4, see "Documenting Macros" below.
3b2f2976
XL
75
76## Hiding portions of the example
77
78Sometimes, you need some setup code, or other things that would distract
79from your example, but are important to make the tests work. Consider
80an example block that looks like this:
81
6a06907d 82```rust,no_run
29967ef6 83/// ```
94b46f34
XL
84/// /// Some documentation.
85/// # fn foo() {} // this function will be hidden
86/// println!("Hello, World!");
29967ef6 87/// ```
6a06907d 88# fn f() {}
3b2f2976
XL
89```
90
91It will render like this:
92
93```rust
94/// Some documentation.
95# fn foo() {}
94b46f34 96println!("Hello, World!");
3b2f2976
XL
97```
98
99Yes, that's right: you can add lines that start with `# `, and they will
100be hidden from the output, but will be used when compiling your code. You
101can use this to your advantage. In this case, documentation comments need
102to apply to some kind of function, so if I want to show you just a
103documentation comment, I need to add a little function definition below
104it. At the same time, it's only there to satisfy the compiler, so hiding
105it makes the example more clear. You can use this technique to explain
106longer examples in detail, while still preserving the testability of your
107documentation.
108
109For example, imagine that we wanted to document this code:
110
111```rust
112let x = 5;
113let y = 6;
114println!("{}", x + y);
115```
116
117We might want the documentation to end up looking like this:
118
119> First, we set `x` to five:
120>
121> ```rust
122> let x = 5;
123> # let y = 6;
124> # println!("{}", x + y);
125> ```
126>
127> Next, we set `y` to six:
128>
129> ```rust
130> # let x = 5;
131> let y = 6;
132> # println!("{}", x + y);
133> ```
134>
135> Finally, we print the sum of `x` and `y`:
136>
137> ```rust
138> # let x = 5;
139> # let y = 6;
140> println!("{}", x + y);
141> ```
142
143To keep each code block testable, we want the whole program in each block, but
144we don't want the reader to see every line every time. Here's what we put in
145our source code:
146
83c7162d
XL
147``````markdown
148First, we set `x` to five:
3b2f2976 149
83c7162d
XL
150```
151let x = 5;
152# let y = 6;
153# println!("{}", x + y);
154```
3b2f2976 155
83c7162d 156Next, we set `y` to six:
3b2f2976 157
83c7162d
XL
158```
159# let x = 5;
160let y = 6;
161# println!("{}", x + y);
162```
3b2f2976 163
83c7162d 164Finally, we print the sum of `x` and `y`:
3b2f2976 165
3b2f2976 166```
83c7162d
XL
167# let x = 5;
168# let y = 6;
169println!("{}", x + y);
170```
171``````
3b2f2976
XL
172
173By repeating all parts of the example, you can ensure that your example still
174compiles, while only showing the parts that are relevant to that part of your
175explanation.
176
8faf50e0 177The `#`-hiding of lines can be prevented by using two consecutive hashes
0731742a 178`##`. This only needs to be done with the first `#` which would've
8faf50e0
XL
179otherwise caused hiding. If we have a string literal like the following,
180which has a line that starts with a `#`:
181
182```rust
183let s = "foo
184## bar # baz";
185```
186
187We can document it by escaping the initial `#`:
188
189```text
190/// let s = "foo
191/// ## bar # baz";
192```
193
94b46f34
XL
194
195## Using `?` in doc tests
196
197When writing an example, it is rarely useful to include a complete error
198handling, as it would add significant amounts of boilerplate code. Instead, you
199may want the following:
3b2f2976 200
6a06907d 201```rust,no_run
94b46f34 202/// ```
3b2f2976
XL
203/// use std::io;
204/// let mut input = String::new();
205/// io::stdin().read_line(&mut input)?;
94b46f34 206/// ```
6a06907d 207# fn f() {}
3b2f2976
XL
208```
209
94b46f34
XL
210The problem is that `?` returns a `Result<T, E>` and test functions don't
211return anything, so this will give a mismatched types error.
212
213You can get around this limitation by manually adding a `main` that returns
214`Result<T, E>`, because `Result<T, E>` implements the `Termination` trait:
3b2f2976 215
6a06907d 216```rust,no_run
3b2f2976
XL
217/// A doc test using ?
218///
219/// ```
220/// use std::io;
94b46f34
XL
221///
222/// fn main() -> io::Result<()> {
223/// let mut input = String::new();
224/// io::stdin().read_line(&mut input)?;
225/// Ok(())
226/// }
227/// ```
6a06907d 228# fn f() {}
94b46f34
XL
229```
230
231Together with the `# ` from the section above, you arrive at a solution that
232appears to the reader as the initial idea but works with doc tests:
233
6a06907d 234```rust,no_run
94b46f34
XL
235/// ```
236/// use std::io;
237/// # fn main() -> io::Result<()> {
3b2f2976
XL
238/// let mut input = String::new();
239/// io::stdin().read_line(&mut input)?;
240/// # Ok(())
241/// # }
242/// ```
6a06907d 243# fn f() {}
3b2f2976
XL
244```
245
9fa01778
XL
246As of version 1.34.0, one can also omit the `fn main()`, but you will have to
247disambiguate the error type:
248
6a06907d 249```rust,no_run
9fa01778
XL
250/// ```
251/// use std::io;
252/// let mut input = String::new();
253/// io::stdin().read_line(&mut input)?;
254/// # Ok::<(), io::Error>(())
255/// ```
6a06907d 256# fn f() {}
9fa01778
XL
257```
258
259This is an unfortunate consequence of the `?` operator adding an implicit
260conversion, so type inference fails because the type is not unique. Please note
261that you must write the `(())` in one sequence without intermediate whitespace
29967ef6 262so that `rustdoc` understands you want an implicit `Result`-returning function.
9fa01778 263
94b46f34 264## Documenting macros
3b2f2976
XL
265
266Here’s an example of documenting a macro:
267
268```rust
269/// Panic with a given message unless an expression evaluates to true.
270///
271/// # Examples
272///
273/// ```
274/// # #[macro_use] extern crate foo;
275/// # fn main() {
276/// panic_unless!(1 + 1 == 2, “Math is broken.”);
277/// # }
278/// ```
279///
ea8adc8c 280/// ```should_panic
3b2f2976
XL
281/// # #[macro_use] extern crate foo;
282/// # fn main() {
283/// panic_unless!(true == false, “I’m broken.”);
284/// # }
285/// ```
286#[macro_export]
287macro_rules! panic_unless {
288 ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
289}
290# fn main() {}
291```
292
293You’ll note three things: we need to add our own `extern crate` line, so that
294we can add the `#[macro_use]` attribute. Second, we’ll need to add our own
295`main()` as well (for reasons discussed above). Finally, a judicious use of
296`#` to comment out those two things, so they don’t show up in the output.
297
298## Attributes
299
300There are a few annotations that are useful to help `rustdoc` do the right
301thing when testing your code:
302
303```rust
304/// ```ignore
305/// fn foo() {
306/// ```
307# fn foo() {}
308```
309
310The `ignore` directive tells Rust to ignore your code. This is almost never
311what you want, as it's the most generic. Instead, consider annotating it
312with `text` if it's not code, or using `#`s to get a working example that
313only shows the part you care about.
314
315```rust
316/// ```should_panic
317/// assert!(false);
318/// ```
319# fn foo() {}
320```
321
322`should_panic` tells `rustdoc` that the code should compile correctly, but
323not actually pass as a test.
324
ba9703b0 325```rust
3b2f2976
XL
326/// ```no_run
327/// loop {
328/// println!("Hello, world");
329/// }
330/// ```
331# fn foo() {}
332```
333
94b46f34
XL
334The `no_run` attribute will compile your code, but not run it. This is
335important for examples such as "Here's how to retrieve a web page,"
336which you would want to ensure compiles, but might be run in a test
337environment that has no network access.
ea8adc8c
XL
338
339```text
340/// ```compile_fail
341/// let x = 5;
342/// x += 2; // shouldn't compile!
343/// ```
344```
345
94b46f34
XL
346`compile_fail` tells `rustdoc` that the compilation should fail. If it
347compiles, then the test will fail. However please note that code failing
348with the current Rust release may work in a future release, as new features
349are added.
8faf50e0 350
0bf4aa26
XL
351```text
352/// Only runs on the 2018 edition.
353///
354/// ```edition2018
355/// let result: Result<i32, ParseIntError> = try {
356/// "1".parse::<i32>()?
357/// + "2".parse::<i32>()?
358/// + "3".parse::<i32>()?
359/// };
360/// ```
361```
362
ba9703b0
XL
363`edition2018` tells `rustdoc` that the code sample should be compiled using
364the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile
365the code with the 2015 edition.
0bf4aa26 366
8faf50e0
XL
367## Syntax reference
368
369The *exact* syntax for code blocks, including the edge cases, can be found
29967ef6 370in the [Fenced Code Blocks](https://spec.commonmark.org/0.29/#fenced-code-blocks)
8faf50e0
XL
371section of the CommonMark specification.
372
373Rustdoc also accepts *indented* code blocks as an alternative to fenced
374code blocks: instead of surrounding your code with three backticks, you
375can indent each line by four or more spaces.
376
377``````markdown
378 let foo = "foo";
379 assert_eq!(foo, "foo");
380``````
381
382These, too, are documented in the CommonMark specification, in the
29967ef6 383[Indented Code Blocks](https://spec.commonmark.org/0.29/#indented-code-blocks)
8faf50e0
XL
384section.
385
386However, it's preferable to use fenced code blocks over indented code blocks.
387Not only are fenced code blocks considered more idiomatic for Rust code,
388but there is no way to use directives such as `ignore` or `should_panic` with
389indented code blocks.
e74abb32
XL
390
391### Include items only when collecting doctests
392
393Rustdoc's documentation tests can do some things that regular unit tests can't, so it can
394sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
395documentation. To this end, Rustdoc allows you to have certain items only appear when it's
396collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
397docs, or to find an arbitrary private item to include it on.
398
29967ef6 399When compiling a crate for use in doctests (with `--test` option), `rustdoc` will set `#[cfg(doctest)]`.
e74abb32
XL
400Note that they will still link against only the public items of your crate; if you need to test
401private items, you need to write a unit test.
402
403In this example, we're adding doctests that we know won't compile, to verify that our struct can
404only take in valid data:
405
406```rust
407/// We have a struct here. Remember it doesn't accept negative numbers!
408pub struct MyStruct(pub usize);
409
410/// ```compile_fail
411/// let x = my_crate::MyStruct(-5);
412/// ```
413#[cfg(doctest)]
414pub struct MyStructOnlyTakesUsize;
415```
416
417Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate
29967ef6 418API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while `rustdoc` is
e74abb32
XL
419collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc,
420but is hidden from the public documentation.
421
29967ef6 422Another possible use of `#[cfg(doctest)]` is to test doctests that are included in your README file
e74abb32
XL
423without including it in your main documentation. For example, you could write this into your
424`lib.rs` to test your README as part of your doctests:
425
6a06907d 426```rust,no_run
f035d41b 427#![feature(external_doc)]
e74abb32 428
29967ef6 429#[doc(include = "../README.md")]
e74abb32
XL
430#[cfg(doctest)]
431pub struct ReadmeDoctests;
432```
433
434This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will
435then be tested alongside the rest of your doctests.