Skip to content

Commit 4f67be4

Browse files
committed
add another test to learn how / behaves, and * + excludes (#1458)
This is quite typical in the wild where there ignore files are used as include lists, instead of exclude-lists.
1 parent 1267712 commit 4f67be4

File tree

2 files changed

+143
-64
lines changed

2 files changed

+143
-64
lines changed

gix-ignore/tests/fixtures/make_global_and_external_and_dir_ignores.sh

+68-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ a/b/*
1515
z/x
1616
EOF
1717

18-
mkdir repo;
18+
git init -q repo;
1919
(cd repo
20-
git init -q
2120
git config core.excludesFile ../user.exclude
2221

2322
cat <<EOF >.git/info/exclude
@@ -93,3 +92,70 @@ E/f
9392
E/F
9493
EOF
9594
)
95+
96+
git init slash-and-excludes
97+
(cd slash-and-excludes
98+
cat <<EOF >.gitignore
99+
# a lone slash does nothing
100+
/
101+
# a file that was never ignored to begin
102+
!file
103+
EOF
104+
105+
git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
106+
file
107+
a-file-not-mentioned-in-gitignore
108+
EOF
109+
)
110+
111+
git init slash-and-excludes-in-subdir
112+
(cd slash-and-excludes-in-subdir
113+
mkdir sub
114+
(cd sub
115+
cat <<EOF >.gitignore
116+
# a lone slash does nothing
117+
/
118+
# a file that was never ignored to begin
119+
!file
120+
EOF
121+
)
122+
git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
123+
sub/file
124+
sub/a-file-not-mentioned-in-gitignore
125+
a-file-not-mentioned-in-gitignore
126+
EOF
127+
)
128+
129+
git init star-and-excludes
130+
(cd star-and-excludes
131+
cat <<EOF >.gitignore
132+
# everything is excluded by default
133+
*
134+
# And negations are used as an allow-list
135+
!file
136+
EOF
137+
138+
git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
139+
file
140+
a-file-not-mentioned-in-gitignore
141+
EOF
142+
)
143+
144+
git init star-and-excludes-in-subdir
145+
(cd star-and-excludes-in-subdir
146+
mkdir sub
147+
(cd sub
148+
cat <<EOF >.gitignore
149+
# everything is excluded by default
150+
*
151+
# And negations are used as an allow-list
152+
!file
153+
EOF
154+
)
155+
156+
git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
157+
sub/file
158+
sub/a-file-not-mentioned-in-gitignore
159+
a-file-not-mentioned-in-gitignore
160+
EOF
161+
)

gix-ignore/tests/search/mod.rs

+75-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::io::Read;
2-
31
use bstr::{BStr, ByteSlice};
42
use gix_glob::pattern::Case;
53
use gix_ignore::search::Match;
@@ -31,69 +29,84 @@ impl<'a> Iterator for Expectations<'a> {
3129

3230
#[test]
3331
fn baseline_from_git_dir() -> crate::Result {
34-
let case = if gix_fs::Capabilities::probe("../.git".as_ref()).ignore_case {
35-
Case::Fold
36-
} else {
37-
Case::Sensitive
38-
};
39-
let dir = gix_testtools::scripted_fixture_read_only("make_global_and_external_and_dir_ignores.sh")?;
40-
let repo_dir = dir.join("repo");
41-
let git_dir = repo_dir.join(".git");
42-
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
43-
let mut buf = Vec::new();
44-
let mut group = gix_ignore::Search::from_git_dir(&git_dir, Some(dir.join("user.exclude")), &mut buf)?;
32+
for repo_name in [
33+
"repo",
34+
"slash-and-excludes",
35+
"star-and-excludes-in-subdir",
36+
"slash-and-excludes-in-subdir",
37+
] {
38+
let case = if gix_fs::Capabilities::probe("../.git".as_ref()).ignore_case {
39+
Case::Fold
40+
} else {
41+
Case::Sensitive
42+
};
43+
let dir = gix_testtools::scripted_fixture_read_only("make_global_and_external_and_dir_ignores.sh")?;
44+
let repo_dir = dir.join(repo_name);
45+
let git_dir = repo_dir.join(".git");
46+
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
47+
let mut buf = Vec::new();
48+
let user_exclude = dir.join("user.exclude");
49+
let mut group =
50+
gix_ignore::Search::from_git_dir(&git_dir, user_exclude.is_file().then_some(user_exclude), &mut buf)?;
4551

46-
assert!(
47-
!gix_glob::search::add_patterns_file(&mut group.patterns, "not-a-file".into(), false, None, &mut buf)?,
48-
"missing files are no problem and cause a negative response"
49-
);
50-
assert!(
51-
gix_glob::search::add_patterns_file(
52-
&mut group.patterns,
53-
repo_dir.join(".gitignore"),
54-
true,
55-
repo_dir.as_path().into(),
56-
&mut buf
57-
)?,
58-
"existing files return true"
59-
);
52+
assert!(
53+
!gix_glob::search::add_patterns_file(&mut group.patterns, "not-a-file".into(), false, None, &mut buf)?,
54+
"missing files are no problem and cause a negative response"
55+
);
56+
let mut ignore_file = repo_dir.join(".gitignore");
57+
if !ignore_file.is_file() {
58+
ignore_file.pop();
59+
ignore_file.push("sub/.gitignore");
60+
}
61+
assert!(
62+
gix_glob::search::add_patterns_file(
63+
&mut group.patterns,
64+
ignore_file,
65+
true,
66+
repo_dir.as_path().into(),
67+
&mut buf
68+
)?,
69+
"existing files return true"
70+
);
6071

61-
buf.clear();
62-
let ignore_file = repo_dir.join("dir-with-ignore").join(".gitignore");
63-
std::fs::File::open(&ignore_file)?.read_to_end(&mut buf)?;
64-
group.add_patterns_buffer(&buf, ignore_file, repo_dir.as_path().into());
72+
let ignore_file = repo_dir.join("dir-with-ignore").join(".gitignore");
73+
if ignore_file.is_file() {
74+
let buf = std::fs::read(&ignore_file)?;
75+
group.add_patterns_buffer(&buf, ignore_file, repo_dir.as_path().into());
76+
}
6577

66-
for (path, source_and_line) in (Expectations {
67-
lines: baseline.lines(),
68-
}) {
69-
let actual = group.pattern_matching_relative_path(
70-
path,
71-
repo_dir
72-
.join(path.to_str_lossy().as_ref())
73-
.metadata()
74-
.ok()
75-
.map(|m| m.is_dir()),
76-
case,
77-
);
78-
match (actual, source_and_line) {
79-
(
80-
Some(Match {
81-
sequence_number,
82-
pattern: _,
83-
source,
84-
kind: gix_ignore::Kind::Expendable,
85-
}),
86-
Some((expected_source, line, _expected_pattern)),
87-
) => {
88-
assert_eq!(sequence_number, line, "our counting should match the one used in git");
89-
assert_eq!(
90-
source.map(|p| p.canonicalize().unwrap()),
91-
Some(repo_dir.join(expected_source.to_str_lossy().as_ref()).canonicalize()?)
92-
);
93-
}
94-
(None, None) => {}
95-
(actual, expected) => {
96-
panic!("{case:?}: actual {actual:?} should match {expected:?} with path '{path}'")
78+
for (path, source_and_line) in (Expectations {
79+
lines: baseline.lines(),
80+
}) {
81+
let actual = group.pattern_matching_relative_path(
82+
path,
83+
repo_dir
84+
.join(path.to_str_lossy().as_ref())
85+
.metadata()
86+
.ok()
87+
.map(|m| m.is_dir()),
88+
case,
89+
);
90+
match (actual, source_and_line) {
91+
(
92+
Some(Match {
93+
sequence_number,
94+
pattern: _,
95+
source,
96+
kind: gix_ignore::Kind::Expendable,
97+
}),
98+
Some((expected_source, line, _expected_pattern)),
99+
) => {
100+
assert_eq!(sequence_number, line, "our counting should match the one used in git");
101+
assert_eq!(
102+
source.map(|p| p.canonicalize().unwrap()),
103+
Some(repo_dir.join(expected_source.to_str_lossy().as_ref()).canonicalize()?)
104+
);
105+
}
106+
(None, None) => {}
107+
(actual, expected) => {
108+
panic!("{repo_name}: {case:?}: actual {actual:?} should match {expected:?} with path '{path}'")
109+
}
97110
}
98111
}
99112
}

0 commit comments

Comments
 (0)