diff --git a/src/glob.rs b/src/glob.rs index dd0eb9ce..c7b17230 100644 --- a/src/glob.rs +++ b/src/glob.rs @@ -39,6 +39,15 @@ lazy_static::lazy_static! { } pub fn glob_exec(manifest_dir: &str, base: &Path, pattern: &str, mut f: F) { + // If settings.allow_empty_glob() == true and `base` doesn't exist, skip + // everything. This is necessary as `base` is user-controlled via `glob!/3` + // and may not exist. + let mut settings = Settings::clone_current(); + + if settings.allow_empty_glob() && !base.exists() { + return; + } + let glob = GlobBuilder::new(pattern) .case_insensitive(true) .literal_separator(true) @@ -48,7 +57,6 @@ pub fn glob_exec(manifest_dir: &str, base: &Path, pattern: &str let walker = WalkDir::new(base).follow_links(true); let mut glob_found_matches = false; - let mut settings = Settings::clone_current(); GLOB_STACK.lock().unwrap().push(GlobCollector { failed: 0, diff --git a/src/macros.rs b/src/macros.rs index 6d0c7593..70dd9749 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -538,19 +538,41 @@ macro_rules! with_settings { /// are deferred until the end of of it. In other words this means that each snapshot /// assertion within the `glob!` block are reported. It can be disabled by setting /// `INSTA_GLOB_FAIL_FAST` environment variable to `1`. +/// +/// A three-argument version of this macro allows specifying a base directory +/// for the glob to start in. This allows globbing in arbitrary directories, +/// including parent directories: +/// +/// ``` +/// # use insta::{assert_snapshot, glob, Settings}; +/// # let mut settings = Settings::clone_current(); +/// # settings.set_allow_empty_glob(true); +/// # let _dropguard = settings.bind_to_scope(); +/// use std::fs; +/// +/// glob!("../test_data", "inputs/*.txt", |path| { +/// let input = fs::read_to_string(path).unwrap(); +/// assert_snapshot!(input.to_uppercase()); +/// }); +/// ``` #[cfg(feature = "glob")] #[cfg_attr(docsrs, doc(cfg(feature = "glob")))] #[macro_export] macro_rules! glob { - ($glob:expr, $closure:expr) => {{ + ($base_path:expr, $glob:expr, $closure:expr) => {{ + use std::path::Path; let base = $crate::_macro_support::get_cargo_workspace(env!("CARGO_MANIFEST_DIR")) - .join(file!()) - .parent() - .unwrap() + .join(Path::new(file!()).parent().unwrap()) + .join($base_path) .to_path_buf(); + // we try to canonicalize but on some platforms (eg: wasm) that might not work, so // we instead silently fall back. let base = base.canonicalize().unwrap_or_else(|_| base); $crate::_macro_support::glob_exec(env!("CARGO_MANIFEST_DIR"), &base, $glob, $closure); }}; + + ($glob:expr, $closure:expr) => {{ + insta::glob!(".", $glob, $closure) + }}; } diff --git a/tests/glob_submodule/mod.rs b/tests/glob_submodule/mod.rs new file mode 100644 index 00000000..984ac362 --- /dev/null +++ b/tests/glob_submodule/mod.rs @@ -0,0 +1,53 @@ +#![cfg(feature = "glob")] + +#[test] +fn test_basic_globbing_parent_dir() { + insta::glob!("../inputs", "*.txt", |path| { + let contents = std::fs::read_to_string(path).unwrap(); + insta::assert_json_snapshot!(&contents); + }); +} + +#[test] +fn test_basic_globbing_nested_parent_dir_base_path() { + insta::glob!("../inputs-nested", "*/*.txt", |path| { + let contents = std::fs::read_to_string(path).unwrap(); + insta::assert_snapshot!(&contents); + }); +} + +#[test] +fn test_basic_globbing_nested_parent_glob() { + 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_parent_dir_base_path() { + insta::glob!("../link-to-inputs", "*.txt", |path| { + let contents = std::fs::read_to_string(path).unwrap(); + insta::assert_json_snapshot!(&contents); + }); +} + +#[test] +fn test_globs_follow_links_parent_dir_glob() { + insta::glob!("..", "link-to-inputs/*.txt", |path| { + let contents = std::fs::read_to_string(path).unwrap(); + insta::assert_json_snapshot!(&contents); + }); +} + +#[test] +fn test_basic_globbing_absolute_dir() { + insta::glob!( + concat!(env!("CARGO_MANIFEST_DIR"), "/tests/inputs"), + "*.txt", + |path| { + let contents = std::fs::read_to_string(path).unwrap(); + insta::assert_json_snapshot!(&contents); + } + ); +} diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_absolute_dir@goodbye.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_absolute_dir@goodbye.txt.snap new file mode 100644 index 00000000..a7d917c8 --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_absolute_dir@goodbye.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/goodbye.txt +--- +"Contents of goodbye" diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_absolute_dir@hello.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_absolute_dir@hello.txt.snap new file mode 100644 index 00000000..f4c2da6e --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_absolute_dir@hello.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/hello.txt +--- +"Contents of hello" diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_dir_base_path@a__file.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_dir_base_path@a__file.txt.snap new file mode 100644 index 00000000..43e4ce8f --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_dir_base_path@a__file.txt.snap @@ -0,0 +1,7 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs-nested/a/file.txt +--- +Hello A + diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_dir_base_path@b__file.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_dir_base_path@b__file.txt.snap new file mode 100644 index 00000000..9208fa1f --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_dir_base_path@b__file.txt.snap @@ -0,0 +1,7 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs-nested/b/file.txt +--- +Hello B + diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_glob@a__file.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_glob@a__file.txt.snap new file mode 100644 index 00000000..43e4ce8f --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_glob@a__file.txt.snap @@ -0,0 +1,7 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs-nested/a/file.txt +--- +Hello A + diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_glob@b__file.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_glob@b__file.txt.snap new file mode 100644 index 00000000..9208fa1f --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_nested_parent_glob@b__file.txt.snap @@ -0,0 +1,7 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs-nested/b/file.txt +--- +Hello B + diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_parent_dir@goodbye.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_parent_dir@goodbye.txt.snap new file mode 100644 index 00000000..a7d917c8 --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_parent_dir@goodbye.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/goodbye.txt +--- +"Contents of goodbye" diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_parent_dir@hello.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_parent_dir@hello.txt.snap new file mode 100644 index 00000000..f4c2da6e --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__basic_globbing_parent_dir@hello.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/hello.txt +--- +"Contents of hello" diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_base_path@goodbye.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_base_path@goodbye.txt.snap new file mode 100644 index 00000000..a7d917c8 --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_base_path@goodbye.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/goodbye.txt +--- +"Contents of goodbye" diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_base_path@hello.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_base_path@hello.txt.snap new file mode 100644 index 00000000..f4c2da6e --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_base_path@hello.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/hello.txt +--- +"Contents of hello" diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_glob@goodbye.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_glob@goodbye.txt.snap new file mode 100644 index 00000000..a7d917c8 --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_glob@goodbye.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/goodbye.txt +--- +"Contents of goodbye" diff --git a/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_glob@hello.txt.snap b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_glob@hello.txt.snap new file mode 100644 index 00000000..f4c2da6e --- /dev/null +++ b/tests/glob_submodule/snapshots/test_glob__glob_submodule__globs_follow_links_parent_dir_glob@hello.txt.snap @@ -0,0 +1,6 @@ +--- +source: tests/glob_submodule/mod.rs +expression: "&contents" +input_file: tests/inputs/hello.txt +--- +"Contents of hello" diff --git a/tests/test_glob.rs b/tests/test_glob.rs index 512601e5..2585a99a 100644 --- a/tests/test_glob.rs +++ b/tests/test_glob.rs @@ -1,5 +1,7 @@ #![cfg(feature = "glob")] +mod glob_submodule; + #[test] fn test_basic_globbing() { insta::glob!("inputs/*.txt", |path| {