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.
This commit is contained in:
parent
13f53eb64f
commit
74eb4059d6
|
@ -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
|
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
|
not specified it will default to the value of the `build.build-dir` key in
|
||||||
`book.toml`, or to `./book`.
|
`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.
|
|
@ -246,6 +246,13 @@ impl MDBook {
|
||||||
|
|
||||||
/// Run `rustdoc` tests on the book, linking against the provided libraries.
|
/// Run `rustdoc` tests on the book, linking against the provided libraries.
|
||||||
pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
|
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())
|
let library_args: Vec<&str> = (0..library_paths.len())
|
||||||
.map(|_| "-L")
|
.map(|_| "-L")
|
||||||
.zip(library_paths.into_iter())
|
.zip(library_paths.into_iter())
|
||||||
|
@ -254,6 +261,8 @@ impl MDBook {
|
||||||
|
|
||||||
let temp_dir = TempFileBuilder::new().prefix("mdbook-").tempdir()?;
|
let temp_dir = TempFileBuilder::new().prefix("mdbook-").tempdir()?;
|
||||||
|
|
||||||
|
let mut chapter_found = false;
|
||||||
|
|
||||||
// FIXME: Is "test" the proper renderer name to use here?
|
// FIXME: Is "test" the proper renderer name to use here?
|
||||||
let preprocess_context =
|
let preprocess_context =
|
||||||
PreprocessorContext::new(self.root.clone(), self.config.clone(), "test".to_string());
|
PreprocessorContext::new(self.root.clone(), self.config.clone(), "test".to_string());
|
||||||
|
@ -270,8 +279,16 @@ impl MDBook {
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = self.source_dir().join(&chapter_path);
|
if let Some(chapter) = chapter {
|
||||||
info!("Testing file: {:?}", path);
|
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
|
// write preprocessed file to tempdir
|
||||||
let path = temp_dir.path().join(&chapter_path);
|
let path = temp_dir.path().join(&chapter_path);
|
||||||
|
@ -311,6 +328,11 @@ impl MDBook {
|
||||||
if failed {
|
if failed {
|
||||||
bail!("One or more tests failed");
|
bail!("One or more tests failed");
|
||||||
}
|
}
|
||||||
|
if let Some(chapter) = chapter {
|
||||||
|
if !chapter_found {
|
||||||
|
bail!("Chapter not found: {}", chapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,16 @@ pub fn make_subcommand<'help>() -> App<'help> {
|
||||||
Relative paths are interpreted relative to the book's root directory.{n}\
|
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`.",
|
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]
|
.arg(arg!([dir]
|
||||||
"Root directory for the book{n}\
|
"Root directory for the book{n}\
|
||||||
|
@ -41,14 +51,18 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
||||||
.values_of("library-path")
|
.values_of("library-path")
|
||||||
.map(std::iter::Iterator::collect)
|
.map(std::iter::Iterator::collect)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
let chapter: Option<&str> = args.value_of("chapter");
|
||||||
|
|
||||||
let book_dir = get_book_dir(args);
|
let book_dir = get_book_dir(args);
|
||||||
let mut book = MDBook::load(&book_dir)?;
|
let mut book = MDBook::load(&book_dir)?;
|
||||||
|
|
||||||
if let Some(dest_dir) = args.value_of("dest-dir") {
|
if let Some(dest_dir) = args.value_of("dest-dir") {
|
||||||
book.config.build.build_dir = dest_dir.into();
|
book.config.build.build_dir = dest_dir.into();
|
||||||
}
|
}
|
||||||
|
match chapter {
|
||||||
book.test(library_paths)?;
|
Some(_) => book.test_chapter(library_paths, chapter),
|
||||||
|
None => book.test(library_paths),
|
||||||
|
}?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ fn mdbook_cli_can_correctly_test_a_passing_book() {
|
||||||
let mut cmd = mdbook_cmd();
|
let mut cmd = mdbook_cmd();
|
||||||
cmd.arg("test").current_dir(temp.path());
|
cmd.arg("test").current_dir(temp.path());
|
||||||
cmd.assert().success()
|
cmd.assert().success()
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "README.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]intro.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "intro.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]index.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]index.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]nested.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]nested.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"rustdoc returned an error:\n\n"##).unwrap().not())
|
.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());
|
.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();
|
let mut cmd = mdbook_cmd();
|
||||||
cmd.arg("test").current_dir(temp.path());
|
cmd.arg("test").current_dir(temp.path());
|
||||||
cmd.assert().failure()
|
cmd.assert().failure()
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "README.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]intro.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "intro.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]index.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]index.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]nested.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]nested.md""##).unwrap())
|
||||||
.stderr(predicates::str::is_match(r##"rustdoc returned an error:\n\n"##).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());
|
.stderr(predicates::str::is_match(r##"Nested_Chapter::Rustdoc_include_works_with_anchors_too \(line \d+\) ... FAILED"##).unwrap());
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,3 +24,24 @@ fn mdbook_detects_book_with_failing_tests() {
|
||||||
|
|
||||||
assert!(md.test(vec![]).is_err());
|
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());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue