summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lovett <lovettchris@hotmail.com>2022-08-25 19:13:51 -0700
committerGitHub <noreply@github.com>2022-08-25 19:13:51 -0700
commit74eb4059d6bea35380566411033f9a469a42f65c (patch)
tree7bbc1741145413163ba847fef71034848cd53223
parent13f53eb64f8056b7d408ca188249132a3c5e2b7b (diff)
add a --chapter option to mdbook test. (#1741)
Sometimes when working on large books it is handy to be able to run mdbook on a single chapter of a book.
-rw-r--r--guide/src/cli/test.md7
-rw-r--r--src/book/mod.rs26
-rw-r--r--src/cmd/test.rs18
-rw-r--r--tests/cli/test.rs20
-rw-r--r--tests/testing.rs21
5 files changed, 77 insertions, 15 deletions
diff --git a/guide/src/cli/test.md b/guide/src/cli/test.md
index e134dc9b..a542f3ce 100644
--- a/guide/src/cli/test.md
+++ b/guide/src/cli/test.md
@@ -43,7 +43,7 @@ mdbook test path/to/book
The `--library-path` (`-L`) option allows you to add directories to the library
search path used by `rustdoc` when it builds and tests the examples. Multiple
directories can be specified with multiple options (`-L foo -L bar`) or with a
-comma-delimited list (`-L foo,bar`). The path should point to the Cargo
+comma-delimited list (`-L foo,bar`). The path should point to the Cargo
[build cache](https://doc.rust-lang.org/cargo/guide/build-cache.html) `deps` directory that
contains the build output of your project. For example, if your Rust project's book is in a directory
named `my-book`, the following command would include the crate's dependencies when running `test`:
@@ -61,3 +61,8 @@ The `--dest-dir` (`-d`) option allows you to change the output directory for the
book. Relative paths are interpreted relative to the book's root directory. If
not specified it will default to the value of the `build.build-dir` key in
`book.toml`, or to `./book`.
+
+#### --chapter
+
+The `--chapter` (`-c`) option allows you to test a specific chapter of the
+book using the chapter name or the relative path to the chapter. \ No newline at end of file
diff --git a/src/book/mod.rs b/src/book/mod.rs
index 9745d2b7..e407ccc3 100644
--- a/src/book/mod.rs
+++ b/src/book/mod.rs
@@ -246,6 +246,13 @@ impl MDBook {
/// Run `rustdoc` tests on the book, linking against the provided libraries.
pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
+ // test_chapter with chapter:None will run all tests.
+ self.test_chapter(library_paths, None)
+ }
+
+ /// Run `rustdoc` tests on a specific chapter of the book, linking against the provided libraries.
+ /// If `chapter` is `None`, all tests will be run.
+ pub fn test_chapter(&mut self, library_paths: Vec<&str>, chapter: Option<&str>) -> Result<()> {
let library_args: Vec<&str> = (0..library_paths.len())
.map(|_| "-L")
.zip(library_paths.into_iter())
@@ -254,6 +261,8 @@ impl MDBook {
let temp_dir = TempFileBuilder::new().prefix("mdbook-").tempdir()?;
+ let mut chapter_found = false;
+
// FIXME: Is "test" the proper renderer name to use here?
let preprocess_context =
PreprocessorContext::new(self.root.clone(), self.config.clone(), "test".to_string());
@@ -270,8 +279,16 @@ impl MDBook {
_ => continue,
};
- let path = self.source_dir().join(&chapter_path);
- info!("Testing file: {:?}", path);
+ if let Some(chapter) = chapter {
+ if ch.name != chapter && chapter_path.to_str() != Some(chapter) {
+ if chapter == "?" {
+ info!("Skipping chapter '{}'...", ch.name);
+ }
+ continue;
+ }
+ }
+ chapter_found = true;
+ info!("Testing chapter '{}': {:?}", ch.name, chapter_path);
// write preprocessed file to tempdir
let path = temp_dir.path().join(&chapter_path);
@@ -311,6 +328,11 @@ impl MDBook {
if failed {
bail!("One or more tests failed");
}
+ if let Some(chapter) = chapter {
+ if !chapter_found {
+ bail!("Chapter not found: {}", chapter);
+ }
+ }
Ok(())
}
diff --git a/src/cmd/test.rs b/src/cmd/test.rs
index 02f982a4..f5ca3ee4 100644
--- a/src/cmd/test.rs
+++ b/src/cmd/test.rs
@@ -17,6 +17,16 @@ pub fn make_subcommand<'help>() -> App<'help> {
Relative paths are interpreted relative to the book's root directory.{n}\
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
),
+ ).arg(
+ Arg::new("chapter")
+ .short('c')
+ .long("chapter")
+ .value_name("chapter")
+ .help(
+ "Only test the specified chapter{n}\
+ Where the name of the chapter is defined in the SUMMARY.md file.{n}\
+ Use the special name \"?\" to the list of chapter names."
+ )
)
.arg(arg!([dir]
"Root directory for the book{n}\
@@ -41,14 +51,18 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
.values_of("library-path")
.map(std::iter::Iterator::collect)
.unwrap_or_default();
+ let chapter: Option<&str> = args.value_of("chapter");
+
let book_dir = get_book_dir(args);
let mut book = MDBook::load(&book_dir)?;
if let Some(dest_dir) = args.value_of("dest-dir") {
book.config.build.build_dir = dest_dir.into();
}
-
- book.test(library_paths)?;
+ match chapter {
+ Some(_) => book.test_chapter(library_paths, chapter),
+ None => book.test(library_paths),
+ }?;
Ok(())
}
diff --git a/tests/cli/test.rs b/tests/cli/test.rs
index bc525d9a..63114d3a 100644
--- a/tests/cli/test.rs
+++ b/tests/cli/test.rs
@@ -10,11 +10,11 @@ fn mdbook_cli_can_correctly_test_a_passing_book() {
let mut cmd = mdbook_cmd();
cmd.arg("test").current_dir(temp.path());
cmd.assert().success()
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]intro.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]index.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]nested.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"rustdoc returned an error:\n\n"##).unwrap().not())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "README.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "intro.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]index.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]nested.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"returned an error:\n\n"##).unwrap().not())
.stderr(predicates::str::is_match(r##"Nested_Chapter::Rustdoc_include_works_with_anchors_too \(line \d+\) ... FAILED"##).unwrap().not());
}
@@ -25,10 +25,10 @@ fn mdbook_cli_detects_book_with_failing_tests() {
let mut cmd = mdbook_cmd();
cmd.arg("test").current_dir(temp.path());
cmd.assert().failure()
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]intro.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]index.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]nested.md""##).unwrap())
- .stderr(predicates::str::is_match(r##"rustdoc returned an error:\n\n"##).unwrap())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "README.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "intro.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]index.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]nested.md""##).unwrap())
+ .stderr(predicates::str::is_match(r##"returned an error:\n\n"##).unwrap())
.stderr(predicates::str::is_match(r##"Nested_Chapter::Rustdoc_include_works_with_anchors_too \(line \d+\) ... FAILED"##).unwrap());
}
diff --git a/tests/testing.rs b/tests/testing.rs
index 2b2c0fd0..3030c5cb 100644
--- a/tests/testing.rs
+++ b/tests/testing.rs
@@ -24,3 +24,24 @@ fn mdbook_detects_book_with_failing_tests() {
assert!(md.test(vec![]).is_err());
}
+
+#[test]
+fn mdbook_test_chapter() {
+ let temp = DummyBook::new().with_passing_test(true).build().unwrap();
+ let mut md = MDBook::load(temp.path()).unwrap();
+
+ let result = md.test_chapter(vec![], Some("Introduction"));
+ assert!(
+ result.is_ok(),
+ "test_chapter failed with {}",
+ result.err().unwrap()
+ );
+}
+
+#[test]
+fn mdbook_test_chapter_not_found() {
+ let temp = DummyBook::new().with_passing_test(true).build().unwrap();
+ let mut md = MDBook::load(temp.path()).unwrap();
+
+ assert!(md.test_chapter(vec![], Some("Bogus Chapter Name")).is_err());
+}