diff --git a/src/glob.rs b/src/glob.rs index e9efa657..a8685d51 100644 --- a/src/glob.rs +++ b/src/glob.rs @@ -1,5 +1,5 @@ use std::env; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Mutex; use globset::{GlobBuilder, GlobMatcher}; @@ -55,6 +55,8 @@ pub fn glob_exec(base: &Path, pattern: &str, mut f: F) { fail_fast: std::env::var("INSTA_GLOB_FAIL_FAST").as_deref() == Ok("1"), }); + // step 1: collect all matching files + let mut matching_files = vec![]; for file in walker { let file = file.unwrap(); let path = file.path(); @@ -71,9 +73,26 @@ pub fn glob_exec(base: &Path, pattern: &str, mut f: F) { continue; } + matching_files.push(path.to_path_buf()); + } + + // step 2: sort, determine common prefix and run assertions + matching_files.sort(); + let common_prefix = find_common_prefix(&matching_files); + for path in &matching_files { settings.set_input_file(path); - settings.set_snapshot_suffix(path.file_name().unwrap().to_str().unwrap()); + // if there is a common prefix, use that stirp down the input file. That way we + // can ensure that a glob like inputs/*/*.txt with a/file.txt and b/file.txt + // does not create two identical snapshot suffixes. Instead of file.txt for both + // it would end up as a/file.txt and b/file.txt. + let snapshot_suffix = if let Some(prefix) = common_prefix { + path.strip_prefix(prefix).unwrap().as_os_str() + } else { + path.file_name().unwrap() + }; + + settings.set_snapshot_suffix(snapshot_suffix.to_str().unwrap()); settings.bind(|| { f(path); }); @@ -104,3 +123,23 @@ pub fn glob_exec(base: &Path, pattern: &str, mut f: F) { ); } } + +fn find_common_prefix(sorted_paths: &[PathBuf]) -> Option<&Path> { + let first = sorted_paths.first()?; + let last = sorted_paths.last()?; + let prefix_len = first + .components() + .zip(last.components()) + .take_while(|(a, b)| a == b) + .count(); + + if prefix_len == 0 { + None + } else { + let mut prefix = first.components(); + for _ in 0..first.components().count() - prefix_len { + prefix.next_back(); + } + Some(prefix.as_path()) + } +} diff --git a/tests/inputs-nested/a/file.txt b/tests/inputs-nested/a/file.txt new file mode 100644 index 00000000..0496cb62 --- /dev/null +++ b/tests/inputs-nested/a/file.txt @@ -0,0 +1 @@ +Hello A diff --git a/tests/inputs-nested/b/file.txt b/tests/inputs-nested/b/file.txt new file mode 100644 index 00000000..a3eee9ba --- /dev/null +++ b/tests/inputs-nested/b/file.txt @@ -0,0 +1 @@ +Hello B diff --git a/tests/snapshots/test_glob__basic_globbing_nested@a__file.txt.snap b/tests/snapshots/test_glob__basic_globbing_nested@a__file.txt.snap new file mode 100644 index 00000000..254b4c60 --- /dev/null +++ b/tests/snapshots/test_glob__basic_globbing_nested@a__file.txt.snap @@ -0,0 +1,7 @@ +--- +source: tests/test_glob.rs +expression: "&contents" +input_file: tests/inputs-nested/a/file.txt +--- +Hello A + diff --git a/tests/snapshots/test_glob__basic_globbing_nested@b__file.txt.snap b/tests/snapshots/test_glob__basic_globbing_nested@b__file.txt.snap new file mode 100644 index 00000000..e6c38641 --- /dev/null +++ b/tests/snapshots/test_glob__basic_globbing_nested@b__file.txt.snap @@ -0,0 +1,7 @@ +--- +source: tests/test_glob.rs +expression: "&contents" +input_file: tests/inputs-nested/b/file.txt +--- +Hello B + diff --git a/tests/test_glob.rs b/tests/test_glob.rs index 08c483f1..512601e5 100644 --- a/tests/test_glob.rs +++ b/tests/test_glob.rs @@ -8,6 +8,14 @@ fn test_basic_globbing() { }); } +#[test] +fn test_basic_globbing_nested() { + insta::glob!("inputs-nested/*/*.txt", |path| { + let contents = std::fs::read_to_string(path).unwrap(); + insta::assert_snapshot!(&contents); + }); +} + #[test] fn test_globs_follow_links() { insta::glob!("link-to-inputs/*.txt", |path| {