docmatic/lib.rs
1//! docmatic:
2//!
3//! `docmatic` runs `rustdoc` on your documentation files.
4//!
5//! ## Writing code blocks
6//!
7//! See ["Documentation tests"](https://doc.rust-lang.org/beta/rustdoc/documentation-tests.html)
8//! for how to customize your code blocks being run as tests.
9//!
10//! ## Example
11//!
12//! First, add this to your `Cargo.toml`:
13//!
14//! ```toml
15//! [dev-dependencies]
16//! docmatic = "0.1"
17//! ```
18//!
19//! Next, in your test file:
20//!
21//! ```rust
22//! extern crate docmatic;
23//!
24//! fn test_readme() {
25//! docmatic::assert_file("README.md");
26//! }
27//! ```
28
29extern crate which;
30
31use std::path;
32use std::ffi::OsStr;
33
34/// A specialized process builder managing a `rustdoc` test session.
35///
36/// # Example
37///
38/// The following code will test the crate README with the `docmatic`
39/// configuration set and a default library path:
40///
41/// ```rust
42/// extern crate docmatic;
43///
44/// use std::default::Default;
45///
46/// fn test_readme() {
47/// docmatic::Assert::default()
48/// .cfg("docmatic")
49/// .test_file("README.md")
50/// }
51/// ```
52pub struct Assert(std::process::Command);
53
54impl Assert {
55 /// Construct a new `Assert` with no flags set.
56 ///
57 /// Will likely fail if you don't provide at least one library path
58 /// containing the tested crate. Instead, you should probably use
59 /// [`Assert::default`]
60 ///
61 /// [`Assert::default`]: #tymethod.default
62 pub fn new() -> Self {
63 let executable = which::which("rustdoc").expect("rustdoc not found");
64 Assert(std::process::Command::new(executable))
65 }
66
67 /// Add a path to the library paths passed to `rustdoc`.
68 pub fn library_path<S>(&mut self, path: S) -> &mut Self
69 where
70 S: AsRef<OsStr>,
71 {
72 self.0.arg("--library-path").arg(path);
73 self
74 }
75
76 /// Add a *cfg* to the configuration passed to `rustdoc`.
77 pub fn cfg<S>(&mut self, cfg: S) -> &mut Self
78 where
79 S: AsRef<OsStr>,
80 {
81 self.0.arg("--cfg").arg(cfg);
82 self
83 }
84
85 /// Test the given file, and panics on failure.
86 pub fn test_file<P>(&mut self, path: P)
87 where
88 P: AsRef<path::Path>,
89 {
90 let process = self.0.arg("--test").arg(path.as_ref()).spawn();
91
92 let result = process
93 .expect("rustdoc is runnable")
94 .wait()
95 .expect("rustdoc can run");
96
97 assert!(
98 result.success(),
99 format!("Failed to run rustdoc tests on '{:?}'", path.as_ref())
100 );
101 }
102}
103
104impl Default for Assert {
105 /// Create an `Assert` instance with the following default parameters:
106 ///
107 /// * `--library-path` set to the current *deps* directory (`target/debug/deps` or
108 /// `target/release/deps` depending on the test compilation mode).
109 ///
110 fn default() -> Self {
111 let mut assert = Self::new();
112 let current_exe = std::env::current_exe()
113 .and_then(|p| p.canonicalize())
114 .expect("could not get path to test executable");
115 assert.library_path(current_exe.parent().expect("parent exists"));
116 assert
117 }
118}
119
120/// Test a single file with default parameters.
121pub fn assert_file<P>(documentation: P)
122where
123 P: AsRef<path::Path>,
124{
125 Assert::default().test_file(documentation);
126}