summaryrefslogtreecommitdiffstats
path: root/vendor/mdbook/tests/dummy_book/mod.rs
blob: d9d9a068deccf413cd076809de7e6809c744501a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! This will create an entire book in a temporary directory using some
//! dummy contents from the `tests/dummy-book/` directory.

// Not all features are used in all test crates, so...
#![allow(dead_code, unused_variables, unused_imports, unused_extern_crates)]

use anyhow::Context;
use mdbook::errors::*;
use mdbook::MDBook;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use tempfile::{Builder as TempFileBuilder, TempDir};
use walkdir::WalkDir;

/// Create a dummy book in a temporary directory, using the contents of
/// `SUMMARY_MD` as a guide.
///
/// The "Nested Chapter" file contains a code block with a single
/// `assert!($TEST_STATUS)`. If you want to check MDBook's testing
/// functionality, `$TEST_STATUS` can be substitute for either `true` or
/// `false`. This is done using the `passing_test` parameter.
#[derive(Clone, Debug, PartialEq)]
pub struct DummyBook {
    passing_test: bool,
}

impl DummyBook {
    /// Create a new `DummyBook` with all the defaults.
    pub fn new() -> DummyBook {
        DummyBook { passing_test: true }
    }

    /// Whether the doc-test included in the "Nested Chapter" should pass or
    /// fail (it passes by default).
    pub fn with_passing_test(&mut self, test_passes: bool) -> &mut DummyBook {
        self.passing_test = test_passes;
        self
    }

    /// Write a book to a temporary directory using the provided settings.
    pub fn build(&self) -> Result<TempDir> {
        let temp = TempFileBuilder::new()
            .prefix("dummy_book-")
            .tempdir()
            .with_context(|| "Unable to create temp directory")?;

        let dummy_book_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/dummy_book");
        recursive_copy(&dummy_book_root, temp.path()).with_context(|| {
            "Couldn't copy files into a \
             temporary directory"
        })?;

        let sub_pattern = if self.passing_test { "true" } else { "false" };
        let files_containing_tests = [
            "src/first/nested.md",
            "src/first/nested-test.rs",
            "src/first/nested-test-with-anchors.rs",
            "src/first/partially-included-test.rs",
            "src/first/partially-included-test-with-anchors.rs",
        ];
        for file in &files_containing_tests {
            let path_containing_tests = temp.path().join(file);
            replace_pattern_in_file(&path_containing_tests, "$TEST_STATUS", sub_pattern)?;
        }

        Ok(temp)
    }
}

fn replace_pattern_in_file(filename: &Path, from: &str, to: &str) -> Result<()> {
    let contents = fs::read_to_string(filename)?;
    File::create(filename)?.write_all(contents.replace(from, to).as_bytes())?;

    Ok(())
}

/// Read the contents of the provided file into memory and then iterate through
/// the list of strings asserting that the file contains all of them.
pub fn assert_contains_strings<P: AsRef<Path>>(filename: P, strings: &[&str]) {
    let filename = filename.as_ref();
    let content = fs::read_to_string(filename).expect("Couldn't read the file's contents");

    for s in strings {
        assert!(
            content.contains(s),
            "Searching for {:?} in {}\n\n{}",
            s,
            filename.display(),
            content
        );
    }
}

pub fn assert_doesnt_contain_strings<P: AsRef<Path>>(filename: P, strings: &[&str]) {
    let filename = filename.as_ref();
    let content = fs::read_to_string(filename).expect("Couldn't read the file's contents");

    for s in strings {
        assert!(
            !content.contains(s),
            "Found {:?} in {}\n\n{}",
            s,
            filename.display(),
            content
        );
    }
}

/// Recursively copy an entire directory tree to somewhere else (a la `cp -r`).
fn recursive_copy<A: AsRef<Path>, B: AsRef<Path>>(from: A, to: B) -> Result<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    for entry in WalkDir::new(&from) {
        let entry = entry.with_context(|| "Unable to inspect directory entry")?;

        let original_location = entry.path();
        let relative = original_location
            .strip_prefix(&from)
            .expect("`original_location` is inside the `from` directory");
        let new_location = to.join(relative);

        if original_location.is_file() {
            if let Some(parent) = new_location.parent() {
                fs::create_dir_all(parent).with_context(|| "Couldn't create directory")?;
            }

            fs::copy(&original_location, &new_location)
                .with_context(|| "Unable to copy file contents")?;
        }
    }

    Ok(())
}

pub fn new_copy_of_example_book() -> Result<TempDir> {
    let temp = TempFileBuilder::new().prefix("guide").tempdir()?;

    let guide = Path::new(env!("CARGO_MANIFEST_DIR")).join("guide");

    recursive_copy(guide, temp.path())?;

    Ok(temp)
}