diff options
Diffstat (limited to 't/test-lib.sh')
-rw-r--r-- | t/test-lib.sh | 326 |
1 files changed, 258 insertions, 68 deletions
diff --git a/t/test-lib.sh b/t/test-lib.sh index e8f21d577c..48fa516004 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -238,14 +238,51 @@ test_set_editor () { } test_decode_color () { - sed -e 's/.\[1m/<WHITE>/g' \ - -e 's/.\[31m/<RED>/g' \ - -e 's/.\[32m/<GREEN>/g' \ - -e 's/.\[33m/<YELLOW>/g' \ - -e 's/.\[34m/<BLUE>/g' \ - -e 's/.\[35m/<MAGENTA>/g' \ - -e 's/.\[36m/<CYAN>/g' \ - -e 's/.\[m/<RESET>/g' + awk ' + function name(n) { + if (n == 0) return "RESET"; + if (n == 1) return "BOLD"; + if (n == 30) return "BLACK"; + if (n == 31) return "RED"; + if (n == 32) return "GREEN"; + if (n == 33) return "YELLOW"; + if (n == 34) return "BLUE"; + if (n == 35) return "MAGENTA"; + if (n == 36) return "CYAN"; + if (n == 37) return "WHITE"; + if (n == 40) return "BLACK"; + if (n == 41) return "BRED"; + if (n == 42) return "BGREEN"; + if (n == 43) return "BYELLOW"; + if (n == 44) return "BBLUE"; + if (n == 45) return "BMAGENTA"; + if (n == 46) return "BCYAN"; + if (n == 47) return "BWHITE"; + } + { + while (match($0, /\x1b\[[0-9;]*m/) != 0) { + printf "%s<", substr($0, 1, RSTART-1); + codes = substr($0, RSTART+2, RLENGTH-3); + if (length(codes) == 0) + printf "%s", name(0) + else { + n = split(codes, ary, ";"); + sep = ""; + for (i = 1; i <= n; i++) { + printf "%s%s", sep, name(ary[i]); + sep = ";" + } + } + printf ">"; + $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1); + } + print + } + ' +} + +nul_to_q () { + perl -pe 'y/\000/Q/' } q_to_nul () { @@ -256,6 +293,10 @@ q_to_cr () { tr Q '\015' } +q_to_tab () { + tr Q '\011' +} + append_cr () { sed -e 's/$/Q/' | tr Q '\015' } @@ -264,6 +305,17 @@ remove_cr () { tr '\015' Q | sed -e 's/Q$//' } +# In some bourne shell implementations, the "unset" builtin returns +# nonzero status when a variable to be unset was not set in the first +# place. +# +# Use sane_unset when that should not be considered an error. + +sane_unset () { + unset "$@" + return 0 +} + test_tick () { if test -z "${test_tick+set}" then @@ -327,12 +379,44 @@ test_set_prereq () { satisfied=" " test_have_prereq () { - case $satisfied in - *" $1 "*) - : yes, have it ;; - *) - ! : nope ;; + # prerequisites can be concatenated with ',' + save_IFS=$IFS + IFS=, + set -- $* + IFS=$save_IFS + + total_prereq=0 + ok_prereq=0 + missing_prereq= + + for prerequisite + do + total_prereq=$(($total_prereq + 1)) + case $satisfied in + *" $prerequisite "*) + ok_prereq=$(($ok_prereq + 1)) + ;; + *) + # Keep a list of missing prerequisites + if test -z "$missing_prereq" + then + missing_prereq=$prerequisite + else + missing_prereq="$prerequisite,$missing_prereq" + fi + esac + done + + test $total_prereq = $ok_prereq +} + +test_declared_prereq () { + case ",$test_prereq," in + *,$1,*) + return 0 + ;; esac + return 1 } # You are not expected to call test_ok_ and test_failure_ directly, use @@ -387,15 +471,21 @@ test_skip () { break esac done - if test -z "$to_skip" && test -n "$prereq" && - ! test_have_prereq "$prereq" + 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 + say_color skip >&3 "skipping test: $@" - say_color skip "ok $test_count # skip $1" + say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" : true ;; *) @@ -405,9 +495,10 @@ test_skip () { } test_expect_failure () { - test "$#" = 3 && { prereq=$1; shift; } || prereq= + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test-expect-failure" + export test_prereq if ! test_skip "$@" then say >&3 "checking known breakage: $2" @@ -423,9 +514,10 @@ test_expect_failure () { } test_expect_success () { - test "$#" = 3 && { prereq=$1; shift; } || prereq= + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test-expect-success" + export test_prereq if ! test_skip "$@" then say >&3 "expecting success: $2" @@ -440,24 +532,6 @@ test_expect_success () { echo >&3 "" } -test_expect_code () { - test "$#" = 4 && { prereq=$1; shift; } || prereq= - test "$#" = 3 || - error "bug in the test script: not 3 or 4 parameters to test-expect-code" - if ! test_skip "$@" - then - say >&3 "expecting exit code $1: $3" - test_run_ "$3" - if [ "$?" = 0 -a "$eval_ret" = "$1" ] - then - test_ok_ "$2" - else - test_failure_ "$@" - fi - fi - echo >&3 "" -} - # test_external runs external test scripts that provide continuous # test output about their progress, and succeeds/fails on # zero/non-zero exit code. It outputs the test output on stdout even @@ -467,11 +541,12 @@ test_expect_code () { # Usage: test_external description command arguments... # Example: test_external 'Perl API' perl ../path/to/test.pl test_external () { - test "$#" = 4 && { prereq=$1; shift; } || prereq= + test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 3 || error >&5 "bug in the test script: not 3 or 4 parameters to test_external" descr="$1" shift + export test_prereq if ! test_skip "$descr" "$@" then # Announce the script to reduce confusion about the @@ -541,6 +616,60 @@ test_external_without_stderr () { fi } +# debugging-friendly alternatives to "test [-f|-d|-e]" +# The commands test the existence or non-existence of $1. $2 can be +# given to provide a more precise diagnosis. +test_path_is_file () { + if ! [ -f "$1" ] + then + echo "File $1 doesn't exist. $*" + false + fi +} + +test_path_is_dir () { + if ! [ -d "$1" ] + then + echo "Directory $1 doesn't exist. $*" + false + fi +} + +test_path_is_missing () { + if [ -e "$1" ] + then + echo "Path exists:" + ls -ld "$1" + if [ $# -ge 1 ]; then + echo "$*" + fi + false + fi +} + +# test_line_count checks that a file has the number of lines it +# ought to. For example: +# +# test_expect_success 'produce exactly one line of output' ' +# do something >output && +# test_line_count = 1 output +# ' +# +# is like "test $(wc -l <output) = 1" except that it passes the +# output through when the number of lines is wrong. + +test_line_count () { + if test $# != 3 + then + error "bug in the test script: not 3 parameters to test_line_count" + elif ! test $(wc -l <"$3") "$1" "$2" + then + echo "test_line_count: line count for $3 !$1 $2" + cat "$3" + return 1 + fi +} + # This is not among top-level (test_expect_success | test_expect_failure) # but is a prefix that can be used in the test script, like: # @@ -555,7 +684,18 @@ test_external_without_stderr () { test_must_fail () { "$@" - test $? -gt 0 -a $? -le 129 -o $? -gt 192 + exit_code=$? + if test $exit_code = 0; then + echo >&2 "test_must_fail: command succeeded: $*" + return 1 + elif test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_must_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_must_fail: command not found: $*" + return 1 + fi + return 0 } # Similar to test_must_fail, but tolerates success, too. This is @@ -571,7 +711,37 @@ test_must_fail () { test_might_fail () { "$@" - test $? -ge 0 -a $? -le 129 -o $? -gt 192 + exit_code=$? + if test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_might_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_might_fail: command not found: $*" + return 1 + fi + return 0 +} + +# Similar to test_must_fail and test_might_fail, but check that a +# given command exited with a given exit code. Meant to be used as: +# +# test_expect_success 'Merge with d/f conflicts' ' +# test_expect_code 1 git merge "merge msg" B master +# ' + +test_expect_code () { + want_code=$1 + shift + "$@" + exit_code=$? + if test $exit_code = $want_code + then + echo >&2 "test_expect_code: command exited with $exit_code: $*" + return 0 + else + echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" + return 1 + fi } # test_cmp is a helper function to compare actual and expected output. @@ -621,28 +791,31 @@ test_when_finished () { test_create_repo () { test "$#" = 1 || error "bug in the test script: not 1 parameter to test-create-repo" - owd=`pwd` repo="$1" mkdir -p "$repo" - cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$TEST_DIRECTORY/../templates/blt/" >&3 2>&4 || - error "cannot run git init -- have you built things yet?" - mv .git/hooks .git/hooks-disabled - cd "$owd" + ( + cd "$repo" || error "Cannot setup test environment" + "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || + error "cannot run git init -- have you built things yet?" + mv .git/hooks .git/hooks-disabled + ) || exit } test_done () { GIT_EXIT_OK=t - test_results_dir="$TEST_DIRECTORY/test-results" - mkdir -p "$test_results_dir" - test_results_path="$test_results_dir/${0%.sh}-$$.counts" - echo "total $test_count" >> $test_results_path - echo "success $test_success" >> $test_results_path - echo "fixed $test_fixed" >> $test_results_path - echo "broken $test_broken" >> $test_results_path - echo "failed $test_failure" >> $test_results_path - echo "" >> $test_results_path + if test -z "$HARNESS_ACTIVE"; then + test_results_dir="$TEST_DIRECTORY/test-results" + mkdir -p "$test_results_dir" + test_results_path="$test_results_dir/${0%.sh}-$$.counts" + + echo "total $test_count" >> $test_results_path + echo "success $test_success" >> $test_results_path + echo "fixed $test_fixed" >> $test_results_path + echo "broken $test_broken" >> $test_results_path + echo "failed $test_failure" >> $test_results_path + echo "" >> $test_results_path + fi if test "$test_fixed" != 0 then @@ -684,7 +857,15 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. -TEST_DIRECTORY=$(pwd) +if test -z "$TEST_DIRECTORY" +then + # We allow tests to override this, in case they want to run tests + # outside of t/, e.g. for running tests on the test library + # itself. + TEST_DIRECTORY=$(pwd) +fi +GIT_BUILD_DIR="$TEST_DIRECTORY"/.. + if test -n "$valgrind" then make_symlink () { @@ -711,7 +892,7 @@ then test -x "$1" || return base=$(basename "$1") - symlink_target=$TEST_DIRECTORY/../$base + symlink_target=$GIT_BUILD_DIR/$base # do not override scripts if test -x "$symlink_target" && test ! -d "$symlink_target" && @@ -730,7 +911,7 @@ then # override all git executables in TEST_DIRECTORY/.. GIT_VALGRIND=$TEST_DIRECTORY/valgrind mkdir -p "$GIT_VALGRIND"/bin - for file in $TEST_DIRECTORY/../git* $TEST_DIRECTORY/../test-* + for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-* do make_valgrind_symlink $file done @@ -751,10 +932,10 @@ then elif test -n "$GIT_TEST_INSTALLED" ; then GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || error "Cannot run git from $GIT_TEST_INSTALLED." - PATH=$GIT_TEST_INSTALLED:$TEST_DIRECTORY/..:$PATH + PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR:$PATH GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH} else # normal case, use ../bin-wrappers only unless $with_dashes: - git_bin_dir="$TEST_DIRECTORY/../bin-wrappers" + git_bin_dir="$GIT_BUILD_DIR/bin-wrappers" if ! test -x "$git_bin_dir/git" ; then if test -z "$with_dashes" ; then say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH" @@ -762,18 +943,18 @@ else # normal case, use ../bin-wrappers only unless $with_dashes: with_dashes=t fi PATH="$git_bin_dir:$PATH" - GIT_EXEC_PATH=$TEST_DIRECTORY/.. + GIT_EXEC_PATH=$GIT_BUILD_DIR if test -n "$with_dashes" ; then - PATH="$TEST_DIRECTORY/..:$PATH" + PATH="$GIT_BUILD_DIR:$PATH" fi fi -GIT_TEMPLATE_DIR=$(pwd)/../templates/blt +GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt unset GIT_CONFIG GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_NOGLOBAL=1 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL -. ../GIT-BUILD-OPTIONS +. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS if test -z "$GIT_TEST_CMP" then @@ -785,22 +966,22 @@ then fi fi -GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git +GITPERLLIB="$GIT_BUILD_DIR"/perl/blib/lib:"$GIT_BUILD_DIR"/perl/blib/arch/auto/Git export GITPERLLIB -test -d ../templates/blt || { +test -d "$GIT_BUILD_DIR"/templates/blt || { error "You haven't built things yet, have you?" } if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON" then - GITPYTHONLIB="$(pwd)/../git_remote_helpers/build/lib" + GITPYTHONLIB="$GIT_BUILD_DIR/git_remote_helpers/build/lib" export GITPYTHONLIB - test -d ../git_remote_helpers/build || { + test -d "$GIT_BUILD_DIR"/git_remote_helpers/build || { error "You haven't built git_remote_helpers yet, have you?" } fi -if ! test -x ../test-chmtime; then +if ! test -x "$GIT_BUILD_DIR"/test-chmtime; then echo >&2 'You need to build test-chmtime:' echo >&2 'Run "make test-chmtime" in the source (toplevel) directory' exit 1 @@ -825,6 +1006,9 @@ test_create_repo "$test" # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$test" || exit 1 +HOME=$(pwd) +export HOME + this_test=${0##*/} this_test=${this_test%%-*} for skp in $GIT_SKIP_TESTS @@ -872,11 +1056,13 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NOT_MINGW ;; esac @@ -886,3 +1072,7 @@ test -z "$NO_PYTHON" && test_set_prereq PYTHON # test whether the filesystem supports symbolic links ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS rm -f y + +# 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 |