Merge branch 'mb/fetch-call-a-non-branch-a-ref'
[gitweb.git] / t / test-lib.sh
index afd3053f96b789a73274217b384d245583500c04..b7d7100c4e5c060c1956e5d4f372fa1fa6ee8c85 100644 (file)
@@ -2,6 +2,18 @@
 #
 # Copyright (c) 2005 Junio C Hamano
 #
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see http://www.gnu.org/licenses/ .
 
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
@@ -30,41 +42,42 @@ TZ=UTC
 TERM=dumb
 export LANG LC_ALL PAGER TERM TZ
 EDITOR=:
-unset VISUAL
-unset GIT_EDITOR
-unset AUTHOR_DATE
-unset AUTHOR_EMAIL
-unset AUTHOR_NAME
-unset COMMIT_AUTHOR_EMAIL
-unset COMMIT_AUTHOR_NAME
-unset EMAIL
-unset GIT_ALTERNATE_OBJECT_DIRECTORIES
-unset GIT_AUTHOR_DATE
+# 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
+# deriving from the command substitution clustered with the other
+# ones.
+unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
+       my @env = keys %ENV;
+       my $ok = join("|", qw(
+               TRACE
+               DEBUG
+               USE_LOOKUP
+               TEST
+               .*_TEST
+               PROVE
+               VALGRIND
+               PERF_AGGREGATING_LATER
+       ));
+       my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
+       print join("\n", @vars);
+')
 GIT_AUTHOR_EMAIL=author@example.com
 GIT_AUTHOR_NAME='A U Thor'
-unset GIT_COMMITTER_DATE
 GIT_COMMITTER_EMAIL=committer@example.com
 GIT_COMMITTER_NAME='C O Mitter'
-unset GIT_DIFF_OPTS
-unset GIT_DIR
-unset GIT_WORK_TREE
-unset GIT_EXTERNAL_DIFF
-unset GIT_INDEX_FILE
-unset GIT_OBJECT_DIRECTORY
-unset GIT_CEILING_DIRECTORIES
-unset SHA1_FILE_DIRECTORIES
-unset SHA1_FILE_DIRECTORY
 GIT_MERGE_VERBOSITY=5
-export GIT_MERGE_VERBOSITY
+GIT_MERGE_AUTOEDIT=no
+export GIT_MERGE_VERBOSITY GIT_MERGE_AUTOEDIT
 export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 export EDITOR
-GIT_TEST_CMP=${GIT_TEST_CMP:-diff -u}
 
 # Protect ourselves from common misconfiguration to export
 # CDPATH into the environment
 unset CDPATH
 
+unset GREP_OPTIONS
+
 case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
        1|2|true)
                echo "* warning: Some tests will not work if GIT_TRACE" \
@@ -80,6 +93,15 @@ esac
 _x05='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x05$_x05"
 
+# Zero SHA-1
+_z40=0000000000000000000000000000000000000000
+
+# Line feed
+LF='
+'
+
+export _x05 _x40 _z40 LF
+
 # Each test should start with something like this, after copyright notices:
 #
 # test_description='Description of this test...
@@ -110,14 +132,13 @@ do
        -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
                verbose=t; shift ;;
        -q|--q|--qu|--qui|--quie|--quiet)
-               quiet=t; shift ;;
+               # Ignore --quiet under a TAP::Harness. Saying how many tests
+               # passed without the ok/not ok details is always an error.
+               test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
        --with-dashes)
                with_dashes=t; shift ;;
        --no-color)
                color=; shift ;;
-       --no-python)
-               # noop now...
-               shift ;;
        --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
                valgrind=t; verbose=t; shift ;;
        --tee)
@@ -143,7 +164,7 @@ if test -n "$color"; then
                        *) test -n "$quiet" && return;;
                esac
                shift
-               printf "%s" "$*"
+               printf "%s" "$*"
                tput sgr0
                echo
                )
@@ -152,7 +173,7 @@ else
        say_color() {
                test -z "$1" && test -n "$quiet" && return
                shift
-               echo "$*"
+               echo "$*"
        }
 fi
 
@@ -176,6 +197,7 @@ then
 fi
 
 exec 5>&1
+exec 6<&0
 if test "$verbose" = "t"
 then
        exec 4>&2 3>&1
@@ -189,6 +211,8 @@ test_fixed=0
 test_broken=0
 test_success=0
 
+test_external_has_tap=0
+
 die () {
        code=$?
        if test -n "$GIT_EXIT_OK"
@@ -203,154 +227,60 @@ die () {
 GIT_EXIT_OK=
 trap 'die' EXIT
 
-# The semantics of the editor variables are that of invoking
-# sh -c "$EDITOR \"$@\"" files ...
-#
-# If our trash directory contains shell metacharacters, they will be
-# interpreted if we just set $EDITOR directly, so do a little dance with
-# environment variables to work around this.
-#
-# In particular, quoting isn't enough, as the path may contain the same quote
-# that we're using.
-test_set_editor () {
-       FAKE_EDITOR="$1"
-       export FAKE_EDITOR
-       EDITOR='"$FAKE_EDITOR"'
-       export 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'
-}
-
-q_to_nul () {
-       perl -pe 'y/Q/\000/'
-}
-
-q_to_cr () {
-       tr Q '\015'
-}
-
-append_cr () {
-       sed -e 's/$/Q/' | tr Q '\015'
-}
-
-remove_cr () {
-       tr '\015' Q | sed -e 's/Q$//'
-}
-
-test_tick () {
-       if test -z "${test_tick+set}"
-       then
-               test_tick=1112911993
-       else
-               test_tick=$(($test_tick + 60))
-       fi
-       GIT_COMMITTER_DATE="$test_tick -0700"
-       GIT_AUTHOR_DATE="$test_tick -0700"
-       export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
-}
-
-# Call test_commit with the arguments "<message> [<file> [<contents>]]"
-#
-# This will commit a file with the given contents and the given commit
-# message.  It will also add a tag with <message> as name.
-#
-# Both <file> and <contents> default to <message>.
-
-test_commit () {
-       file=${2:-"$1.t"}
-       echo "${3-$1}" > "$file" &&
-       git add "$file" &&
-       test_tick &&
-       git commit -m "$1" &&
-       git tag "$1"
-}
-
-# Call test_merge with the arguments "<message> <commit>", where <commit>
-# can be a tag pointing to the commit-to-merge.
-
-test_merge () {
-       test_tick &&
-       git merge -m "$1" "$2" &&
-       git tag "$1"
-}
-
-# This function helps systems where core.filemode=false is set.
-# Use it instead of plain 'chmod +x' to set or unset the executable bit
-# of a file in the working directory and add it to the index.
-
-test_chmod () {
-       chmod "$@" &&
-       git update-index --add "--chmod=$@"
-}
-
-# Use test_set_prereq to tell that a particular prerequisite is available.
-# The prerequisite can later be checked for in two ways:
-#
-# - Explicitly using test_have_prereq.
-#
-# - Implicitly by specifying the prerequisite tag in the calls to
-#   test_expect_{success,failure,code}.
-#
-# The single parameter is the prerequisite tag (a simple word, in all
-# capital letters by convention).
-
-test_set_prereq () {
-       satisfied="$satisfied$1 "
-}
-satisfied=" "
-
-test_have_prereq () {
-       case $satisfied in
-       *" $1 "*)
-               : yes, have it ;;
-       *)
-               ! : nope ;;
-       esac
-}
+# The user-facing functions are loaded from a separate file so that
+# test_perf subshells can have them too
+. "${TEST_DIRECTORY:-.}"/test-lib-functions.sh
 
 # You are not expected to call test_ok_ and test_failure_ directly, use
 # the text_expect_* functions instead.
 
 test_ok_ () {
        test_success=$(($test_success + 1))
-       say_color "" "  ok $test_count: $@"
+       say_color "" "ok $test_count - $@"
 }
 
 test_failure_ () {
        test_failure=$(($test_failure + 1))
-       say_color error "FAIL $test_count: $1"
+       say_color error "not ok - $test_count $1"
        shift
-       echo "$@" | sed -e 's/^/        /'
+       echo "$@" | sed -e 's/^/#       /'
        test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
 }
 
 test_known_broken_ok_ () {
        test_fixed=$(($test_fixed+1))
-       say_color "" "  FIXED $test_count: $@"
+       say_color "" "ok $test_count - $@ # TODO known breakage"
 }
 
 test_known_broken_failure_ () {
        test_broken=$(($test_broken+1))
-       say_color skip "  still broken $test_count: $@"
+       say_color skip "not ok $test_count - $@ # TODO known breakage"
 }
 
 test_debug () {
        test "$debug" = "" || eval "$1"
 }
 
+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 "$*"
+}
+
 test_run_ () {
-       eval >&3 2>&4 "$1"
-       eval_ret="$?"
-       return 0
+       test_cleanup=:
+       expecting_failure=$2
+       test_eval_ "$1"
+       eval_ret=$?
+
+       if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"
+       then
+               test_eval_ "$test_cleanup"
+       fi
+       if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
+               echo ""
+       fi
+       return "$eval_ret"
 }
 
 test_skip () {
@@ -361,17 +291,24 @@ test_skip () {
                case $this_test.$test_count in
                $skp)
                        to_skip=t
+                       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 "skip $test_count: $1"
+               say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
                : true
                ;;
        *)
@@ -380,204 +317,64 @@ test_skip () {
        esac
 }
 
-test_expect_failure () {
-       test "$#" = 3 && { prereq=$1; shift; } || prereq=
-       test "$#" = 2 ||
-       error "bug in the test script: not 2 or 3 parameters to test-expect-failure"
-       if ! test_skip "$@"
-       then
-               say >&3 "checking known breakage: $2"
-               test_run_ "$2"
-               if [ "$?" = 0 -a "$eval_ret" = 0 ]
-               then
-                       test_known_broken_ok_ "$1"
-               else
-                       test_known_broken_failure_ "$1"
-               fi
-       fi
-       echo >&3 ""
+# stub; perf-lib overrides it
+test_at_end_hook_ () {
+       :
 }
 
-test_expect_success () {
-       test "$#" = 3 && { prereq=$1; shift; } || prereq=
-       test "$#" = 2 ||
-       error "bug in the test script: not 2 or 3 parameters to test-expect-success"
-       if ! test_skip "$@"
-       then
-               say >&3 "expecting success: $2"
-               test_run_ "$2"
-               if [ "$?" = 0 -a "$eval_ret" = 0 ]
-               then
-                       test_ok_ "$1"
-               else
-                       test_failure_ "$@"
-               fi
-       fi
-       echo >&3 ""
-}
+test_done () {
+       GIT_EXIT_OK=t
 
-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 ""
-}
+       if test -z "$HARNESS_ACTIVE"; then
+               test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
+               mkdir -p "$test_results_dir"
+               test_results_path="$test_results_dir/${0%.sh}-$$.counts"
 
-# 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
-# in non-verbose mode, and announces the external script with "* run
-# <n>: ..." before running it.  When providing relative paths, keep in
-# mind that all scripts run in "trash directory".
-# 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 "$#" = 3 ||
-       error >&5 "bug in the test script: not 3 or 4 parameters to test_external"
-       descr="$1"
-       shift
-       if ! test_skip "$descr" "$@"
-       then
-               # Announce the script to reduce confusion about the
-               # test output that follows.
-               say_color "" " run $test_count: $descr ($*)"
-               # Run command; redirect its stderr to &4 as in
-               # test_run_, but keep its stdout on our stdout even in
-               # non-verbose mode.
-               "$@" 2>&4
-               if [ "$?" = 0 ]
-               then
-                       test_ok_ "$descr"
-               else
-                       test_failure_ "$descr" "$@"
-               fi
-       fi
-}
+               cat >>"$test_results_path" <<-EOF
+               total $test_count
+               success $test_success
+               fixed $test_fixed
+               broken $test_broken
+               failed $test_failure
 
