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