diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index e2d783d90b..1d9a0a736d 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -10,7 +10,14 @@ export TEST_CONTRIB_TOO=yes case "$jobname" in linux-musl-meson) MESONFLAGS="$MESONFLAGS -Drust=disabled" + export GIT_TEST_USE_SET_E=yes ;; +almalinux-*|debian-*|fedora-*|linux-*) + export GIT_TEST_USE_SET_E=yes + ;; +esac + +case "$jobname" in fedora-breaking-changes-musl|linux-breaking-changes) export WITH_BREAKING_CHANGES=YesPlease MESONFLAGS="$MESONFLAGS -Dbreaking_changes=true" diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh index e62569222b..d172aa51f0 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -85,14 +85,16 @@ stop_git_daemon() { # kill git-daemon child of git say >&3 "Stopping git daemon ..." + kill "$GIT_DAEMON_PID" - wait "$GIT_DAEMON_PID" >&3 2>&4 - ret=$? + ret=0; wait "$GIT_DAEMON_PID" >&3 2>&4 || ret=$? + if ! test_match_signal 15 $ret then error "git daemon exited with status: $ret" fi - kill "$(cat "$GIT_DAEMON_PIDFILE")" 2>/dev/null + + kill "$(cat "$GIT_DAEMON_PIDFILE")" 2>/dev/null || : GIT_DAEMON_PID= rm -f git_daemon_output "$GIT_DAEMON_PIDFILE" } diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 2fde2353fd..52843f667d 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -15,8 +15,7 @@ GIT_SVN_DIR=$GIT_DIR/svn/refs/remotes/git-svn SVN_TREE=$GIT_SVN_DIR/svn-tree test_set_port SVNSERVE_PORT -svn >/dev/null 2>&1 -if test $? -ne 1 +if ! svn help >/dev/null 2>&1 then skip_all='skipping git svn tests, svn not found' test_done @@ -27,13 +26,13 @@ export svnrepo svnconf=$PWD/svnconf export svnconf +x=0 perl -w -e " use SVN::Core; use SVN::Repos; \$SVN::Core::VERSION gt '1.1.0' or exit(42); system(qw/svnadmin create --fs-type fsfs/, \$ENV{svnrepo}) == 0 or exit(41); -" >&3 2>&4 -x=$? +" >&3 2>&4 || x=$? if test $x -ne 0 then if test $x -eq 42; then diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 4c76e813e3..fc646447d5 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -235,11 +235,10 @@ start_httpd() { test_atexit stop_httpd - "$LIB_HTTPD_PATH" -d "$HTTPD_ROOT_PATH" \ + if ! "$LIB_HTTPD_PATH" -d "$HTTPD_ROOT_PATH" \ -f "$TEST_PATH/apache.conf" $HTTPD_PARA \ -c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start \ >&3 2>&4 - if test $? -ne 0 then cat "$HTTPD_ROOT_PATH"/error.log >&4 2>/dev/null test_skip_or_die GIT_TEST_HTTPD "web server setup failed" diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh index afba0fc3fc..84319cf169 100755 --- a/t/t0005-signals.sh +++ b/t/t0005-signals.sh @@ -42,12 +42,12 @@ test_expect_success 'create blob' ' ' test_expect_success !MINGW 'a constipated git dies with SIGPIPE' ' - OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && + OUT=$( ((large_git && echo 0 1>&3 || echo $? 1>&3) | :) 3>&1 ) && test_match_signal 13 "$OUT" ' test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' ' - OUT=$( ((trap "" PIPE && large_git; echo $? 1>&3) | :) 3>&1 ) && + OUT=$( ((trap "" PIPE && large_git && echo 0 1>&3 || echo $? 1>&3) | :) 3>&1 ) && test_match_signal 13 "$OUT" ' diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh index e716b5cdfa..d77a179bdd 100755 --- a/t/t0008-ignores.sh +++ b/t/t0008-ignores.sh @@ -122,8 +122,8 @@ test_expect_success_multiple () { fi testname="$1" expect_all="$2" code="$3" - expect_verbose=$( echo "$expect_all" | grep -v '^:: ' ) - expect=$( echo "$expect_verbose" | sed -e 's/.* //' ) + expect_verbose=$(echo "$expect_all" | grep -v '^:: ' || :) + expect=$(echo "$expect_verbose" | sed -e 's/.* //') test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" ' expect "$expect" && diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 630a47af21..0e0d07a1a1 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -12,7 +12,7 @@ TEST_CREATE_REPO_NO_TEMPLATE=1 . ./test-lib.sh # Remove a default ACL from the test dir if possible. -setfacl -k . 2>/dev/null +setfacl -k . 2>/dev/null || : # User must have read permissions to the repo -> failure on --shared=0400 test_expect_success 'shared = 0400 (faulty permission u-w)' ' diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 1f16e6b522..a371ea690e 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -260,7 +260,7 @@ test_expect_success 'choking "git rm" should not let it die with cruft (induce S test_expect_success !MINGW 'choking "git rm" should not let it die with cruft (induce and check SIGPIPE)' ' choke_git_rm_setup && - OUT=$( ((trap "" PIPE && git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) && + OUT=$( ((trap "" PIPE && git rm -n "some-file-*" && echo 0 1>&3 || echo $? 1>&3) | :) 3>&1 ) && test_match_signal 13 "$OUT" && test_path_is_missing .git/index.lock ' diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index f03601b49a..ef7d7e1edc 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -28,7 +28,8 @@ check_encoding () { 8859) grep "^encoding ISO8859-1" ;; *) - grep "^encoding ISO8859-1"; test "$?" != 0 ;; + ret=0; grep "^encoding ISO8859-1" || ret=$? + test "$ret" != 0 ;; esac || return 1 j=$i i=$(($i+1)) diff --git a/t/t4032-diff-inter-hunk-context.sh b/t/t4032-diff-inter-hunk-context.sh index bada0cbd32..2d216fb70f 100755 --- a/t/t4032-diff-inter-hunk-context.sh +++ b/t/t4032-diff-inter-hunk-context.sh @@ -17,7 +17,7 @@ f() { t() { use_config= - git config --unset diff.interHunkContext + git config --unset diff.interHunkContext || : case $# in 4) hunks=$4; cmd="diff -U$3";; @@ -40,11 +40,13 @@ t() { test $(git $cmd $file | grep '^@@ ' | wc -l) = $hunks " - test -f $expected && - test_expect_success "$label: check output" " - git $cmd $file | grep -v '^index ' >actual && - test_cmp $expected actual - " + if test -f $expected + then + test_expect_success "$label: check output" " + git $cmd $file | grep -v '^index ' >actual && + test_cmp $expected actual + " + fi } cat <expected.f1.0.1 || exit 1 diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 5465054f17..a8c28533dc 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -503,8 +503,8 @@ test_expect_success LONG_IS_64BIT 'set up repository with huge blob' ' # would generate the whole 64GB). test_expect_success LONG_IS_64BIT 'generate tar with huge size' ' { - git archive HEAD - echo $? >exit-code + { ret=0 && git archive HEAD || ret=$?; } && + echo "$ret" >exit-code } | test_copy_bytes 4096 >huge.tar && echo 141 >expect && test_cmp expect exit-code diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh index daa009c9a1..f2de40b5ed 100755 --- a/t/t6002-rev-list-bisect.sh +++ b/t/t6002-rev-list-bisect.sh @@ -27,13 +27,16 @@ test_bisection_diff() # Test if bisection size is close to half of list size within # tolerance. # - _bisect_err=$(expr $_list_size - $_bisection_size \* 2) - test "$_bisect_err" -lt 0 && _bisect_err=$(expr 0 - $_bisect_err) - _bisect_err=$(expr $_bisect_err / 2) ; # floor + _bisect_err=$(($_list_size - $_bisection_size * 2)) + if test "$_bisect_err" -lt 0 + then + _bisect_err=$((0 - $_bisect_err)) + fi + _bisect_err=$(($_bisect_err / 2)) ; # floor - test_expect_success \ - "bisection diff $_bisect_option $_head $* <= $_max_diff" \ - 'test $_bisect_err -le $_max_diff' + test_expect_success "bisection diff $_bisect_option $_head $* <= $_max_diff" ' + test $_bisect_err -le $_max_diff + ' } date >path0 diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh index aea1ddf117..852136fdfd 100755 --- a/t/t7422-submodule-output.sh +++ b/t/t7422-submodule-output.sh @@ -198,7 +198,7 @@ test_expect_success !MINGW 'git submodule status --recursive propagates SIGPIPE' ( cd repo && GIT_ALLOW_PROTOCOL=file git submodule add "$(pwd)"/../submodule && - { git submodule status --recursive 2>err; echo $?>status; } | + { { ret=0 && git submodule status --recursive 2>err || ret=$?; } && echo $ret >status; } | grep -q recursive-submodule-path-1 && test_must_be_empty err && test_match_signal 13 "$(cat status)" diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh index f512eed278..8cc86522b2 100755 --- a/t/t7450-bad-git-dotfiles.sh +++ b/t/t7450-bad-git-dotfiles.sh @@ -220,17 +220,19 @@ check_dotx_symlink () { ) ' - test -n "$refuse_index" && - test_expect_success "refuse to load symlinked $name into index ($type)" ' - test_must_fail \ - git -C $dir \ - -c core.protectntfs \ - -c core.protecthfs \ - read-tree $tree 2>err && - grep "invalid path.*$name" err && - git -C $dir ls-files -s >out && - test_must_be_empty out - ' + if test -n "$refuse_index" + then + test_expect_success "refuse to load symlinked $name into index ($type)" ' + test_must_fail \ + git -C $dir \ + -c core.protectntfs \ + -c core.protecthfs \ + read-tree $tree 2>err && + grep "invalid path.*$name" err && + git -C $dir ls-files -s >out && + test_must_be_empty out + ' + fi } check_dotx_symlink gitmodules vanilla .gitmodules diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a5e21bf8bf..1167b835a4 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -773,8 +773,8 @@ test_expect_success TTY 'status --porcelain ignores color.status' ' ' # recover unconditionally from color tests -git config --unset color.status -git config --unset color.ui +git config --unset color.status || : +git config --unset color.ui || : test_expect_success 'status --porcelain respects -b' ' diff --git a/t/t9138-git-svn-authors-prog.sh b/t/t9138-git-svn-authors-prog.sh index 784ec7fc2d..5bb38cb23a 100755 --- a/t/t9138-git-svn-authors-prog.sh +++ b/t/t9138-git-svn-authors-prog.sh @@ -68,8 +68,8 @@ test_expect_success 'authors-file overrode authors-prog' ' ) ' -git --git-dir=x/.git config --unset svn.authorsfile -git --git-dir=x/.git config --unset svn.authorsprog +git --git-dir=x/.git config --unset svn.authorsfile || : +git --git-dir=x/.git config --unset svn.authorsprog || : test_expect_success 'authors-prog imported user without email' ' svn mkdir -m gg --username gg-hermit "$svnrepo"/gg && diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 14cbe96527..581cf3d28f 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -11,8 +11,7 @@ if ! test_have_prereq PERL; then test_done fi -cvs >/dev/null 2>&1 -if test $? -ne 1 +if ! cvs version >/dev/null 2>&1 then skip_all='skipping git cvsexportcommit tests, cvs not found' test_done diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index e499c7f955..4b45398bab 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -17,12 +17,13 @@ if ! test_have_prereq PERL; then skip_all='skipping git cvsserver tests, perl not available' test_done fi -cvs >/dev/null 2>&1 -if test $? -ne 1 + +if ! cvs version >/dev/null 2>&1 then skip_all='skipping git-cvsserver tests, cvs not found' test_done fi + perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { skip_all='skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index a34805acdc..6b4cbb1651 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -60,12 +60,12 @@ check_status_options() { return $stat } -cvs >/dev/null 2>&1 -if test $? -ne 1 +if ! cvs version >/dev/null 2>&1 then skip_all='skipping git-cvsserver tests, cvs not found' test_done fi + if ! test_have_prereq PERL then skip_all='skipping git-cvsserver tests, perl not available' diff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh index 2ee41f9443..65f2ceedec 100755 --- a/t/t9402-git-cvsserver-refs.sh +++ b/t/t9402-git-cvsserver-refs.sh @@ -68,12 +68,12 @@ check_diff() { ######### -cvs >/dev/null 2>&1 -if test $? -ne 1 +if ! cvs version >/dev/null 2>&1 then skip_all='skipping git-cvsserver tests, cvs not found' test_done fi + if ! test_have_prereq PERL then skip_all='skipping git-cvsserver tests, perl not available' diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 2f9a597ec7..28f61f08fb 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -590,12 +590,10 @@ test_expect_success '__gitcomp - doesnt fail because of invalid variable name' ' __gitcomp "$invalid_variable_name" ' -read -r -d "" refs <<-\EOF -main +refs='main maint next -seen -EOF +seen' test_expect_success '__gitcomp_nl - trailing space' ' test_gitcomp_nl "m" "$refs" <<-EOF diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index f3af10fb7e..502bb0ddcb 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1195,8 +1195,9 @@ test_must_fail () { echo >&7 "test_must_fail: only 'git' is allowed: $*" return 1 fi - "$@" 2>&7 - exit_code=$? + + exit_code=0; "$@" 2>&7 || exit_code=$? + if test $exit_code -eq 0 && ! list_contains "$_test_ok" success then echo >&4 "test_must_fail: command succeeded: $*" @@ -1247,8 +1248,7 @@ test_might_fail () { test_expect_code () { want_code=$1 shift - "$@" 2>&7 - exit_code=$? + exit_code=0; "$@" 2>&7 || exit_code=$? if test $exit_code = $want_code then return 0 @@ -1512,7 +1512,7 @@ test_when_finished () { test "${BASH_SUBSHELL-0}" = 0 || BUG "test_when_finished does nothing in a subshell" test_cleanup="{ $* - } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" + } || eval_ret=\$?; $test_cleanup" } # This function can be used to schedule some commands to be run @@ -1540,7 +1540,7 @@ test_atexit () { test "${BASH_SUBSHELL-0}" = 0 || BUG "test_atexit does nothing in a subshell" test_atexit_cleanup="{ $* - } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_atexit_cleanup" + } || eval_ret=\$?; $test_atexit_cleanup" } # Deprecated wrapper for "git init", use "git init" directly instead diff --git a/t/test-lib.sh b/t/test-lib.sh index 70fd3e9baf..cded7bd693 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,31 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see https://www.gnu.org/licenses/ . +# Enable the use of errexit so that any unexpected failures will cause us to +# abort tests, even when outside of a specific test case. +# +# Note that we only enable this on Bash 5 and newer, or when explicitly +# requested by the user via `GIT_TEST_USE_SET_E=true`. This ib secause `set -e` +# has wildly different behaviour across shells. The list of default-enabled +# shells may be extended going forward. +if test -z "$GIT_TEST_USE_SET_E" && test "${BASH_VERSINFO:=0}" -ge 5 +then + GIT_TEST_USE_SET_E=true +fi + +# We cannot use `test-tool env-helper` here, as it's not yet available. +case "${GIT_TEST_USE_SET_E:-false}" in +1|on|true|yes) + set -e + ;; +0|off|false|no) + ;; +*) + echo "GIT_TEST_USE_SET_E requires a boolean" >&2 + exit 1 + ;; +esac + # 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" @@ -143,8 +168,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME ################################################################ # It appears that people try to run tests without building... GIT_BINARY="${GIT_TEST_INSTALLED:-$GIT_BUILD_DIR}/git$X" -"$GIT_BINARY" >/dev/null -if test $? != 1 + +if ! "$GIT_BINARY" version >/dev/null then if test -n "$GIT_TEST_INSTALLED" then @@ -454,8 +479,10 @@ then # from any previous runs. >"$GIT_TEST_TEE_OUTPUT_FILE" - (GIT_TEST_TEE_STARTED=done ${TEST_SHELL_PATH} "$0" "$@" 2>&1; - echo $? >"$TEST_RESULTS_BASE.exit") | tee -a "$GIT_TEST_TEE_OUTPUT_FILE" + ( + ret=0 && GIT_TEST_TEE_STARTED=done ${TEST_SHELL_PATH} "$0" "$@" 2>&1 || ret=$? + echo "$ret" >"$TEST_RESULTS_BASE.exit" + ) | tee -a "$GIT_TEST_TEE_OUTPUT_FILE" test "$(cat "$TEST_RESULTS_BASE.exit")" = 0 exit fi