summaryrefslogtreecommitdiffstats
path: root/vendor/gix-glob/tests/pattern
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix-glob/tests/pattern
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-glob/tests/pattern')
-rw-r--r--vendor/gix-glob/tests/pattern/matching.rs325
-rw-r--r--vendor/gix-glob/tests/pattern/mod.rs18
2 files changed, 343 insertions, 0 deletions
diff --git a/vendor/gix-glob/tests/pattern/matching.rs b/vendor/gix-glob/tests/pattern/matching.rs
new file mode 100644
index 000000000..3e757f8d6
--- /dev/null
+++ b/vendor/gix-glob/tests/pattern/matching.rs
@@ -0,0 +1,325 @@
+use std::collections::BTreeSet;
+
+use bstr::{BStr, ByteSlice};
+use gix_glob::{pattern, pattern::Case};
+
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
+pub struct GitMatch<'a> {
+ pattern: &'a BStr,
+ value: &'a BStr,
+ /// True if git could match `value` with `pattern`
+ is_match: bool,
+}
+
+pub struct Baseline<'a> {
+ inner: bstr::Lines<'a>,
+}
+
+impl<'a> Iterator for Baseline<'a> {
+ type Item = GitMatch<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut tokens = self.inner.next()?.splitn(2, |b| *b == b' ');
+ let pattern = tokens.next().expect("pattern").as_bstr();
+ let value = tokens.next().expect("value").as_bstr().trim_start().as_bstr();
+
+ let git_match = self.inner.next()?;
+ let is_match = !git_match.starts_with(b"::\t");
+ Some(GitMatch {
+ pattern,
+ value,
+ is_match,
+ })
+ }
+}
+
+impl<'a> Baseline<'a> {
+ fn new(input: &'a [u8]) -> Self {
+ Baseline {
+ inner: input.as_bstr().lines(),
+ }
+ }
+}
+
+#[test]
+fn compare_baseline_with_ours() {
+ let dir = gix_testtools::scripted_fixture_read_only("make_baseline.sh").unwrap();
+ let (mut total_matches, mut total_correct, mut panics) = (0, 0, 0);
+ let mut mismatches = Vec::new();
+ for (input_file, expected_matches, case) in &[
+ ("git-baseline.match", true, pattern::Case::Sensitive),
+ ("git-baseline.nmatch", false, pattern::Case::Sensitive),
+ ("git-baseline.match-icase", true, pattern::Case::Fold),
+ ] {
+ let input = std::fs::read(dir.join(*input_file)).unwrap();
+ let mut seen = BTreeSet::default();
+
+ for m @ GitMatch {
+ pattern,
+ value,
+ is_match,
+ } in Baseline::new(&input)
+ {
+ total_matches += 1;
+ assert!(seen.insert(m), "duplicate match entry: {m:?}");
+ assert_eq!(
+ is_match, *expected_matches,
+ "baseline for matches must be {expected_matches} - check baseline and git version: {m:?}"
+ );
+ match std::panic::catch_unwind(|| {
+ let pattern = pat(pattern);
+ pattern.matches_repo_relative_path(value, basename_start_pos(value), None, *case)
+ }) {
+ Ok(actual_match) => {
+ if actual_match == is_match {
+ total_correct += 1;
+ } else {
+ mismatches.push((pattern.to_owned(), value.to_owned(), is_match, expected_matches));
+ }
+ }
+ Err(_) => {
+ panics += 1;
+ continue;
+ }
+ };
+ }
+ }
+
+ dbg!(mismatches);
+ assert_eq!(
+ total_correct,
+ total_matches - panics,
+ "We perfectly agree with git here"
+ );
+ assert_eq!(panics, 0);
+}
+
+#[test]
+fn non_dirs_for_must_be_dir_patterns_are_ignored() {
+ let pattern = pat("hello/");
+
+ assert!(pattern.mode.contains(pattern::Mode::MUST_BE_DIR));
+ assert_eq!(
+ pattern.text, "hello",
+ "a dir pattern doesn't actually end with the trailing slash"
+ );
+ let path = "hello";
+ assert!(
+ !pattern.matches_repo_relative_path(path, None, false.into() /* is-dir */, Case::Sensitive),
+ "non-dirs never match a dir pattern"
+ );
+ assert!(
+ pattern.matches_repo_relative_path(path, None, true.into() /* is-dir */, Case::Sensitive),
+ "dirs can match a dir pattern with the normal rules"
+ );
+}
+
+#[test]
+fn matches_of_absolute_paths_work() {
+ let pattern = "/hello/git";
+ assert!(
+ gix_glob::wildmatch(pattern.into(), pattern.into(), gix_glob::wildmatch::Mode::empty()),
+ "patterns always match themselves"
+ );
+ assert!(
+ gix_glob::wildmatch(
+ pattern.into(),
+ pattern.into(),
+ gix_glob::wildmatch::Mode::NO_MATCH_SLASH_LITERAL
+ ),
+ "patterns always match themselves, path mode doesn't change that"
+ );
+}
+
+#[test]
+fn basename_matches_from_end() {
+ let pat = &pat("foo");
+ assert!(match_file(pat, "FoO", Case::Fold));
+ assert!(!match_file(pat, "FoOo", Case::Fold));
+ assert!(!match_file(pat, "Foo", Case::Sensitive));
+ assert!(match_file(pat, "foo", Case::Sensitive));
+ assert!(!match_file(pat, "Foo", Case::Sensitive));
+ assert!(!match_file(pat, "barfoo", Case::Sensitive));
+}
+
+#[test]
+fn absolute_basename_matches_only_from_beginning() {
+ let pat = &pat("/foo");
+ assert!(match_file(pat, "FoO", Case::Fold));
+ assert!(!match_file(pat, "bar/Foo", Case::Fold));
+ assert!(match_file(pat, "foo", Case::Sensitive));
+ assert!(!match_file(pat, "Foo", Case::Sensitive));
+ assert!(!match_file(pat, "bar/foo", Case::Sensitive));
+}
+
+#[test]
+fn absolute_path_matches_only_from_beginning() {
+ let pat = &pat("/bar/foo");
+ assert!(!match_file(pat, "FoO", Case::Fold));
+ assert!(match_file(pat, "bar/Foo", Case::Fold));
+ assert!(!match_file(pat, "foo", Case::Sensitive));
+ assert!(match_file(pat, "bar/foo", Case::Sensitive));
+ assert!(!match_file(pat, "bar/Foo", Case::Sensitive));
+}
+
+#[test]
+fn absolute_path_with_recursive_glob_detects_mismatches_quickly() {
+ let pat = &pat("/bar/foo/**");
+ assert!(!match_file(pat, "FoO", Case::Fold));
+ assert!(!match_file(pat, "bar/Fooo", Case::Fold));
+ assert!(!match_file(pat, "baz/bar/Foo", Case::Fold));
+}
+
+#[test]
+fn absolute_path_with_recursive_glob_can_do_case_insensitive_prefix_search() {
+ let pat = &pat("/bar/foo/**");
+ assert!(!match_file(pat, "bar/Foo/match", Case::Sensitive));
+ assert!(match_file(pat, "bar/Foo/match", Case::Fold));
+}
+
+#[test]
+fn relative_path_does_not_match_from_end() {
+ for pattern in &["bar/foo", "/bar/foo"] {
+ let pattern = &pat(*pattern);
+ assert!(!match_file(pattern, "FoO", Case::Fold));
+ assert!(match_file(pattern, "bar/Foo", Case::Fold));
+ assert!(!match_file(pattern, "baz/bar/Foo", Case::Fold));
+ assert!(!match_file(pattern, "foo", Case::Sensitive));
+ assert!(match_file(pattern, "bar/foo", Case::Sensitive));
+ assert!(!match_file(pattern, "baz/bar/foo", Case::Sensitive));
+ assert!(!match_file(pattern, "Baz/bar/Foo", Case::Sensitive));
+ }
+}
+
+#[test]
+fn basename_glob_and_literal_is_ends_with() {
+ let pattern = &pat("*foo");
+ assert!(match_file(pattern, "FoO", Case::Fold));
+ assert!(match_file(pattern, "BarFoO", Case::Fold));
+ assert!(!match_file(pattern, "BarFoOo", Case::Fold));
+ assert!(!match_file(pattern, "Foo", Case::Sensitive));
+ assert!(!match_file(pattern, "BarFoo", Case::Sensitive));
+ assert!(match_file(pattern, "barfoo", Case::Sensitive));
+ assert!(!match_file(pattern, "barfooo", Case::Sensitive));
+
+ assert!(match_file(pattern, "bar/foo", Case::Sensitive));
+ assert!(match_file(pattern, "bar/bazfoo", Case::Sensitive));
+}
+
+#[test]
+fn special_cases_from_corpus() {
+ let pattern = &pat("foo*bar");
+ assert!(
+ !match_file(pattern, "foo/baz/bar", Case::Sensitive),
+ "asterisk does not match path separators"
+ );
+ let pattern = &pat("*some/path/to/hello.txt");
+ assert!(
+ !match_file(pattern, "a/bigger/some/path/to/hello.txt", Case::Sensitive),
+ "asterisk doesn't match path separators"
+ );
+
+ let pattern = &pat("/*foo.txt");
+ assert!(match_file(pattern, "hello-foo.txt", Case::Sensitive));
+ assert!(
+ !match_file(pattern, "hello/foo.txt", Case::Sensitive),
+ "absolute single asterisk doesn't match paths"
+ );
+}
+
+#[test]
+fn absolute_basename_glob_and_literal_is_ends_with_in_basenames() {
+ let pattern = &pat("/*foo");
+
+ assert!(match_file(pattern, "FoO", Case::Fold));
+ assert!(match_file(pattern, "BarFoO", Case::Fold));
+ assert!(!match_file(pattern, "BarFoOo", Case::Fold));
+ assert!(!match_file(pattern, "Foo", Case::Sensitive));
+ assert!(!match_file(pattern, "BarFoo", Case::Sensitive));
+ assert!(match_file(pattern, "barfoo", Case::Sensitive));
+ assert!(!match_file(pattern, "barfooo", Case::Sensitive));
+}
+
+#[test]
+fn absolute_basename_glob_and_literal_is_glob_in_paths() {
+ let pattern = &pat("/*foo");
+
+ assert!(!match_file(pattern, "bar/foo", Case::Sensitive), "* does not match /");
+ assert!(!match_file(pattern, "bar/bazfoo", Case::Sensitive));
+}
+
+#[test]
+fn negated_patterns_are_handled_by_caller() {
+ let pattern = &pat("!foo");
+ assert!(
+ match_file(pattern, "foo", Case::Sensitive),
+ "negative patterns match like any other"
+ );
+ assert!(
+ pattern.is_negative(),
+ "the caller checks for the negative flag and acts accordingly"
+ );
+}
+#[test]
+fn names_do_not_automatically_match_entire_directories() {
+ // this feature is implemented with the directory stack.
+ let pattern = &pat("foo");
+ assert!(!match_file(pattern, "foobar", Case::Sensitive));
+ assert!(!match_file(pattern, "foo/bar", Case::Sensitive));
+ assert!(!match_file(pattern, "foo/bar/baz", Case::Sensitive));
+}
+
+#[test]
+fn directory_patterns_do_not_match_files_within_a_directory_as_well_like_slash_star_star() {
+ // this feature is implemented with the directory stack, which excludes entire directories
+ let pattern = &pat("dir/");
+ assert!(!match_path(pattern, "dir/file", None, Case::Sensitive));
+ assert!(!match_path(pattern, "base/dir/file", None, Case::Sensitive));
+ assert!(!match_path(pattern, "base/ndir/file", None, Case::Sensitive));
+ assert!(!match_path(pattern, "Dir/File", None, Case::Fold));
+ assert!(!match_path(pattern, "Base/Dir/File", None, Case::Fold));
+ assert!(!match_path(pattern, "dir2/file", None, Case::Sensitive));
+
+ let pattern = &pat("dir/sub-dir/");
+ assert!(!match_path(pattern, "dir/sub-dir/file", None, Case::Sensitive));
+ assert!(!match_path(pattern, "dir/Sub-dir/File", None, Case::Fold));
+ assert!(!match_path(pattern, "dir/Sub-dir2/File", None, Case::Fold));
+}
+
+#[test]
+fn single_paths_match_anywhere() {
+ let pattern = &pat("target");
+ assert!(match_file(pattern, "dir/target", Case::Sensitive));
+ assert!(!match_file(pattern, "dir/atarget", Case::Sensitive));
+ assert!(!match_file(pattern, "dir/targeta", Case::Sensitive));
+ assert!(match_path(pattern, "dir/target", Some(true), Case::Sensitive));
+
+ let pattern = &pat("target/");
+ assert!(!match_file(pattern, "dir/target", Case::Sensitive));
+ assert!(
+ !match_path(pattern, "dir/target", None, Case::Sensitive),
+ "it assumes unknown to not be a directory"
+ );
+ assert!(match_path(pattern, "dir/target", Some(true), Case::Sensitive));
+ assert!(
+ !match_path(pattern, "dir/target/", Some(true), Case::Sensitive),
+ "we need sanitized paths that don't have trailing slashes"
+ );
+}
+
+fn pat<'a>(pattern: impl Into<&'a BStr>) -> gix_glob::Pattern {
+ gix_glob::Pattern::from_bytes(pattern.into()).expect("parsing works")
+}
+
+fn match_file<'a>(pattern: &gix_glob::Pattern, path: impl Into<&'a BStr>, case: Case) -> bool {
+ match_path(pattern, path, false.into(), case)
+}
+
+fn match_path<'a>(pattern: &gix_glob::Pattern, path: impl Into<&'a BStr>, is_dir: Option<bool>, case: Case) -> bool {
+ let path = path.into();
+ pattern.matches_repo_relative_path(path, basename_start_pos(path), is_dir, case)
+}
+
+fn basename_start_pos(value: &BStr) -> Option<usize> {
+ value.rfind_byte(b'/').map(|pos| pos + 1)
+}
diff --git a/vendor/gix-glob/tests/pattern/mod.rs b/vendor/gix-glob/tests/pattern/mod.rs
new file mode 100644
index 000000000..ca5d8cbad
--- /dev/null
+++ b/vendor/gix-glob/tests/pattern/mod.rs
@@ -0,0 +1,18 @@
+use gix_glob::{pattern::Mode, Pattern};
+
+#[test]
+fn display() {
+ fn pat(text: &str, mode: Mode) -> String {
+ Pattern {
+ text: text.into(),
+ mode,
+ first_wildcard_pos: None,
+ }
+ .to_string()
+ }
+ assert_eq!(pat("a", Mode::ABSOLUTE), "/a");
+ assert_eq!(pat("a", Mode::MUST_BE_DIR), "a/");
+ assert_eq!(pat("a", Mode::NEGATIVE), "!a");
+ assert_eq!(pat("a", Mode::ABSOLUTE | Mode::NEGATIVE | Mode::MUST_BE_DIR), "!/a/");
+}
+mod matching;