test_cmp "$HOME/expected-stderr" "$HOME/stderr"
}
+broken_c_unquote () {
+ "$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@"
+}
+
+broken_c_unquote_verbose () {
+ "$PERL_PATH" -pe 's/ "/ /; s/\\//; s/"$//; tr/:\t\n/\0/' "$@"
+}
+
stderr_contains () {
regexp="$1"
if grep "$regexp" "$HOME/stderr"
init_vars &&
rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
- echo git $global_args check-ignore $quiet_opt $verbose_opt $args \
+ echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
>"$HOME/cmd" &&
+ echo "$expect_code" >"$HOME/expected-exit-code" &&
test_expect_code "$expect_code" \
- git $global_args check-ignore $quiet_opt $verbose_opt $args \
+ git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
>"$HOME/stdout" 2>"$HOME/stderr" &&
test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
stderr_empty_on_success "$expect_code"
}
-# Runs the same code with 3 different levels of output verbosity,
+# Runs the same code with 4 different levels of output verbosity:
+#
+# 1. with -q / --quiet
+# 2. with default verbosity
+# 3. with -v / --verbose
+# 4. with -v / --verbose, *and* -n / --non-matching
+#
# expecting success each time. Takes advantage of the fact that
# check-ignore --verbose output is the same as normal output except
# for the extra first column.
#
+# A parameter is used to determine if the tests are run with the
+# normal case (using the index), or with the --no-index option.
+#
# Arguments:
# - (optional) prereqs for this test, e.g. 'SYMLINKS'
# - test name
-# - output to expect from -v / --verbose mode
+# - output to expect from the fourth verbosity mode (the output
+# from the other verbosity modes is automatically inferred
+# from this value)
# - code to run (should invoke test_check_ignore)
-test_expect_success_multi () {
+# - index option: --index or --no-index
+test_expect_success_multiple () {
prereq=
- if test $# -eq 4
+ if test $# -eq 5
then
prereq=$1
shift
fi
- testname="$1" expect_verbose="$2" code="$3"
+ if test "$4" = "--index"
+ then
+ no_index_opt=
+ else
+ no_index_opt=$4
+ fi
+ testname="$1" expect_all="$2" code="$3"
+ expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
- test_expect_success $prereq "$testname" '
+ test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" '
expect "$expect" &&
eval "$code"
'
- for quiet_opt in '-q' '--quiet'
- do
- test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
+ # --quiet is only valid when a single pattern is passed
+ if test $( echo "$expect_all" | wc -l ) = 1
+ then
+ for quiet_opt in '-q' '--quiet'
+ do
+ opts="${no_index_opt:+$no_index_opt }$quiet_opt"
+ test_expect_success $prereq "$testname${opts:+ with $opts}" "
expect '' &&
$code
"
- done
- quiet_opt=
+ done
+ quiet_opt=
+ fi
for verbose_opt in '-v' '--verbose'
do
- test_expect_success $prereq "$testname${verbose_opt:+ with $verbose_opt}" "
- expect '$expect_verbose' &&
- $code
- "
+ for non_matching_opt in '' '-n' '--non-matching'
+ do
+ if test -n "$non_matching_opt"
+ then
+ my_expect="$expect_all"
+ else
+ my_expect="$expect_verbose"
+ fi
+
+ test_code="
+ expect '$my_expect' &&
+ $code
+ "
+ opts="${no_index_opt:+$no_index_opt }$verbose_opt${non_matching_opt:+ $non_matching_opt}"
+ test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
+ done
done
verbose_opt=
+ non_matching_opt=
+ no_index_opt=
+}
+
+test_expect_success_multi () {
+ test_expect_success_multiple "$@" "--index"
+}
+
+test_expect_success_no_index_multi () {
+ test_expect_success_multiple "$@" "--no-index"
}
test_expect_success 'setup' '
#
# test invalid inputs
-test_expect_success_multi '. corner-case' '' '
+test_expect_success_multi '. corner-case' ':: .' '
test_check_ignore . 1
'
test_expect_success_multi '--stdin with empty STDIN' '' '
test_check_ignore "--stdin" 1 </dev/null &&
- if test -n "$quiet_opt"; then
- test_stderr ""
- else
- test_stderr "no pathspec given."
- fi
+ test_stderr ""
'
test_expect_success '-q with multiple args' '
# First make sure that the presence of a file in the working tree
# does not impact results, but that the presence of a file in the
-# index does.
+# index does unless the --no-index option is used.
for subdir in '' 'a/'
do
where="in subdir $subdir"
fi
- test_expect_success_multi "non-existent file $where not ignored" '' "
- test_check_ignore '${subdir}non-existent' 1
- "
+ test_expect_success_multi "non-existent file $where not ignored" \
+ ":: ${subdir}non-existent" \
+ "test_check_ignore '${subdir}non-existent' 1"
+
+ test_expect_success_no_index_multi "non-existent file $where not ignored" \
+ ":: ${subdir}non-existent" \
+ "test_check_ignore '${subdir}non-existent' 1"
test_expect_success_multi "non-existent file $where ignored" \
- ".gitignore:1:one ${subdir}one" "
- test_check_ignore '${subdir}one'
- "
+ ".gitignore:1:one ${subdir}one" \
+ "test_check_ignore '${subdir}one'"
- test_expect_success_multi "existing untracked file $where not ignored" '' "
- test_check_ignore '${subdir}not-ignored' 1
- "
+ test_expect_success_no_index_multi "non-existent file $where ignored" \
+ ".gitignore:1:one ${subdir}one" \
+ "test_check_ignore '${subdir}one'"
- test_expect_success_multi "existing tracked file $where not ignored" '' "
- test_check_ignore '${subdir}ignored-but-in-index' 1
- "
+ test_expect_success_multi "existing untracked file $where not ignored" \
+ ":: ${subdir}not-ignored" \
+ "test_check_ignore '${subdir}not-ignored' 1"
+
+ test_expect_success_no_index_multi "existing untracked file $where not ignored" \
+ ":: ${subdir}not-ignored" \
+ "test_check_ignore '${subdir}not-ignored' 1"
+
+ test_expect_success_multi "existing tracked file $where not ignored" \
+ ":: ${subdir}ignored-but-in-index" \
+ "test_check_ignore '${subdir}ignored-but-in-index' 1"
+
+ test_expect_success_no_index_multi "existing tracked file $where shown as ignored" \
+ ".gitignore:2:ignored-* ${subdir}ignored-but-in-index" \
+ "test_check_ignore '${subdir}ignored-but-in-index'"
test_expect_success_multi "existing untracked file $where ignored" \
- ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" "
- test_check_ignore '${subdir}ignored-and-untracked'
- "
+ ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '${subdir}ignored-and-untracked'"
+
+ test_expect_success_no_index_multi "existing untracked file $where ignored" \
+ ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '${subdir}ignored-and-untracked'"
+
+ test_expect_success_multi "mix of file types $where" \
+":: ${subdir}non-existent
+.gitignore:1:one ${subdir}one
+:: ${subdir}not-ignored
+:: ${subdir}ignored-but-in-index
+.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '
+ ${subdir}non-existent
+ ${subdir}one
+ ${subdir}not-ignored
+ ${subdir}ignored-but-in-index
+ ${subdir}ignored-and-untracked'
+ "
+
+ test_expect_success_no_index_multi "mix of file types $where" \
+":: ${subdir}non-existent
+.gitignore:1:one ${subdir}one
+:: ${subdir}not-ignored
+.gitignore:2:ignored-* ${subdir}ignored-but-in-index
+.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '
+ ${subdir}non-existent
+ ${subdir}one
+ ${subdir}not-ignored
+ ${subdir}ignored-but-in-index
+ ${subdir}ignored-and-untracked'
+ "
done
# Having established the above, from now on we mostly test against
#
# test handling of symlinks
-test_expect_success_multi SYMLINKS 'symlink' '' '
+test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' '
test_check_ignore "a/symlink" 1
'
test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
test_check_ignore "a/symlink/foo" 128 &&
- test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
+ test_stderr "fatal: pathspec '\''a/symlink/foo'\'' is beyond a symbolic link"
'
test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
cd a &&
test_check_ignore "symlink/foo" 128
) &&
- test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
+ test_stderr "fatal: pathspec '\''symlink/foo'\'' is beyond a symbolic link"
'
############################################################################
test_expect_success_multi 'submodule' '' '
test_check_ignore "a/submodule/one" 128 &&
- test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
+ test_stderr "fatal: Pathspec '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
'
test_expect_success_multi 'submodule from subdirectory' '' '
cd a &&
test_check_ignore "submodule/one" 128
) &&
- test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
+ test_stderr "fatal: Pathspec '\''submodule/one'\'' is in submodule '\''a/submodule'\''"
'
############################################################################
$global_excludes:2:!globaltwo b/globaltwo
EOF
-sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
- tr "\n" "\0" >stdin0
-sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
- tr "\n" "\0" >expected-default0
-sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
- tr ":\t\n" "\0" >expected-verbose0
+broken_c_unquote stdin >stdin0
+
+broken_c_unquote expected-default >expected-default0
+
+broken_c_unquote_verbose expected-verbose >expected-verbose0
test_expect_success '--stdin' '
expect_from_stdin <expected-default &&
globaltwo
b/globaltwo
../b/globaltwo
+ c/not-ignored
EOF
-cat <<-\EOF >expected-default
- ../one
- one
- b/on
- b/one
- b/one one
- b/one two
- "b/one\"three"
- b/two
- b/twooo
- ../globaltwo
- globaltwo
- b/globaltwo
- ../b/globaltwo
-EOF
-cat <<-EOF >expected-verbose
+# N.B. we deliberately end STDIN with a non-matching pattern in order
+# to test that the exit code indicates that one or more of the
+# provided paths is ignored - in other words, that it represents an
+# aggregation of all the results, not just the final result.
+
+cat <<-EOF >expected-all
.gitignore:1:one ../one
+ :: ../not-ignored
.gitignore:1:one one
+ :: not-ignored
a/b/.gitignore:8:!on* b/on
a/b/.gitignore:8:!on* b/one
a/b/.gitignore:8:!on* b/one one
a/b/.gitignore:8:!on* b/one two
a/b/.gitignore:8:!on* "b/one\"three"
a/b/.gitignore:9:!two b/two
+ :: b/not-ignored
a/.gitignore:1:two* b/twooo
$global_excludes:2:!globaltwo ../globaltwo
$global_excludes:2:!globaltwo globaltwo
$global_excludes:2:!globaltwo b/globaltwo
$global_excludes:2:!globaltwo ../b/globaltwo
+ :: c/not-ignored
EOF
+grep -v '^:: ' expected-all >expected-verbose
+sed -e 's/.* //' expected-verbose >expected-default
+
+broken_c_unquote stdin >stdin0
-sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
- tr "\n" "\0" >stdin0
-sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
- tr "\n" "\0" >expected-default0
-sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
- tr ":\t\n" "\0" >expected-verbose0
+broken_c_unquote expected-default >expected-default0
+
+broken_c_unquote_verbose expected-verbose >expected-verbose0
test_expect_success '--stdin from subdirectory' '
expect_from_stdin <expected-default &&
)
'
+test_expect_success '--stdin from subdirectory with -v -n' '
+ expect_from_stdin <expected-all &&
+ (
+ cd a &&
+ test_check_ignore "--stdin -v -n" <../stdin
+ )
+'
+
for opts in '--stdin -z' '-z --stdin'
do
test_expect_success "$opts from subdirectory" '
'
done
+test_expect_success PIPE 'streaming support for --stdin' '
+ mkfifo in out &&
+ (git check-ignore -n -v --stdin <in >out &) &&
+
+ # We cannot just "echo >in" because check-ignore would get EOF
+ # after echo exited; instead we open the descriptor in our
+ # shell, and then echo to the fd. We make sure to close it at
+ # the end, so that the subprocess does get EOF and dies
+ # properly.
+ #
+ # Similarly, we must keep "out" open so that check-ignore does
+ # not ever get SIGPIPE trying to write to us. Not only would that
+ # produce incorrect results, but then there would be no writer on the
+ # other end of the pipe, and we would potentially block forever trying
+ # to open it.
+ exec 9>in &&
+ exec 8<out &&
+ test_when_finished "exec 9>&-" &&
+ test_when_finished "exec 8<&-" &&
+ echo >&9 one &&
+ read response <&8 &&
+ echo "$response" | grep "^\.gitignore:1:one one" &&
+ echo >&9 two &&
+ read response <&8 &&
+ echo "$response" | grep "^:: two"
+'
+
+############################################################################
+#
+# test whitespace handling
+
+test_expect_success 'trailing whitespace is ignored' '
+ mkdir whitespace &&
+ >whitespace/trailing &&
+ >whitespace/untracked &&
+ echo "whitespace/trailing " >ignore &&
+ cat >expect <<EOF &&
+whitespace/untracked
+EOF
+ : >err.expect &&
+ git ls-files -o -X ignore whitespace >actual 2>err &&
+ test_cmp expect actual &&
+ test_cmp err.expect err
+'
+
+test_expect_success !MINGW 'quoting allows trailing whitespace' '
+ rm -rf whitespace &&
+ mkdir whitespace &&
+ >"whitespace/trailing " &&
+ >whitespace/untracked &&
+ echo "whitespace/trailing\\ \\ " >ignore &&
+ echo whitespace/untracked >expect &&
+ : >err.expect &&
+ git ls-files -o -X ignore whitespace >actual 2>err &&
+ test_cmp expect actual &&
+ test_cmp err.expect err
+'
test_done