-# Like test_external, but in addition tests that the command generated
-# no output on stderr.
-test_external_without_stderr () {
-       # The temporary file has no (and must have no) security
-       # implications.
-       tmp="$TMPDIR"; if [ -z "$tmp" ]; then tmp=/tmp; fi
-       stderr="$tmp/git-external-stderr.$$.tmp"
-       test_external "$@" 4> "$stderr"
-       [ -f "$stderr" ] || error "Internal error: $stderr disappeared."
-       descr="no stderr: $1"
-       shift
-       say >&3 "expecting no stderr from previous command"
-       if [ ! -s "$stderr" ]; then
-               rm "$stderr"
-               test_ok_ "$descr"
-       else
-               if [ "$verbose" = t ]; then
-                       output=`echo; echo Stderr is:; cat "$stderr"`
-               else
-                       output=
-               fi
-               # rm first in case test_failure exits.
-               rm "$stderr"
-               test_failure_ "$descr" "$@" "$output"
+               EOF
        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:
-#
-#      test_expect_success 'complain and die' '
-#           do something &&
-#           do something else &&
-#          test_must_fail git checkout ../outerspace
-#      '
-#
-# Writing this as "! git checkout ../outerspace" is wrong, because
-# the failure could be due to a segv.  We want a controlled failure.
-
-test_must_fail () {
-       "$@"
-       test $? -gt 0 -a $? -le 129 -o $? -gt 192
-}
-
-# test_cmp is a helper function to compare actual and expected output.
-# You can use it like:
-#
-#      test_expect_success 'foo works' '
-#              echo expected >expected &&
-#              foo >actual &&
-#              test_cmp expected actual
-#      '
-#
-# This could be written as either "cmp" or "diff -u", but:
-# - cmp's output is not nearly as easy to read as diff -u
-# - not all diff versions understand "-u"
-
-test_cmp() {
-       $GIT_TEST_CMP "$@"
-}
-
-# Most tests can use the created repository, but some may need to create more.
-# Usage: test_create_repo <directory>
-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"
-}
-
-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}-$$"
-
-       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 "$test_fixed" != 0
        then
-               say_color pass "fixed $test_fixed known breakage(s)"
+               say_color pass "fixed $test_fixed known breakage(s)"
        fi
        if test "$test_broken" != 0
        then
-               say_color error "still have $test_broken known breakage(s)"
+               say_color error "still have $test_broken known breakage(s)"
                msg="remaining $(($test_count-$test_broken)) test(s)"
        else
                msg="$test_count test(s)"
        fi
        case "$test_failure" in
        0)
-               say_color pass "passed all $msg"
+               # Maybe print SKIP message
+               [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
+
+               if test $test_external_has_tap -eq 0; then
+                       say_color pass "# passed all $msg"
+                       say "1..$test_count$skip_all"
+               fi
 
                test -d "$remove_trash" &&
                cd "$(dirname "$remove_trash")" &&
                rm -rf "$(basename "$remove_trash")"
 
+               test_at_end_hook_
+
                exit 0 ;;
 
        *)
-               say_color error "failed $test_failure among $msg"
+               if test $test_external_has_tap -eq 0; then
+                       say_color error "# failed $test_failure among $msg"
+                       say "1..$test_count"
+               fi
+
                exit 1 ;;
 
        esac
