Skip to content

Commit de8bada

Browse files
avargitster
authored andcommitted
wildmatch test: create & test files on disk in addition to in-memory
There has never been any full roundtrip testing of what git-ls-files and other commands that use wildmatch() actually do, rather we've been satisfied with just testing the underlying C function. Due to git-ls-files and friends having their own codepaths before they call wildmatch() there's sometimes differences in the behavior between the two. Even when we test for those (as with [1]), there was no one place where you can review how these two modes differ. Now there is. We now attempt to create a file called $haystack and match $needle against it for each pair of $needle and $haystack that we were passing to test-wildmatch. If we can't create the file we skip the test. This ensures that we can run this on all platforms and not maintain some infinitely growing whitelist of e.g. platforms that don't support certain characters in filenames. A notable exception to this is Windows, where due to the reasons explained in [2] the shellscript emulation layer might fake the creation of a file such as "*", and "test -e" for it will succeed since it just got created with some character that maps to "*", but git ls-files won't be fooled by this. Thus we need to skip creating certain filenames entirely on Windows, the list here might be overly aggressive. I don't have access to a Windows system to test this. As a result of doing these tests we can now see the cases where these two ways of testing wildmatch differ: * Creating a file called 'a[]b' and running ls-files 'a[]b' will show that file, but wildmatch("a[]b", "a[]b") will not match * wildmatch() won't match a file called \ against \, but ls-files will. * `git --glob-pathspecs ls-files 'foo**'` will match a file 'foo/bba/arr', but wildmatch won't, however pathmatch will. This seems like a bug to me, the two are otherwise equivalent as these tests show. This also reveals the case discussed in [1], since 2.16.0 '' is now an error as far as ls-files is concerned, but wildmatch() itself happily accepts it. 1. 9e4e8a6 ("pathspec: die on empty strings as pathspec", 2017-06-06) 2. nycvar.QRO.7.76.6.1801052133380.1337@wbunaarf-fpuvaqryva.tvgsbejvaqbjf.bet (https://public-inbox.org/git/?q=nycvar.QRO.7.76.6.1801052133380.1337%40wbunaarf-fpuvaqryva.tvgsbejvaqbjf.bet) Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 91061c4 commit de8bada

File tree

1 file changed

+190
-11
lines changed

1 file changed

+190
-11
lines changed

t/t3070-wildmatch.sh

Lines changed: 190 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,72 @@ test_description='wildmatch tests'
44

55
. ./test-lib.sh
66

7+
should_create_test_file() {
8+
file=$1
9+
10+
case $file in
11+
# `touch .` will succeed but obviously not do what we intend
12+
# here.
13+
".")
14+
return 1
15+
;;
16+
# We cannot create a file with an empty filename.
17+
"")
18+
return 1
19+
;;
20+
# The tests that are testing that e.g. foo//bar is matched by
21+
# foo/*/bar can't be tested on filesystems since there's no
22+
# way we're getting a double slash.
23+
*//*)
24+
return 1
25+
;;
26+
# When testing the difference between foo/bar and foo/bar/ we
27+
# can't test the latter.
28+
*/)
29+
return 1
30+
;;
31+
# On Windows, \ in paths is silently converted to /, which
32+
# would result in the "touch" below working, but the test
33+
# itself failing. See 6fd1106aa4 ("t3700: Skip a test with
34+
# backslashes in pathspec", 2009-03-13) for prior art and
35+
# details.
36+
*\\*)
37+
if ! test_have_prereq BSLASHPSPEC
38+
then
39+
return 1
40+
fi
41+
# NOTE: The ;;& bash extension is not portable, so
42+
# this test needs to be at the end of the pattern
43+
# list.
44+
#
45+
# If we want to add more conditional returns we either
46+
# need a new case statement, or turn this whole thing
47+
# into a series of "if" tests.
48+
;;
49+
esac
50+
51+
52+
# On Windows proper (i.e. not Cygwin) many file names which
53+
# under Cygwin would be emulated don't work.
54+
if test_have_prereq MINGW
55+
then
56+
case $file in
57+
" ")
58+
# Files called " " are forbidden on Windows
59+
return 1
60+
;;
61+
*\<*|*\>*|*:*|*\"*|*\|*|*\?*|*\**)
62+
# Files with various special characters aren't
63+
# allowed on Windows. Sourced from
64+
# https://stackoverflow.com/a/31976060
65+
return 1
66+
;;
67+
esac
68+
fi
69+
70+
return 0
71+
}
72+
773
match_with_function() {
874
text=$1
975
pattern=$2
@@ -26,25 +92,133 @@ match_with_function() {
2692

2793
}
2894

95+
match_with_ls_files() {
96+
text=$1
97+
pattern=$2
98+
match_expect=$3
99+
match_function=$4
100+
ls_files_args=$5
101+
102+
match_stdout_stderr_cmp="
103+
tr -d '\0' <actual.raw >actual &&
104+
>expect.err &&
105+
test_cmp expect.err actual.err &&
106+
test_cmp expect actual"
107+
108+
if test "$match_expect" = 'E'
109+
then
110+
if test -e .git/created_test_file
111+
then
112+
test_expect_success "$match_function (via ls-files): match dies on '$pattern' '$text'" "
113+
printf '%s' '$text' >expect &&
114+
test_must_fail git$ls_files_args ls-files -z -- '$pattern'
115+
"
116+
else
117+
test_expect_failure "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
118+
fi
119+
elif test "$match_expect" = 1
120+
then
121+
if test -e .git/created_test_file
122+
then
123+
test_expect_success "$match_function (via ls-files): match '$pattern' '$text'" "
124+
printf '%s' '$text' >expect &&
125+
git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
126+
$match_stdout_stderr_cmp
127+
"
128+
else
129+
test_expect_failure "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
130+
fi
131+
elif test "$match_expect" = 0
132+
then
133+
if test -e .git/created_test_file
134+
then
135+
test_expect_success "$match_function (via ls-files): no match '$pattern' '$text'" "
136+
>expect &&
137+
git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
138+
$match_stdout_stderr_cmp
139+
"
140+
else
141+
test_expect_failure "$match_function (via ls-files): no match skip '$pattern' '$text'" 'false'
142+
fi
143+
else
144+
test_expect_success "PANIC: Test framework error. Unknown matches value $match_expect" 'false'
145+
fi
146+
}
147+
29148
match() {
30-
match_glob=$1
31-
match_iglob=$2
32-
match_pathmatch=$3
33-
match_pathmatchi=$4
34-
text=$5
35-
pattern=$6
149+
if test "$#" = 6
150+
then
151+
# When test-wildmatch and git ls-files produce the same
152+
# result.
153+
match_glob=$1
154+
match_file_glob=$match_glob
155+
match_iglob=$2
156+
match_file_iglob=$match_iglob
157+
match_pathmatch=$3
158+
match_file_pathmatch=$match_pathmatch
159+
match_pathmatchi=$4
160+
match_file_pathmatchi=$match_pathmatchi
161+
text=$5
162+
pattern=$6
163+
elif test "$#" = 10
164+
then
165+
match_glob=$1
166+
match_iglob=$2
167+
match_pathmatch=$3
168+
match_pathmatchi=$4
169+
match_file_glob=$5
170+
match_file_iglob=$6
171+
match_file_pathmatch=$7
172+
match_file_pathmatchi=$8
173+
text=$9
174+
pattern=${10}
175+
fi
176+
177+
test_expect_success 'cleanup after previous file test' '
178+
if test -e .git/created_test_file
179+
then
180+
git reset &&
181+
git clean -df
182+
fi
183+
'
184+
185+
printf '%s' "$text" >.git/expected_test_file
186+
187+
test_expect_success "setup match file test for $text" '
188+
file=$(cat .git/expected_test_file) &&
189+
if should_create_test_file "$file"
190+
then
191+
dirs=${file%/*}
192+
if test "$file" != "$dirs"
193+
then
194+
mkdir -p -- "$dirs" &&
195+
touch -- "./$text"
196+
else
197+
touch -- "./$file"
198+
fi &&
199+
git add -A &&
200+
printf "%s" "$file" >.git/created_test_file
201+
elif test -e .git/created_test_file
202+
then
203+
rm .git/created_test_file
204+
fi
205+
'
36206

37207
# $1: Case sensitive glob match: test-wildmatch & ls-files
38208
match_with_function "$text" "$pattern" $match_glob "wildmatch"
209+
match_with_ls_files "$text" "$pattern" $match_file_glob "wildmatch" " --glob-pathspecs"
39210

40211
# $2: Case insensitive glob match: test-wildmatch & ls-files
41212
match_with_function "$text" "$pattern" $match_iglob "iwildmatch"
213+
match_with_ls_files "$text" "$pattern" $match_file_iglob "iwildmatch" " --glob-pathspecs --icase-pathspecs"
42214

43215
# $3: Case sensitive path match: test-wildmatch & ls-files
44216
match_with_function "$text" "$pattern" $match_pathmatch "pathmatch"
217+
match_with_ls_files "$text" "$pattern" $match_file_pathmatch "pathmatch" ""
45218

46219
# $4: Case insensitive path match: test-wildmatch & ls-files
47220
match_with_function "$text" "$pattern" $match_pathmatchi "ipathmatch"
221+
match_with_ls_files "$text" "$pattern" $match_file_pathmatchi "ipathmatch" " --icase-pathspecs"
48222
}
49223

50224
# Basic wildmatch features
@@ -113,7 +287,8 @@ match 1 1 1 1 'acrt' 'a[c-c]rt'
113287
match 0 0 0 0 ']' '[!]-]'
114288
match 1 1 1 1 'a' '[!]-]'
115289
match 0 0 0 0 '' '\'
116-
match 0 0 0 0 '\' '\'
290+
match 0 0 0 0 \
291+
1 1 1 1 '\' '\'
117292
match 0 0 0 0 'XXX/\' '*/\'
118293
match 1 1 1 1 'XXX/\' '*/\\'
119294
match 1 1 1 1 'foo' 'foo'
@@ -127,7 +302,8 @@ match 1 1 1 1 '[ab]' '[[:digit]ab]'
127302
match 1 1 1 1 '[ab]' '[\[:]ab]'
128303
match 1 1 1 1 '?a?b' '\??\?b'
129304
match 1 1 1 1 'abc' '\a\b\c'
130-
match 0 0 0 0 'foo' ''
305+
match 0 0 0 0 \
306+
E E E E 'foo' ''
131307
match 1 1 1 1 'foo/bar/baz/to' '**/t[o]'
132308

133309
# Character class tests
@@ -157,8 +333,10 @@ match 1 1 1 1 ']' '[\]]'
157333
match 0 0 0 0 '\]' '[\]]'
158334
match 0 0 0 0 '\' '[\]]'
159335
match 0 0 0 0 'ab' 'a[]b'
160-
match 0 0 0 0 'a[]b' 'a[]b'
161-
match 0 0 0 0 'ab[' 'ab['
336+
match 0 0 0 0 \
337+
1 1 1 1 'a[]b' 'a[]b'
338+
match 0 0 0 0 \
339+
1 1 1 1 'ab[' 'ab['
162340
match 0 0 0 0 'ab' '[!'
163341
match 0 0 0 0 'ab' '[-'
164342
match 1 1 1 1 '-' '[-]'
@@ -226,7 +404,8 @@ match 1 1 1 1 foo/bar 'foo/*'
226404
match 0 0 1 1 foo/bba/arr 'foo/*'
227405
match 1 1 1 1 foo/bba/arr 'foo/**'
228406
match 0 0 1 1 foo/bba/arr 'foo*'
229-
match 0 0 1 1 foo/bba/arr 'foo**'
407+
match 0 0 1 1 \
408+
1 1 1 1 foo/bba/arr 'foo**'
230409
match 0 0 1 1 foo/bba/arr 'foo/*arr'
231410
match 0 0 1 1 foo/bba/arr 'foo/**arr'
232411
match 0 0 0 0 foo/bba/arr 'foo/*z'

0 commit comments

Comments
 (0)