|
| 1 | +//! This will create an entire book in a temporary directory using some |
| 2 | +//! dummy contents from the `tests/dummy-book/` directory. |
| 3 | +
|
| 4 | +// Not all features are used in all test crates, so... |
| 5 | +#![allow(dead_code, unused_variables, unused_imports, unused_extern_crates)] |
| 6 | +extern crate mdbook; |
| 7 | +extern crate tempdir; |
| 8 | +extern crate walkdir; |
| 9 | + |
| 10 | +use std::path::Path; |
| 11 | +use std::fs::{self, File}; |
| 12 | +use std::io::{Read, Write}; |
| 13 | +use mdbook::errors::*; |
| 14 | +use mdbook::utils::fs::file_to_string; |
| 15 | + |
| 16 | +// The funny `self::` here is because we've got an `extern crate ...` and are |
| 17 | +// in a submodule |
| 18 | +use self::tempdir::TempDir; |
| 19 | +use self::mdbook::MDBook; |
| 20 | +use self::walkdir::WalkDir; |
| 21 | + |
| 22 | + |
| 23 | +/// Create a dummy book in a temporary directory, using the contents of |
| 24 | +/// `SUMMARY_MD` as a guide. |
| 25 | +/// |
| 26 | +/// The "Nested Chapter" file contains a code block with a single |
| 27 | +/// `assert!($TEST_STATUS)`. If you want to check MDBook's testing |
| 28 | +/// functionality, `$TEST_STATUS` can be substitute for either `true` or |
| 29 | +/// `false`. This is done using the `passing_test` parameter. |
| 30 | +#[derive(Clone, Debug, PartialEq)] |
| 31 | +pub struct DummyBook { |
| 32 | + passing_test: bool, |
| 33 | +} |
| 34 | + |
| 35 | +impl DummyBook { |
| 36 | + /// Create a new `DummyBook` with all the defaults. |
| 37 | + pub fn new() -> DummyBook { |
| 38 | + DummyBook { passing_test: true } |
| 39 | + } |
| 40 | + |
| 41 | + /// Whether the doc-test included in the "Nested Chapter" should pass or |
| 42 | + /// fail (it passes by default). |
| 43 | + pub fn with_passing_test(&mut self, test_passes: bool) -> &mut DummyBook { |
| 44 | + self.passing_test = test_passes; |
| 45 | + self |
| 46 | + } |
| 47 | + |
| 48 | + /// Write a book to a temporary directory using the provided settings. |
| 49 | + pub fn build(&self) -> Result<TempDir> { |
| 50 | + let temp = TempDir::new("dummy_book").chain_err(|| "Unable to create temp directory")?; |
| 51 | + |
| 52 | + let dummy_book_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/dummy_book"); |
| 53 | + recursive_copy(&dummy_book_root, temp.path()).chain_err(|| { |
| 54 | + "Couldn't copy files into a \ |
| 55 | + temporary directory" |
| 56 | + })?; |
| 57 | + |
| 58 | + let sub_pattern = if self.passing_test { "true" } else { "false" }; |
| 59 | + let file_containing_test = temp.path().join("src/first/nested.md"); |
| 60 | + replace_pattern_in_file(&file_containing_test, "$TEST_STATUS", sub_pattern)?; |
| 61 | + |
| 62 | + Ok(temp) |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +fn replace_pattern_in_file(filename: &Path, from: &str, to: &str) -> Result<()> { |
| 67 | + let contents = file_to_string(filename)?; |
| 68 | + File::create(filename)?.write_all(contents.replace(from, to).as_bytes())?; |
| 69 | + |
| 70 | + Ok(()) |
| 71 | +} |
| 72 | + |
| 73 | +/// Read the contents of the provided file into memory and then iterate through |
| 74 | +/// the list of strings asserting that the file contains all of them. |
| 75 | +pub fn assert_contains_strings<P: AsRef<Path>>(filename: P, strings: &[&str]) { |
| 76 | + let filename = filename.as_ref(); |
| 77 | + let content = file_to_string(filename).expect("Couldn't read the file's contents"); |
| 78 | + |
| 79 | + for s in strings { |
| 80 | + assert!(content.contains(s), |
| 81 | + "Searching for {:?} in {}\n\n{}", |
| 82 | + s, |
| 83 | + filename.display(), |
| 84 | + content); |
| 85 | + } |
| 86 | +} |
| 87 | + |
| 88 | + |
| 89 | + |
| 90 | +/// Recursively copy an entire directory tree to somewhere else (a la `cp -r`). |
| 91 | +fn recursive_copy<A: AsRef<Path>, B: AsRef<Path>>(from: A, to: B) -> Result<()> { |
| 92 | + let from = from.as_ref(); |
| 93 | + let to = to.as_ref(); |
| 94 | + |
| 95 | + for entry in WalkDir::new(&from) { |
| 96 | + let entry = entry.chain_err(|| "Unable to inspect directory entry")?; |
| 97 | + |
| 98 | + let original_location = entry.path(); |
| 99 | + let relative = original_location.strip_prefix(&from) |
| 100 | + .expect("`original_location` is inside the `from` \ |
| 101 | + directory"); |
| 102 | + let new_location = to.join(relative); |
| 103 | + |
| 104 | + if original_location.is_file() { |
| 105 | + if let Some(parent) = new_location.parent() { |
| 106 | + fs::create_dir_all(parent).chain_err(|| "Couldn't create directory")?; |
| 107 | + } |
| 108 | + |
| 109 | + fs::copy(&original_location, &new_location).chain_err(|| { |
| 110 | + "Unable to copy file contents" |
| 111 | + })?; |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + Ok(()) |
| 116 | +} |
0 commit comments