@@ -585,7 +382,21 @@ 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
+if test -z "$TEST_OUTPUT_DIRECTORY"
+then
+       # Similarly, override this to store the test-results subdir
+       # elsewhere
+       TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
+fi
+GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+
 if test -n "$valgrind"
 then
        make_symlink () {
@@ -608,11 +419,16 @@ then
        }
 
        make_valgrind_symlink () {
-               # handle only executables
-               test -x "$1" || return
+               # handle only executables, unless they are shell libraries that
+               # need to be in the exec-path.  We will just use "#!" as a
+               # guess for a shell-script, since we have no idea what the user
+               # may have configured as the shell path.
+               test -x "$1" ||
+               test "#!" = "$(head -c 2 <"$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" &&
@@ -631,10 +447,12 @@ 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
+       # special-case the mergetools loadables
+       make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools"
        OLDIFS=$IFS
        IFS=:
        for path in $PATH
@@ -652,10 +470,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"
@@ -663,35 +481,45 @@ 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_ATTR_NOSYSTEM=1
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
 
-. ../GIT-BUILD-OPTIONS
+. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
 
-GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
+if test -z "$GIT_TEST_CMP"
+then
+       if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT"
+       then
+               GIT_TEST_CMP="$DIFF -c"
+       else
+               GIT_TEST_CMP="$DIFF -u"
+       fi
+fi
+
+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
@@ -702,7 +530,7 @@ test="trash directory.$(basename "$0" .sh)"
 test -n "$root" && test="$root/$test"
 case "$test" in
 /*) TRASH_DIRECTORY="$test" ;;
- *) TRASH_DIRECTORY="$TEST_DIRECTORY/$test" ;;
+ *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$test" ;;
 esac
 test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY
 rm -fr "$test" || {
@@ -711,7 +539,14 @@ rm -fr "$test" || {
        exit 1
 }
 
-test_create_repo "$test"
+HOME="$TRASH_DIRECTORY"
+export HOME
+
+if test -z "$TEST_NO_CREATE_REPO"; then
+       test_create_repo "$test"
+else
+       mkdir -p "$test"
+fi
 # Use -P to resolve symlinks in our working directory so that the cwd
 # in subprocesses like git equals our $PWD (for pathname comparisons).
 cd -P "$test" || exit 1
@@ -720,18 +555,10 @@ this_test=${0##*/}
 this_test=${this_test%%-*}
 for skp in $GIT_SKIP_TESTS
 do
-       to_skip=
-       for skp in $GIT_SKIP_TESTS
-       do
-               case "$this_test" in
-               $skp)
-                       to_skip=t
-               esac
-       done
-       case "$to_skip" in
-       t)
+       case "$this_test" in
+       $skp)
                say_color skip >&3 "skipping test $this_test altogether"
-               say_color skip "skip all tests in $this_test"
+               skip_all="skip all tests in $this_test"
                test_done
        esac
 done
@@ -771,17 +598,68 @@ 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 SED_STRIPS_CR
+       ;;
+*CYGWIN*)
+       test_set_prereq POSIXPERM
+       test_set_prereq EXECKEEPSPID
+       test_set_prereq NOT_MINGW
+       test_set_prereq SED_STRIPS_CR
        ;;
 *)
        test_set_prereq POSIXPERM
        test_set_prereq BSLASHPSPEC
        test_set_prereq EXECKEEPSPID
+       test_set_prereq NOT_MINGW
        ;;
 esac
 
 test -z "$NO_PERL" && test_set_prereq PERL
 test -z "$NO_PYTHON" && test_set_prereq PYTHON
+test -n "$USE_LIBPCRE" && test_set_prereq LIBPCRE
+test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
+
+# Can we rely on git's output in the C locale?
+if test -n "$GETTEXT_POISON"
+then
+       GIT_GETTEXT_POISON=YesPlease
+       export GIT_GETTEXT_POISON
+       test_set_prereq GETTEXT_POISON
+else
+       test_set_prereq C_LOCALE_OUTPUT
+fi
+
+# Use this instead of test_cmp to compare files that contain expected and
+# actual output from git commands that can be translated.  When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ncmp () {
+       test -n "$GETTEXT_POISON" || test_cmp "$@"
+}
+
+# Use this instead of "grep expected-string actual" to see if the
+# output from a git command that can be translated either contains an
+# expected string, or does not contain an unwanted one.  When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ngrep () {
+       if test -n "$GETTEXT_POISON"
+       then
+           : # pretend success
+       elif test "x!" = "x$1"
+       then
+               shift
+               ! grep "$@"
+       else
+               grep "$@"
+       fi
+}
 
 # 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