]>
Commit | Line | Data |
---|---|---|
041b39d2 XL |
1 | # Documentation tests |
2 | ||
3b2f2976 | 3 | `rustdoc` supports executing your documentation examples as tests. This makes sure |
60c5eb7d | 4 | that examples within your documentation are up to date and working. |
3b2f2976 XL |
5 | |
6 | The 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 | ||
17 | The triple backticks start and end code blocks. If this were in a file named `foo.rs`, | |
18 | running `rustdoc --test foo.rs` will extract this example, and then run it as a test. | |
19 | ||
29967ef6 XL |
20 | Please note that by default, if no language is set for the block code, rustdoc |
21 | assumes it is Rust code. So the following: | |
ea8adc8c | 22 | |
0531ce1d | 23 | ``````markdown |
ea8adc8c XL |
24 | ```rust |
25 | let x = 5; | |
26 | ``` | |
0531ce1d | 27 | `````` |
ea8adc8c XL |
28 | |
29 | is strictly equivalent to: | |
30 | ||
0531ce1d | 31 | ``````markdown |
ea8adc8c XL |
32 | ``` |
33 | let x = 5; | |
34 | ``` | |
0531ce1d | 35 | `````` |
ea8adc8c | 36 | |
3b2f2976 XL |
37 | There's some subtlety though! Read on for more details. |
38 | ||
0531ce1d XL |
39 | ## Passing or failing a doctest |
40 | ||
41 | Like regular unit tests, regular doctests are considered to "pass" | |
42 | if they compile and run without panicking. | |
43 | So if you want to demonstrate that some computation gives a certain result, | |
44 | the `assert!` family of macros works the same as other Rust code: | |
45 | ||
46 | ```rust | |
47 | let foo = "foo"; | |
0531ce1d XL |
48 | assert_eq!(foo, "foo"); |
49 | ``` | |
50 | ||
51 | This way, if the computation ever returns something different, | |
52 | the code panics and the doctest fails. | |
53 | ||
3b2f2976 XL |
54 | ## Pre-processing examples |
55 | ||
56 | In the example above, you'll note something strange: there's no `main` | |
57 | function! Forcing you to write `main` for every example, no matter how small, | |
29967ef6 XL |
58 | adds friction and clutters the output. So `rustdoc` processes your examples |
59 | slightly before running them. Here's the full algorithm `rustdoc` uses to | |
60 | preprocess examples: | |
3b2f2976 | 61 | |
abe05a73 | 62 | 1. 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 |
66 | 2. Any attributes specified with `#![doc(test(attr(...)))]` are added. |
67 | 3. Any leading `#![foo]` attributes are left intact as crate attributes. | |
68 | 4. 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 | 71 | 5. 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 | 74 | For more about that caveat in rule 4, see "Documenting Macros" below. |
3b2f2976 XL |
75 | |
76 | ## Hiding portions of the example | |
77 | ||
78 | Sometimes, you need some setup code, or other things that would distract | |
79 | from your example, but are important to make the tests work. Consider | |
80 | an 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 | ||
91 | It will render like this: | |
92 | ||
93 | ```rust | |
94 | /// Some documentation. | |
95 | # fn foo() {} | |
94b46f34 | 96 | println!("Hello, World!"); |
3b2f2976 XL |
97 | ``` |
98 | ||
99 | Yes, that's right: you can add lines that start with `# `, and they will | |
100 | be hidden from the output, but will be used when compiling your code. You | |
101 | can use this to your advantage. In this case, documentation comments need | |
102 | to apply to some kind of function, so if I want to show you just a | |
103 | documentation comment, I need to add a little function definition below | |
104 | it. At the same time, it's only there to satisfy the compiler, so hiding | |
105 | it makes the example more clear. You can use this technique to explain | |
106 | longer examples in detail, while still preserving the testability of your | |
107 | documentation. | |
108 | ||
109 | For example, imagine that we wanted to document this code: | |
110 | ||
111 | ```rust | |
112 | let x = 5; | |
113 | let y = 6; | |
114 | println!("{}", x + y); | |
115 | ``` | |
116 | ||
117 | We 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 | ||
143 | To keep each code block testable, we want the whole program in each block, but | |
144 | we don't want the reader to see every line every time. Here's what we put in | |
145 | our source code: | |
146 | ||
83c7162d XL |
147 | ``````markdown |
148 | First, we set `x` to five: | |
3b2f2976 | 149 | |
83c7162d XL |
150 | ``` |
151 | let x = 5; | |
152 | # let y = 6; | |
153 | # println!("{}", x + y); | |
154 | ``` | |
3b2f2976 | 155 | |
83c7162d | 156 | Next, we set `y` to six: |
3b2f2976 | 157 | |
83c7162d XL |
158 | ``` |
159 | # let x = 5; | |
160 | let y = 6; | |
161 | # println!("{}", x + y); | |
162 | ``` | |
3b2f2976 | 163 | |
83c7162d | 164 | Finally, we print the sum of `x` and `y`: |
3b2f2976 | 165 | |
3b2f2976 | 166 | ``` |
83c7162d XL |
167 | # let x = 5; |
168 | # let y = 6; | |
169 | println!("{}", x + y); | |
170 | ``` | |
171 | `````` | |
3b2f2976 XL |
172 | |
173 | By repeating all parts of the example, you can ensure that your example still | |
174 | compiles, while only showing the parts that are relevant to that part of your | |
175 | explanation. | |
176 | ||
8faf50e0 | 177 | The `#`-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 |
179 | otherwise caused hiding. If we have a string literal like the following, |
180 | which has a line that starts with a `#`: | |
181 | ||
182 | ```rust | |
183 | let s = "foo | |
184 | ## bar # baz"; | |
185 | ``` | |
186 | ||
187 | We 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 | ||
197 | When writing an example, it is rarely useful to include a complete error | |
198 | handling, as it would add significant amounts of boilerplate code. Instead, you | |
199 | may 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 |
210 | The problem is that `?` returns a `Result<T, E>` and test functions don't |
211 | return anything, so this will give a mismatched types error. | |
212 | ||
213 | You 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 | ||
231 | Together with the `# ` from the section above, you arrive at a solution that | |
232 | appears 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 |
246 | As of version 1.34.0, one can also omit the `fn main()`, but you will have to |
247 | disambiguate 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 | ||
259 | This is an unfortunate consequence of the `?` operator adding an implicit | |
260 | conversion, so type inference fails because the type is not unique. Please note | |
261 | that you must write the `(())` in one sequence without intermediate whitespace | |
29967ef6 | 262 | so that `rustdoc` understands you want an implicit `Result`-returning function. |
9fa01778 | 263 | |
94b46f34 | 264 | ## Documenting macros |
3b2f2976 XL |
265 | |
266 | Here’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] | |
287 | macro_rules! panic_unless { | |
288 | ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } }); | |
289 | } | |
290 | # fn main() {} | |
291 | ``` | |
292 | ||
293 | You’ll note three things: we need to add our own `extern crate` line, so that | |
294 | we 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 | ||
300 | There are a few annotations that are useful to help `rustdoc` do the right | |
301 | thing when testing your code: | |
302 | ||
303 | ```rust | |
304 | /// ```ignore | |
305 | /// fn foo() { | |
306 | /// ``` | |
307 | # fn foo() {} | |
308 | ``` | |
309 | ||
310 | The `ignore` directive tells Rust to ignore your code. This is almost never | |
311 | what you want, as it's the most generic. Instead, consider annotating it | |
312 | with `text` if it's not code, or using `#`s to get a working example that | |
313 | only 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 | |
323 | not 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 |
334 | The `no_run` attribute will compile your code, but not run it. This is |
335 | important for examples such as "Here's how to retrieve a web page," | |
336 | which you would want to ensure compiles, but might be run in a test | |
337 | environment 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 |
347 | compiles, then the test will fail. However please note that code failing | |
348 | with the current Rust release may work in a future release, as new features | |
349 | are 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 |
364 | the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile | |
365 | the code with the 2015 edition. | |
0bf4aa26 | 366 | |
8faf50e0 XL |
367 | ## Syntax reference |
368 | ||
369 | The *exact* syntax for code blocks, including the edge cases, can be found | |
29967ef6 | 370 | in the [Fenced Code Blocks](https://spec.commonmark.org/0.29/#fenced-code-blocks) |
8faf50e0 XL |
371 | section of the CommonMark specification. |
372 | ||
373 | Rustdoc also accepts *indented* code blocks as an alternative to fenced | |
374 | code blocks: instead of surrounding your code with three backticks, you | |
375 | can indent each line by four or more spaces. | |
376 | ||
377 | ``````markdown | |
378 | let foo = "foo"; | |
379 | assert_eq!(foo, "foo"); | |
380 | `````` | |
381 | ||
382 | These, 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 |
384 | section. |
385 | ||
386 | However, it's preferable to use fenced code blocks over indented code blocks. | |
387 | Not only are fenced code blocks considered more idiomatic for Rust code, | |
388 | but there is no way to use directives such as `ignore` or `should_panic` with | |
389 | indented code blocks. | |
e74abb32 XL |
390 | |
391 | ### Include items only when collecting doctests | |
392 | ||
393 | Rustdoc's documentation tests can do some things that regular unit tests can't, so it can | |
394 | sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in | |
395 | documentation. To this end, Rustdoc allows you to have certain items only appear when it's | |
396 | collecting doctests, so you can utilize doctest functionality without forcing the test to appear in | |
397 | docs, or to find an arbitrary private item to include it on. | |
398 | ||
29967ef6 | 399 | When compiling a crate for use in doctests (with `--test` option), `rustdoc` will set `#[cfg(doctest)]`. |
e74abb32 XL |
400 | Note that they will still link against only the public items of your crate; if you need to test |
401 | private items, you need to write a unit test. | |
402 | ||
403 | In this example, we're adding doctests that we know won't compile, to verify that our struct can | |
404 | only take in valid data: | |
405 | ||
406 | ```rust | |
407 | /// We have a struct here. Remember it doesn't accept negative numbers! | |
408 | pub struct MyStruct(pub usize); | |
409 | ||
410 | /// ```compile_fail | |
411 | /// let x = my_crate::MyStruct(-5); | |
412 | /// ``` | |
413 | #[cfg(doctest)] | |
414 | pub struct MyStructOnlyTakesUsize; | |
415 | ``` | |
416 | ||
417 | Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate | |
29967ef6 | 418 | API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while `rustdoc` is |
e74abb32 XL |
419 | collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc, |
420 | but is hidden from the public documentation. | |
421 | ||
29967ef6 | 422 | Another possible use of `#[cfg(doctest)]` is to test doctests that are included in your README file |
e74abb32 XL |
423 | without 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)] |
431 | pub struct ReadmeDoctests; | |
432 | ``` | |
433 | ||
434 | This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will | |
435 | then be tested alongside the rest of your doctests. |