Skip to content

Commit 73a1652

Browse files
authored
Merge pull request #2819 from ehuss/test-improvements
Various test improvements
2 parents 8c5b72c + 9b5e5e7 commit 73a1652

File tree

3 files changed

+53
-12
lines changed

3 files changed

+53
-12
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ elasticlunr-rs = "3.0.2"
3535
env_logger = "0.11.8"
3636
font-awesome-as-a-crate = "0.3.0"
3737
futures-util = "0.3.31"
38+
glob = "0.3.3"
3839
handlebars = "6.3.2"
3940
hex = "0.4.3"
4041
indexmap = "2.10.0"
@@ -118,6 +119,7 @@ tokio = { workspace = true, features = ["macros", "rt-multi-thread"], optional =
118119
tower-http = { workspace = true, features = ["fs", "trace"], optional = true }
119120

120121
[dev-dependencies]
122+
glob.workspace = true
121123
regex.workspace = true
122124
select.workspace = true
123125
semver.workspace = true

tests/testsuite/book_test.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Utility for building and running tests against mdbook.
22
3+
use anyhow::Context;
34
use mdbook_driver::MDBook;
45
use mdbook_driver::init::BookBuilder;
56
use snapbox::IntoData;
@@ -91,6 +92,7 @@ impl BookTest {
9192
///
9293
/// Normally the contents outside of the `<main>` tag aren't interesting,
9394
/// and they add a significant amount of noise.
95+
#[track_caller]
9496
pub fn check_main_file(&mut self, path: &str, expected: impl IntoData) -> &mut Self {
9597
if !self.built {
9698
self.build();
@@ -107,6 +109,7 @@ impl BookTest {
107109
}
108110

109111
/// Checks the summary contents of `toc.js` against the expected value.
112+
#[track_caller]
110113
pub fn check_toc_js(&mut self, expected: impl IntoData) -> &mut Self {
111114
if !self.built {
112115
self.build();
@@ -119,6 +122,7 @@ impl BookTest {
119122
}
120123

121124
/// Returns the summary contents from `toc.js`.
125+
#[track_caller]
122126
pub fn toc_js_html(&self) -> String {
123127
let full_path = self.dir.join("book/toc.js");
124128
let actual = read_to_string(&full_path);
@@ -135,27 +139,31 @@ impl BookTest {
135139
}
136140

137141
/// Checks that the contents of the given file matches the expected value.
138-
pub fn check_file(&mut self, path: &str, expected: impl IntoData) -> &mut Self {
142+
///
143+
/// The path can use glob-style wildcards, but it must match only a single file.
144+
#[track_caller]
145+
pub fn check_file(&mut self, path_pattern: &str, expected: impl IntoData) -> &mut Self {
139146
if !self.built {
140147
self.build();
141148
}
142-
let path = self.dir.join(path);
149+
let path = glob_one(&self.dir, path_pattern);
143150
let actual = read_to_string(&path);
144151
self.assert.eq(actual, expected);
145152
self
146153
}
147154

148-
/// Checks that the given file contains the given string somewhere.
149-
pub fn check_file_contains(&mut self, path: &str, expected: &str) -> &mut Self {
155+
/// Checks that the given file contains the given [`snapbox::Assert`] pattern somewhere.
156+
///
157+
/// The path can use glob-style wildcards, but it must match only a single file.
158+
#[track_caller]
159+
pub fn check_file_contains(&mut self, path_pattern: &str, expected: &str) -> &mut Self {
150160
if !self.built {
151161
self.build();
152162
}
153-
let path = self.dir.join(path);
163+
let path = glob_one(&self.dir, path_pattern);
154164
let actual = read_to_string(&path);
155-
assert!(
156-
actual.contains(expected),
157-
"Did not find {expected:?} in {path:?}\n\n{actual}",
158-
);
165+
let expected = format!("...\n[..]{expected}[..]\n...\n");
166+
self.assert.eq(actual, expected);
159167
self
160168
}
161169

@@ -164,11 +172,14 @@ impl BookTest {
164172
/// Beware that using this is fragile, as it may be unable to catch
165173
/// regressions (it can't tell the difference between success, or the
166174
/// string being looked for changed).
167-
pub fn check_file_doesnt_contain(&mut self, path: &str, string: &str) -> &mut Self {
175+
///
176+
/// The path can use glob-style wildcards, but it must match only a single file.
177+
#[track_caller]
178+
pub fn check_file_doesnt_contain(&mut self, path_pattern: &str, string: &str) -> &mut Self {
168179
if !self.built {
169180
self.build();
170181
}
171-
let path = self.dir.join(path);
182+
let path = glob_one(&self.dir, path_pattern);
172183
let actual = read_to_string(&path);
173184
assert!(
174185
!actual.contains(string),
@@ -178,6 +189,7 @@ impl BookTest {
178189
}
179190

180191
/// Checks that the list of files at the given path matches the given value.
192+
#[track_caller]
181193
pub fn check_file_list(&mut self, path: &str, expected: impl IntoData) -> &mut Self {
182194
let mut all_paths: Vec<_> = walkdir::WalkDir::new(&self.dir.join(path))
183195
.into_iter()
@@ -499,5 +511,25 @@ fn assert(root: &Path) -> snapbox::Assert {
499511
#[track_caller]
500512
pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
501513
let path = path.as_ref();
502-
std::fs::read_to_string(path).unwrap_or_else(|e| panic!("could not read file {path:?}: {e:?}"))
514+
std::fs::read_to_string(path)
515+
.with_context(|| format!("could not read file {path:?}"))
516+
.unwrap()
517+
}
518+
519+
/// Returns the first path from the given glob pattern.
520+
pub fn glob_one<P: AsRef<Path>>(path: P, pattern: &str) -> PathBuf {
521+
let path = path.as_ref();
522+
let mut matches = glob::glob(path.join(pattern).to_str().unwrap()).unwrap();
523+
let Some(first) = matches.next() else {
524+
panic!("expected at least one file at `{path:?}` with pattern `{pattern}`, found none");
525+
};
526+
let first = first.unwrap();
527+
if let Some(next) = matches.next() {
528+
panic!(
529+
"expected only one file for pattern `{pattern}` in `{path:?}`, \
530+
found `{first:?}` and `{:?}`",
531+
next.unwrap()
532+
);
533+
}
534+
first
503535
}

0 commit comments

Comments
 (0)