7af93ba928ece85265509537b521764827194955
1#!/bin/sh
2
3test_description=check-ignore
4
5. ./test-lib.sh
6
7init_vars () {
8 global_excludes="$(pwd)/global-excludes"
9}
10
11enable_global_excludes () {
12 init_vars &&
13 git config core.excludesfile "$global_excludes"
14}
15
16expect_in () {
17 dest="$HOME/expected-$1" text="$2"
18 if test -z "$text"
19 then
20 >"$dest" # avoid newline
21 else
22 echo "$text" >"$dest"
23 fi
24}
25
26expect () {
27 expect_in stdout "$1"
28}
29
30expect_from_stdin () {
31 cat >"$HOME/expected-stdout"
32}
33
34test_stderr () {
35 expected="$1"
36 expect_in stderr "$1" &&
37 test_cmp "$HOME/expected-stderr" "$HOME/stderr"
38}
39
40stderr_contains () {
41 regexp="$1"
42 if grep "$regexp" "$HOME/stderr"
43 then
44 return 0
45 else
46 echo "didn't find /$regexp/ in $HOME/stderr"
47 cat "$HOME/stderr"
48 return 1
49 fi
50}
51
52stderr_empty_on_success () {
53 expect_code="$1"
54 if test $expect_code = 0
55 then
56 test_stderr ""
57 else
58 # If we expect failure then stderr might or might not be empty
59 # due to --quiet - the caller can check its contents
60 return 0
61 fi
62}
63
64test_check_ignore () {
65 args="$1" expect_code="${2:-0}" global_args="$3"
66
67 init_vars &&
68 rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
69 echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
70 >"$HOME/cmd" &&
71 echo "$expect_code" >"$HOME/expected-exit-code" &&
72 test_expect_code "$expect_code" \
73 git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
74 >"$HOME/stdout" 2>"$HOME/stderr" &&
75 test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
76 stderr_empty_on_success "$expect_code"
77}
78
79# Runs the same code with 4 different levels of output verbosity:
80#
81# 1. with -q / --quiet
82# 2. with default verbosity
83# 3. with -v / --verbose
84# 4. with -v / --verbose, *and* -n / --non-matching
85#
86# expecting success each time. Takes advantage of the fact that
87# check-ignore --verbose output is the same as normal output except
88# for the extra first column.
89#
90# Arguments:
91# - (optional) prereqs for this test, e.g. 'SYMLINKS'
92# - test name
93# - output to expect from the fourth verbosity mode (the output
94# from the other verbosity modes is automatically inferred
95# from this value)
96# - code to run (should invoke test_check_ignore)
97test_expect_success_multi () {
98 prereq=
99 if test $# -eq 4
100 then
101 prereq=$1
102 shift
103 fi
104 testname="$1" expect_all="$2" code="$3"
105
106 expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
107 expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
108
109 test_expect_success $prereq "$testname" '
110 expect "$expect" &&
111 eval "$code"
112 '
113
114 # --quiet is only valid when a single pattern is passed
115 if test $( echo "$expect_all" | wc -l ) = 1
116 then
117 for quiet_opt in '-q' '--quiet'
118 do
119 test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
120 expect '' &&
121 $code
122 "
123 done
124 quiet_opt=
125 fi
126
127 for verbose_opt in '-v' '--verbose'
128 do
129 for non_matching_opt in '' ' -n' ' --non-matching'
130 do
131 if test -n "$non_matching_opt"
132 then
133 my_expect="$expect_all"
134 else
135 my_expect="$expect_verbose"
136 fi
137
138 test_code="
139 expect '$my_expect' &&
140 $code
141 "
142 opts="$verbose_opt$non_matching_opt"
143 test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
144 done
145 done
146 verbose_opt=
147 non_matching_opt=
148}
149
150test_expect_success 'setup' '
151 init_vars &&
152 mkdir -p a/b/ignored-dir a/submodule b &&
153 if test_have_prereq SYMLINKS
154 then
155 ln -s b a/symlink
156 fi &&
157 (
158 cd a/submodule &&
159 git init &&
160 echo a >a &&
161 git add a &&
162 git commit -m"commit in submodule"
163 ) &&
164 git add a/submodule &&
165 cat <<-\EOF >.gitignore &&
166 one
167 ignored-*
168 top-level-dir/
169 EOF
170 for dir in . a
171 do
172 : >$dir/not-ignored &&
173 : >$dir/ignored-and-untracked &&
174 : >$dir/ignored-but-in-index
175 done &&
176 git add -f ignored-but-in-index a/ignored-but-in-index &&
177 cat <<-\EOF >a/.gitignore &&
178 two*
179 *three
180 EOF
181 cat <<-\EOF >a/b/.gitignore &&
182 four
183 five
184 # this comment should affect the line numbers
185 six
186 ignored-dir/
187 # and so should this blank line:
188
189 !on*
190 !two
191 EOF
192 echo "seven" >a/b/ignored-dir/.gitignore &&
193 test -n "$HOME" &&
194 cat <<-\EOF >"$global_excludes" &&
195 globalone
196 !globaltwo
197 globalthree
198 EOF
199 cat <<-\EOF >>.git/info/exclude
200 per-repo
201 EOF
202'
203
204############################################################################
205#
206# test invalid inputs
207
208test_expect_success_multi '. corner-case' ':: .' '
209 test_check_ignore . 1
210'
211
212test_expect_success_multi 'empty command line' '' '
213 test_check_ignore "" 128 &&
214 stderr_contains "fatal: no path specified"
215'
216
217test_expect_success_multi '--stdin with empty STDIN' '' '
218 test_check_ignore "--stdin" 1 </dev/null &&
219 if test -n "$quiet_opt"; then
220 test_stderr ""
221 else
222 test_stderr "no pathspec given."
223 fi
224'
225
226test_expect_success '-q with multiple args' '
227 expect "" &&
228 test_check_ignore "-q one two" 128 &&
229 stderr_contains "fatal: --quiet is only valid with a single pathname"
230'
231
232test_expect_success '--quiet with multiple args' '
233 expect "" &&
234 test_check_ignore "--quiet one two" 128 &&
235 stderr_contains "fatal: --quiet is only valid with a single pathname"
236'
237
238for verbose_opt in '-v' '--verbose'
239do
240 for quiet_opt in '-q' '--quiet'
241 do
242 test_expect_success "$quiet_opt $verbose_opt" "
243 expect '' &&
244 test_check_ignore '$quiet_opt $verbose_opt foo' 128 &&
245 stderr_contains 'fatal: cannot have both --quiet and --verbose'
246 "
247 done
248done
249
250test_expect_success '--quiet with multiple args' '
251 expect "" &&
252 test_check_ignore "--quiet one two" 128 &&
253 stderr_contains "fatal: --quiet is only valid with a single pathname"
254'
255
256test_expect_success_multi 'erroneous use of --' '' '
257 test_check_ignore "--" 128 &&
258 stderr_contains "fatal: no path specified"
259'
260
261test_expect_success_multi '--stdin with superfluous arg' '' '
262 test_check_ignore "--stdin foo" 128 &&
263 stderr_contains "fatal: cannot specify pathnames with --stdin"
264'
265
266test_expect_success_multi '--stdin -z with superfluous arg' '' '
267 test_check_ignore "--stdin -z foo" 128 &&
268 stderr_contains "fatal: cannot specify pathnames with --stdin"
269'
270
271test_expect_success_multi '-z without --stdin' '' '
272 test_check_ignore "-z" 128 &&
273 stderr_contains "fatal: -z only makes sense with --stdin"
274'
275
276test_expect_success_multi '-z without --stdin and superfluous arg' '' '
277 test_check_ignore "-z foo" 128 &&
278 stderr_contains "fatal: -z only makes sense with --stdin"
279'
280
281test_expect_success_multi 'needs work tree' '' '
282 (
283 cd .git &&
284 test_check_ignore "foo" 128
285 ) &&
286 stderr_contains "fatal: This operation must be run in a work tree"
287'
288
289############################################################################
290#
291# test standard ignores
292
293# First make sure that the presence of a file in the working tree
294# does not impact results, but that the presence of a file in the
295# index does.
296
297for subdir in '' 'a/'
298do
299 if test -z "$subdir"
300 then
301 where="at top-level"
302 else
303 where="in subdir $subdir"
304 fi
305
306 test_expect_success_multi "non-existent file $where not ignored" \
307 ":: ${subdir}non-existent" \
308 "test_check_ignore '${subdir}non-existent' 1"
309
310 test_expect_success_multi "non-existent file $where ignored" \
311 ".gitignore:1:one ${subdir}one" \
312 "test_check_ignore '${subdir}one'"
313
314 test_expect_success_multi "existing untracked file $where not ignored" \
315 ":: ${subdir}not-ignored" \
316 "test_check_ignore '${subdir}not-ignored' 1"
317
318 test_expect_success_multi "existing tracked file $where not ignored" \
319 ":: ${subdir}ignored-but-in-index" \
320 "test_check_ignore '${subdir}ignored-but-in-index' 1"
321
322 test_expect_success_multi "existing untracked file $where ignored" \
323 ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
324 "test_check_ignore '${subdir}ignored-and-untracked'"
325
326 test_expect_success_multi "mix of file types $where" \
327":: ${subdir}non-existent
328.gitignore:1:one ${subdir}one
329:: ${subdir}not-ignored
330:: ${subdir}ignored-but-in-index
331.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
332 "test_check_ignore '
333 ${subdir}non-existent
334 ${subdir}one
335 ${subdir}not-ignored
336 ${subdir}ignored-but-in-index
337 ${subdir}ignored-and-untracked'
338 "
339done
340
341# Having established the above, from now on we mostly test against
342# files which do not exist in the working tree or index.
343
344test_expect_success 'sub-directory local ignore' '
345 expect "a/3-three" &&
346 test_check_ignore "a/3-three a/three-not-this-one"
347'
348
349test_expect_success 'sub-directory local ignore with --verbose' '
350 expect "a/.gitignore:2:*three a/3-three" &&
351 test_check_ignore "--verbose a/3-three a/three-not-this-one"
352'
353
354test_expect_success 'local ignore inside a sub-directory' '
355 expect "3-three" &&
356 (
357 cd a &&
358 test_check_ignore "3-three three-not-this-one"
359 )
360'
361test_expect_success 'local ignore inside a sub-directory with --verbose' '
362 expect "a/.gitignore:2:*three 3-three" &&
363 (
364 cd a &&
365 test_check_ignore "--verbose 3-three three-not-this-one"
366 )
367'
368
369test_expect_success_multi 'nested include' \
370 'a/b/.gitignore:8:!on* a/b/one' '
371 test_check_ignore "a/b/one"
372'
373
374############################################################################
375#
376# test ignored sub-directories
377
378test_expect_success_multi 'ignored sub-directory' \
379 'a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir' '
380 test_check_ignore "a/b/ignored-dir"
381'
382
383test_expect_success 'multiple files inside ignored sub-directory' '
384 expect_from_stdin <<-\EOF &&
385 a/b/ignored-dir/foo
386 a/b/ignored-dir/twoooo
387 a/b/ignored-dir/seven
388 EOF
389 test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
390'
391
392test_expect_success 'multiple files inside ignored sub-directory with -v' '
393 expect_from_stdin <<-\EOF &&
394 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/foo
395 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/twoooo
396 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/seven
397 EOF
398 test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
399'
400
401test_expect_success 'cd to ignored sub-directory' '
402 expect_from_stdin <<-\EOF &&
403 foo
404 twoooo
405 ../one
406 seven
407 ../../one
408 EOF
409 (
410 cd a/b/ignored-dir &&
411 test_check_ignore "foo twoooo ../one seven ../../one"
412 )
413'
414
415test_expect_success 'cd to ignored sub-directory with -v' '
416 expect_from_stdin <<-\EOF &&
417 a/b/.gitignore:5:ignored-dir/ foo
418 a/b/.gitignore:5:ignored-dir/ twoooo
419 a/b/.gitignore:8:!on* ../one
420 a/b/.gitignore:5:ignored-dir/ seven
421 .gitignore:1:one ../../one
422 EOF
423 (
424 cd a/b/ignored-dir &&
425 test_check_ignore "-v foo twoooo ../one seven ../../one"
426 )
427'
428
429############################################################################
430#
431# test handling of symlinks
432
433test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' '
434 test_check_ignore "a/symlink" 1
435'
436
437test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
438 test_check_ignore "a/symlink/foo" 128 &&
439 test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
440'
441
442test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
443 (
444 cd a &&
445 test_check_ignore "symlink/foo" 128
446 ) &&
447 test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
448'
449
450############################################################################
451#
452# test handling of submodules
453
454test_expect_success_multi 'submodule' '' '
455 test_check_ignore "a/submodule/one" 128 &&
456 test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
457'
458
459test_expect_success_multi 'submodule from subdirectory' '' '
460 (
461 cd a &&
462 test_check_ignore "submodule/one" 128
463 ) &&
464 test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
465'
466
467############################################################################
468#
469# test handling of global ignore files
470
471test_expect_success 'global ignore not yet enabled' '
472 expect_from_stdin <<-\EOF &&
473 .git/info/exclude:7:per-repo per-repo
474 a/.gitignore:2:*three a/globalthree
475 .git/info/exclude:7:per-repo a/per-repo
476 EOF
477 test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
478'
479
480test_expect_success 'global ignore' '
481 enable_global_excludes &&
482 expect_from_stdin <<-\EOF &&
483 globalone
484 per-repo
485 globalthree
486 a/globalthree
487 a/per-repo
488 globaltwo
489 EOF
490 test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
491'
492
493test_expect_success 'global ignore with -v' '
494 enable_global_excludes &&
495 expect_from_stdin <<-EOF &&
496 $global_excludes:1:globalone globalone
497 .git/info/exclude:7:per-repo per-repo
498 $global_excludes:3:globalthree globalthree
499 a/.gitignore:2:*three a/globalthree
500 .git/info/exclude:7:per-repo a/per-repo
501 $global_excludes:2:!globaltwo globaltwo
502 EOF
503 test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
504'
505
506############################################################################
507#
508# test --stdin
509
510cat <<-\EOF >stdin
511 one
512 not-ignored
513 a/one
514 a/not-ignored
515 a/b/on
516 a/b/one
517 a/b/one one
518 "a/b/one two"
519 "a/b/one\"three"
520 a/b/not-ignored
521 a/b/two
522 a/b/twooo
523 globaltwo
524 a/globaltwo
525 a/b/globaltwo
526 b/globaltwo
527EOF
528cat <<-\EOF >expected-default
529 one
530 a/one
531 a/b/on
532 a/b/one
533 a/b/one one
534 a/b/one two
535 "a/b/one\"three"
536 a/b/two
537 a/b/twooo
538 globaltwo
539 a/globaltwo
540 a/b/globaltwo
541 b/globaltwo
542EOF
543cat <<-EOF >expected-verbose
544 .gitignore:1:one one
545 .gitignore:1:one a/one
546 a/b/.gitignore:8:!on* a/b/on
547 a/b/.gitignore:8:!on* a/b/one
548 a/b/.gitignore:8:!on* a/b/one one
549 a/b/.gitignore:8:!on* a/b/one two
550 a/b/.gitignore:8:!on* "a/b/one\"three"
551 a/b/.gitignore:9:!two a/b/two
552 a/.gitignore:1:two* a/b/twooo
553 $global_excludes:2:!globaltwo globaltwo
554 $global_excludes:2:!globaltwo a/globaltwo
555 $global_excludes:2:!globaltwo a/b/globaltwo
556 $global_excludes:2:!globaltwo b/globaltwo
557EOF
558
559sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
560 tr "\n" "\0" >stdin0
561sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
562 tr "\n" "\0" >expected-default0
563sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
564 tr ":\t\n" "\0" >expected-verbose0
565
566test_expect_success '--stdin' '
567 expect_from_stdin <expected-default &&
568 test_check_ignore "--stdin" <stdin
569'
570
571test_expect_success '--stdin -q' '
572 expect "" &&
573 test_check_ignore "-q --stdin" <stdin
574'
575
576test_expect_success '--stdin -v' '
577 expect_from_stdin <expected-verbose &&
578 test_check_ignore "-v --stdin" <stdin
579'
580
581for opts in '--stdin -z' '-z --stdin'
582do
583 test_expect_success "$opts" "
584 expect_from_stdin <expected-default0 &&
585 test_check_ignore '$opts' <stdin0
586 "
587
588 test_expect_success "$opts -q" "
589 expect "" &&
590 test_check_ignore '-q $opts' <stdin0
591 "
592
593 test_expect_success "$opts -v" "
594 expect_from_stdin <expected-verbose0 &&
595 test_check_ignore '-v $opts' <stdin0
596 "
597done
598
599cat <<-\EOF >stdin
600 ../one
601 ../not-ignored
602 one
603 not-ignored
604 b/on
605 b/one
606 b/one one
607 "b/one two"
608 "b/one\"three"
609 b/two
610 b/not-ignored
611 b/twooo
612 ../globaltwo
613 globaltwo
614 b/globaltwo
615 ../b/globaltwo
616 c/not-ignored
617EOF
618# N.B. we deliberately end STDIN with a non-matching pattern in order
619# to test that the exit code indicates that one or more of the
620# provided paths is ignored - in other words, that it represents an
621# aggregation of all the results, not just the final result.
622
623cat <<-EOF >expected-all
624 .gitignore:1:one ../one
625 :: ../not-ignored
626 .gitignore:1:one one
627 :: not-ignored
628 a/b/.gitignore:8:!on* b/on
629 a/b/.gitignore:8:!on* b/one
630 a/b/.gitignore:8:!on* b/one one
631 a/b/.gitignore:8:!on* b/one two
632 a/b/.gitignore:8:!on* "b/one\"three"
633 a/b/.gitignore:9:!two b/two
634 :: b/not-ignored
635 a/.gitignore:1:two* b/twooo
636 $global_excludes:2:!globaltwo ../globaltwo
637 $global_excludes:2:!globaltwo globaltwo
638 $global_excludes:2:!globaltwo b/globaltwo
639 $global_excludes:2:!globaltwo ../b/globaltwo
640 :: c/not-ignored
641EOF
642grep -v '^:: ' expected-all >expected-verbose
643sed -e 's/.* //' expected-verbose >expected-default
644
645sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
646 tr "\n" "\0" >stdin0
647sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
648 tr "\n" "\0" >expected-default0
649sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
650 tr ":\t\n" "\0" >expected-verbose0
651
652test_expect_success '--stdin from subdirectory' '
653 expect_from_stdin <expected-default &&
654 (
655 cd a &&
656 test_check_ignore "--stdin" <../stdin
657 )
658'
659
660test_expect_success '--stdin from subdirectory with -v' '
661 expect_from_stdin <expected-verbose &&
662 (
663 cd a &&
664 test_check_ignore "--stdin -v" <../stdin
665 )
666'
667
668test_expect_success '--stdin from subdirectory with -v -n' '
669 expect_from_stdin <expected-all &&
670 (
671 cd a &&
672 test_check_ignore "--stdin -v -n" <../stdin
673 )
674'
675
676for opts in '--stdin -z' '-z --stdin'
677do
678 test_expect_success "$opts from subdirectory" '
679 expect_from_stdin <expected-default0 &&
680 (
681 cd a &&
682 test_check_ignore "'"$opts"'" <../stdin0
683 )
684 '
685
686 test_expect_success "$opts from subdirectory with -v" '
687 expect_from_stdin <expected-verbose0 &&
688 (
689 cd a &&
690 test_check_ignore "'"$opts"' -v" <../stdin0
691 )
692 '
693done
694
695
696test_done