summaryrefslogtreecommitdiff
path: root/t/test-lib.sh
diff options
context:
space:
mode:
Diffstat (limited to 't/test-lib.sh')
-rw-r--r--t/test-lib.sh379
1 files changed, 315 insertions, 64 deletions
diff --git a/t/test-lib.sh b/t/test-lib.sh
index e0266f0357..11562bde10 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -15,9 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/ .
-# Keep the original TERM for say_color
-ORIGINAL_TERM=$TERM
-
# Test the binaries we have just built. The tests are kept in
# t/ subdirectory and are run in 'trash directory' subdirectory.
if test -z "$TEST_DIRECTORY"
@@ -68,12 +65,12 @@ done,*)
esac
# For repeatability, reset the environment to known value.
+# TERM is sanitized below, after saving color control sequences.
LANG=C
LC_ALL=C
PAGER=cat
TZ=UTC
-TERM=dumb
-export LANG LC_ALL PAGER TERM TZ
+export LANG LC_ALL PAGER TZ
EDITOR=:
# A call to "unset" with no arguments causes at least Solaris 10
# /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets
@@ -91,6 +88,8 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
VALGRIND
UNZIP
PERF_
+ CURL_VERBOSE
+ TRACE_CURL
));
my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
print join("\n", @vars);
@@ -108,6 +107,10 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
export EDITOR
+# Tests using GIT_TRACE typically don't want <timestamp> <file>:<line> output
+GIT_TRACE_BARE=1
+export GIT_TRACE_BARE
+
if test -n "${TEST_GIT_INDEX_VERSION:+isset}"
then
GIT_INDEX_VERSION="$TEST_GIT_INDEX_VERSION"
@@ -135,6 +138,9 @@ else
}
fi
+: ${ASAN_OPTIONS=detect_leaks=0}
+export ASAN_OPTIONS
+
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
unset CDPATH
@@ -144,10 +150,7 @@ unset UNZIP
case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
1|2|true)
- echo "* warning: Some tests will not work if GIT_TRACE" \
- "is set as to trace on STDERR ! *"
- echo "* warning: Please set GIT_TRACE to something" \
- "other than 1, 2 or true ! *"
+ GIT_TRACE=4
;;
esac
@@ -160,6 +163,9 @@ _x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x05$_x05"
# Zero SHA-1
_z40=0000000000000000000000000000000000000000
+EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+EMPTY_BLOB=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+
# Line feed
LF='
'
@@ -168,7 +174,7 @@ LF='
# when case-folding filenames
u200c=$(printf '\342\200\214')
-export _x05 _x40 _z40 LF u200c
+export _x05 _x40 _z40 LF u200c EMPTY_TREE EMPTY_BLOB
# Each test should start with something like this, after copyright notices:
#
@@ -176,10 +182,8 @@ export _x05 _x40 _z40 LF u200c
# This test checks if command xyzzy does the right thing...
# '
# . ./test-lib.sh
-[ "x$ORIGINAL_TERM" != "xdumb" ] && (
- TERM=$ORIGINAL_TERM &&
- export TERM &&
- [ -t 1 ] &&
+test "x$TERM" != "xdumb" && (
+ test -t 1 &&
tput bold >/dev/null 2>&1 &&
tput setaf 1 >/dev/null 2>&1 &&
tput sgr0 >/dev/null 2>&1
@@ -195,12 +199,20 @@ do
immediate=t; shift ;;
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
+ -r)
+ shift; test "$#" -ne 0 || {
+ echo 'error: -r requires an argument' >&2;
+ exit 1;
+ }
+ run_list=$1; shift ;;
+ --run=*)
+ run_list=${1#--*=}; shift ;;
-h|--h|--he|--hel|--help)
help=t; shift ;;
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
verbose=t; shift ;;
--verbose-only=*)
- verbose_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ verbose_only=${1#--*=}
shift ;;
-q|--q|--qu|--qui|--quie|--quiet)
# Ignore --quiet under a TAP::Harness. Saying how many tests
@@ -214,15 +226,25 @@ do
valgrind=memcheck
shift ;;
--valgrind=*)
- valgrind=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ valgrind=${1#--*=}
shift ;;
--valgrind-only=*)
- valgrind_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ valgrind_only=${1#--*=}
shift ;;
--tee)
shift ;; # was handled already
--root=*)
- root=$(expr "z$1" : 'z[^=]*=\(.*\)')
+ root=${1#--*=}
+ shift ;;
+ --chain-lint)
+ GIT_TEST_CHAIN_LINT=1
+ shift ;;
+ --no-chain-lint)
+ GIT_TEST_CHAIN_LINT=0
+ shift ;;
+ -x)
+ trace=t
+ verbose=t
shift ;;
*)
echo "error: unknown test option '$1'" >&2; exit 1 ;;
@@ -240,29 +262,30 @@ fi
if test -n "$color"
then
+ # Save the color control sequences now rather than run tput
+ # each time say_color() is called. This is done for two
+ # reasons:
+ # * TERM will be changed to dumb
+ # * HOME will be changed to a temporary directory and tput
+ # might need to read ~/.terminfo from the original HOME
+ # directory to get the control sequences
+ # Note: This approach assumes the control sequences don't end
+ # in a newline for any terminal of interest (command
+ # substitutions strip trailing newlines). Given that most
+ # (all?) terminals in common use are related to ECMA-48, this
+ # shouldn't be a problem.
+ say_color_error=$(tput bold; tput setaf 1) # bold red
+ say_color_skip=$(tput setaf 4) # blue
+ say_color_warn=$(tput setaf 3) # brown/yellow
+ say_color_pass=$(tput setaf 2) # green
+ say_color_info=$(tput setaf 6) # cyan
+ say_color_reset=$(tput sgr0)
+ say_color_="" # no formatting for normal text
say_color () {
- (
- TERM=$ORIGINAL_TERM
- export TERM
- case "$1" in
- error)
- tput bold; tput setaf 1;; # bold red
- skip)
- tput setaf 4;; # blue
- warn)
- tput setaf 3;; # brown/yellow
- pass)
- tput setaf 2;; # green
- info)
- tput setaf 6;; # cyan
- *)
- test -n "$quiet" && return;;
- esac
+ test -z "$1" && test -n "$quiet" && return
+ eval "say_color_color=\$say_color_$1"
shift
- printf "%s" "$*"
- tput sgr0
- echo
- )
+ printf "%s\\n" "$say_color_color$*$say_color_reset"
}
else
say_color() {
@@ -272,6 +295,9 @@ else
}
fi
+TERM=dumb
+export TERM
+
error () {
say_color error "error: $*"
GIT_EXIT_OK=t
@@ -300,6 +326,19 @@ else
exec 4>/dev/null 3>/dev/null
fi
+# Send any "-x" output directly to stderr to avoid polluting tests
+# which capture stderr. We can do this unconditionally since it
+# has no effect if tracing isn't turned on.
+#
+# Note that this sets up the trace fd as soon as we assign the variable, so it
+# must come after the creation of descriptor 4 above. Likewise, we must never
+# unset this, as it has the side effect of closing descriptor 4, which we
+# use to show verbose tests to the user.
+#
+# Note also that we don't need or want to export it. The tracing is local to
+# this shell, and we would not want to influence any shells we exec.
+BASH_XTRACEFD=4
+
test_failure=0
test_count=0
test_fixed=0
@@ -321,6 +360,7 @@ die () {
GIT_EXIT_OK=
trap 'die' EXIT
+trap 'exit $?' INT
# The user-facing functions are loaded from a separate file so that
# test_perf subshells can have them too
@@ -370,6 +410,99 @@ match_pattern_list () {
return 1
}
+match_test_selector_list () {
+ title="$1"
+ shift
+ arg="$1"
+ shift
+ test -z "$1" && return 0
+
+ # Both commas and whitespace are accepted as separators.
+ OLDIFS=$IFS
+ IFS=' ,'
+ set -- $1
+ IFS=$OLDIFS
+
+ # If the first selector is negative we include by default.
+ include=
+ case "$1" in
+ !*) include=t ;;
+ esac
+
+ for selector
+ do
+ orig_selector=$selector
+
+ positive=t
+ case "$selector" in
+ !*)
+ positive=
+ selector=${selector##?}
+ ;;
+ esac
+
+ test -z "$selector" && continue
+
+ case "$selector" in
+ *-*)
+ if expr "z${selector%%-*}" : "z[0-9]*[^0-9]" >/dev/null
+ then
+ echo "error: $title: invalid non-numeric in range" \
+ "start: '$orig_selector'" >&2
+ exit 1
+ fi
+ if expr "z${selector#*-}" : "z[0-9]*[^0-9]" >/dev/null
+ then
+ echo "error: $title: invalid non-numeric in range" \
+ "end: '$orig_selector'" >&2
+ exit 1
+ fi
+ ;;
+ *)
+ if expr "z$selector" : "z[0-9]*[^0-9]" >/dev/null
+ then
+ echo "error: $title: invalid non-numeric in test" \
+ "selector: '$orig_selector'" >&2
+ exit 1
+ fi
+ esac
+
+ # Short cut for "obvious" cases
+ test -z "$include" && test -z "$positive" && continue
+ test -n "$include" && test -n "$positive" && continue
+
+ case "$selector" in
+ -*)
+ if test $arg -le ${selector#-}
+ then
+ include=$positive
+ fi
+ ;;
+ *-)
+ if test $arg -ge ${selector%-}
+ then
+ include=$positive
+ fi
+ ;;
+ *-*)
+ if test ${selector%%-*} -le $arg \
+ && test $arg -le ${selector#*-}
+ then
+ include=$positive
+ fi
+ ;;
+ *)
+ if test $arg -eq $selector
+ then
+ include=$positive
+ fi
+ ;;
+ esac
+ done
+
+ test -n "$include"
+}
+
maybe_teardown_verbose () {
test -z "$verbose_only" && return
exec 4>/dev/null 3>/dev/null
@@ -415,21 +548,70 @@ maybe_setup_valgrind () {
fi
}
+want_trace () {
+ test "$trace" = t && test "$verbose" = t
+}
+
+# This is a separate function because some tests use
+# "return" to end a test_expect_success block early
+# (and we want to make sure we run any cleanup like
+# "set +x").
+test_eval_inner_ () {
+ # Do not add anything extra (including LF) after '$*'
+ eval "
+ want_trace && set -x
+ $*"
+}
+
test_eval_ () {
- # This is a separate function because some tests use
- # "return" to end a test_expect_success block early.
- eval </dev/null >&3 2>&4 "$*"
+ # We run this block with stderr redirected to avoid extra cruft
+ # during a "-x" trace. Once in "set -x" mode, we cannot prevent
+ # the shell from printing the "set +x" to turn it off (nor the saving
+ # of $? before that). But we can make sure that the output goes to
+ # /dev/null.
+ #
+ # The test itself is run with stderr put back to &4 (so either to
+ # /dev/null, or to the original stderr if --verbose was used).
+ {
+ test_eval_inner_ "$@" </dev/null >&3 2>&4
+ test_eval_ret_=$?
+ if want_trace
+ then
+ set +x
+ if test "$test_eval_ret_" != 0
+ then
+ say_color error >&4 "error: last command exited with \$?=$test_eval_ret_"
+ fi
+ fi
+ } 2>/dev/null
+ return $test_eval_ret_
}
test_run_ () {
test_cleanup=:
expecting_failure=$2
+
+ if test "${GIT_TEST_CHAIN_LINT:-1}" != 0; then
+ # turn off tracing for this test-eval, as it simply creates
+ # confusing noise in the "-x" output
+ trace_tmp=$trace
+ trace=
+ # 117 is magic because it is unlikely to match the exit
+ # code of other programs
+ test_eval_ "(exit 117) && $1"
+ if test "$?" != 117; then
+ error "bug in the test script: broken &&-chain: $1"
+ fi
+ trace=$trace_tmp
+ fi
+
setup_malloc_check
test_eval_ "$1"
eval_ret=$?
teardown_malloc_check
- if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"
+ if test -z "$immediate" || test $eval_ret = 0 ||
+ test -n "$expecting_failure" && test "$test_cleanup" != ":"
then
setup_malloc_check
test_eval_ "$test_cleanup"
@@ -456,25 +638,35 @@ test_finish_ () {
test_skip () {
to_skip=
+ skipped_reason=
if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS
then
to_skip=t
+ skipped_reason="GIT_SKIP_TESTS"
fi
if test -z "$to_skip" && test -n "$test_prereq" &&
! test_have_prereq "$test_prereq"
then
to_skip=t
- fi
- case "$to_skip" in
- t)
+
of_prereq=
if test "$missing_prereq" != "$test_prereq"
then
of_prereq=" of $test_prereq"
fi
+ skipped_reason="missing $missing_prereq${of_prereq}"
+ fi
+ if test -z "$to_skip" && test -n "$run_list" &&
+ ! match_test_selector_list '--run' $test_count "$run_list"
+ then
+ to_skip=t
+ skipped_reason="--run"
+ fi
+ case "$to_skip" in
+ t)
say_color skip >&3 "skipping test: $@"
- say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
+ say_color skip "ok $test_count # skip $1 ($skipped_reason)"
: true
;;
*)
@@ -496,9 +688,9 @@ test_done () {
test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
base=${0##*/}
- test_results_path="$test_results_dir/${base%.sh}-$$.counts"
+ test_results_path="$test_results_dir/${base%.sh}.counts"
- cat >>"$test_results_path" <<-EOF
+ cat >"$test_results_path" <<-EOF
total $test_count
success $test_success
fixed $test_fixed
@@ -531,7 +723,7 @@ test_done () {
then
error "Can't use skip_all after running some tests"
fi
- [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
+ test -z "$skip_all" || skip_all=" # SKIP $skip_all"
if test $test_external_has_tap -eq 0
then
@@ -610,7 +802,7 @@ then
# override all git executables in TEST_DIRECTORY/..
GIT_VALGRIND=$TEST_DIRECTORY/valgrind
mkdir -p "$GIT_VALGRIND"/bin
- for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-*
+ for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/t/helper/test-*
do
make_valgrind_symlink $file
done
@@ -679,10 +871,10 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
error "You haven't built things yet, have you?"
}
-if ! test -x "$GIT_BUILD_DIR"/test-chmtime
+if ! test -x "$GIT_BUILD_DIR"/t/helper/test-chmtime
then
echo >&2 'You need to build test-chmtime:'
- echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
+ echo >&2 'Run "make t/helper/test-chmtime" in the source (toplevel) directory'
exit 1
fi
@@ -701,7 +893,8 @@ rm -fr "$TRASH_DIRECTORY" || {
}
HOME="$TRASH_DIRECTORY"
-export HOME
+GNUPGHOME="$HOME/gnupg-home-not-used"
+export HOME GNUPGHOME
if test -z "$TEST_NO_CREATE_REPO"
then
@@ -731,9 +924,11 @@ yes () {
y="$*"
fi
- while echo "$y"
+ i=0
+ while test $i -lt 99
do
- :
+ echo "$y"
+ i=$(($i+1))
done
}
@@ -758,7 +953,7 @@ case $(uname -s) in
# backslashes in pathspec are converted to '/'
# exec does not inherit the PID
test_set_prereq MINGW
- test_set_prereq NOT_CYGWIN
+ test_set_prereq NATIVE_CRLF
test_set_prereq SED_STRIPS_CR
test_set_prereq GREP_STRIPS_CR
GIT_TEST_CMP=mingw_test_cmp
@@ -766,7 +961,6 @@ case $(uname -s) in
*CYGWIN*)
test_set_prereq POSIXPERM
test_set_prereq EXECKEEPSPID
- test_set_prereq NOT_MINGW
test_set_prereq CYGWIN
test_set_prereq SED_STRIPS_CR
test_set_prereq GREP_STRIPS_CR
@@ -775,8 +969,6 @@ case $(uname -s) in
test_set_prereq POSIXPERM
test_set_prereq BSLASHPSPEC
test_set_prereq EXECKEEPSPID
- test_set_prereq NOT_MINGW
- test_set_prereq NOT_CYGWIN
;;
esac
@@ -825,7 +1017,7 @@ test_i18ngrep () {
test_lazy_prereq PIPE '
# test whether the filesystem supports FIFOs
case $(uname -s) in
- CYGWIN*)
+ CYGWIN*|MINGW*)
false
;;
*)
@@ -868,12 +1060,71 @@ test_lazy_prereq AUTOIDENT '
git var GIT_AUTHOR_IDENT
'
-# When the tests are run as root, permission tests will report that
-# things are writable when they shouldn't be.
-test -w / || test_set_prereq SANITY
+test_lazy_prereq EXPENSIVE '
+ test -n "$GIT_TEST_LONG"
+'
+
+test_lazy_prereq USR_BIN_TIME '
+ test -x /usr/bin/time
+'
+
+test_lazy_prereq NOT_ROOT '
+ uid=$(id -u) &&
+ test "$uid" != 0
+'
+
+test_lazy_prereq JGIT '
+ type jgit
+'
+
+# SANITY is about "can you correctly predict what the filesystem would
+# do by only looking at the permission bits of the files and
+# directories?" A typical example of !SANITY is running the test
+# suite as root, where a test may expect "chmod -r file && cat file"
+# to fail because file is supposed to be unreadable after a successful
+# chmod. In an environment (i.e. combination of what filesystem is
+# being used and who is running the tests) that lacks SANITY, you may
+# be able to delete or create a file when the containing directory
+# doesn't have write permissions, or access a file even if the
+# containing directory doesn't have read or execute permissions.
+
+test_lazy_prereq SANITY '
+ mkdir SANETESTD.1 SANETESTD.2 &&
+
+ chmod +w SANETESTD.1 SANETESTD.2 &&
+ >SANETESTD.1/x 2>SANETESTD.2/x &&
+ chmod -w SANETESTD.1 &&
+ chmod -r SANETESTD.1/x &&
+ chmod -rx SANETESTD.2 ||
+ error "bug in test sript: cannot prepare SANETESTD"
+
+ ! test -r SANETESTD.1/x &&
+ ! rm SANETESTD.1/x && ! test -f SANETESTD.2/x
+ status=$?
+
+ chmod +rwx SANETESTD.1 SANETESTD.2 &&
+ rm -rf SANETESTD.1 SANETESTD.2 ||
+ error "bug in test sript: cannot clean SANETESTD"
+ return $status
+'
GIT_UNZIP=${GIT_UNZIP:-unzip}
test_lazy_prereq UNZIP '
"$GIT_UNZIP" -v
test $? -ne 127
'
+
+run_with_limited_cmdline () {
+ (ulimit -s 128 && "$@")
+}
+
+test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true'
+
+build_option () {
+ git version --build-options |
+ sed -ne "s/^$1: //p"
+}
+
+test_lazy_prereq LONG_IS_64BIT '
+ test 8 -le "$(build_option sizeof-long)"
+'