Merge branch 'jc/test-say-color-avoid-echo-escape'
authorJeff King <peff@peff.net>
Thu, 25 Oct 2012 10:42:49 +0000 (06:42 -0400)
committerJeff King <peff@peff.net>
Thu, 25 Oct 2012 10:42:49 +0000 (06:42 -0400)
Recent nd/wildmatch series was the first to reveal this ancient bug
in the test scaffolding.

* jc/test-say-color-avoid-echo-escape:
  test-lib: Fix say_color () not to interpret \a\b\c in the message

1  2 
t/test-lib.sh

diff --combined t/test-lib.sh
  # 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"
 +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"/..
 +
 +################################################################
 +# It appears that people try to run tests without building...
 +"$GIT_BUILD_DIR/git" >/dev/null
 +if test $? != 1
 +then
 +      echo >&2 'error: you do not seem to have built git yet.'
 +      exit 1
 +fi
 +
 +. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
 +export PERL_PATH SHELL_PATH
 +
  # if --tee was passed, write the output not only to the terminal, but
  # additionally to the file test-results/$BASENAME.out, too.
  case "$GIT_TEST_TEE_STARTED, $* " in
@@@ -56,13 -24,16 +56,13 @@@ done,*
  *' --tee '*|*' --va'*)
        mkdir -p test-results
        BASE=test-results/$(basename "$0" .sh)
 -      (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
 +      (GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1;
         echo $? > $BASE.exit) | tee $BASE.out
        test "$(cat $BASE.exit)" = 0
        exit
        ;;
  esac
  
 -# Keep the original TERM for say_color
 -ORIGINAL_TERM=$TERM
 -
  # For repeatability, reset the environment to known value.
  LANG=C
  LC_ALL=C
@@@ -75,7 -46,7 +75,7 @@@ EDITOR=
  # /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 $(perl -e '
 +unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
        my @env = keys %ENV;
        my $ok = join("|", qw(
                TRACE
                .*_TEST
                PROVE
                VALGRIND
 +              PERF_AGGREGATING_LATER
        ));
        my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
        print join("\n", @vars);
  ')
 +unset XDG_CONFIG_HOME
  GIT_AUTHOR_EMAIL=author@example.com
  GIT_AUTHOR_NAME='A U Thor'
  GIT_COMMITTER_EMAIL=committer@example.com
  GIT_COMMITTER_NAME='C O Mitter'
  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
  
 +# Add libc MALLOC and MALLOC_PERTURB test
 +# only if we are not executing the test with valgrind
 +if expr " $GIT_TEST_OPTS " : ".* --valgrind " >/dev/null ||
 +   test -n "$TEST_NO_MALLOC_CHECK"
 +then
 +      setup_malloc_check () {
 +              : nothing
 +      }
 +      teardown_malloc_check () {
 +              : nothing
 +      }
 +else
 +      setup_malloc_check () {
 +              MALLOC_CHECK_=3 MALLOC_PERTURB_=165
 +              export MALLOC_CHECK_ MALLOC_PERTURB_
 +      }
 +      teardown_malloc_check () {
 +              unset MALLOC_CHECK_ MALLOC_PERTURB_
 +      }
 +fi
 +
  # 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" \
 -                      "is set as to trace on STDERR ! *"
 -              echo "* warning: Please set GIT_TRACE to something" \
 -                      "other than 1, 2 or true ! *"
 -              ;;
 +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 ! *"
 +      ;;
  esac
  
  # Convenience
@@@ -151,8 -98,6 +151,8 @@@ _z40=0000000000000000000000000000000000
  LF='
  '
  
 +export _x05 _x40 _z40 LF
 +
  # Each test should start with something like this, after copyright notices:
  #
  # test_description='Description of this test...
        esac
  done
  
 -if test -n "$color"; then
 +if test -n "$color"
 +then
        say_color () {
                (
                TERM=$ORIGINAL_TERM
                export TERM
                case "$1" in
 -                      error) tput bold; tput setaf 1;; # bold red
 -                      skip)  tput bold; tput setaf 2;; # bold green
 -                      pass)  tput setaf 2;;            # green
 -                      info)  tput setaf 3;;            # brown
 -                      *) test -n "$quiet" && return;;
 +              error)
 +                      tput bold; tput setaf 1;; # bold red
 +              skip)
 +                      tput bold; tput setaf 2;; # bold green
 +              pass)
 +                      tput setaf 2;;            # green
 +              info)
 +                      tput setaf 3;;            # brown
 +              *)
 +                      test -n "$quiet" && return;;
                esac
                shift
                printf "%s" "$*"
@@@ -230,7 -169,7 +230,7 @@@ els
        say_color() {
                test -z "$1" && test -n "$quiet" && return
                shift
-               echo "$*"
+               printf "%s\n" "$*"
        }
  fi
  
@@@ -284,9 -223,235 +284,9 @@@ 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 () {
 -      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, /\033\[[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 () {
 -      perl -pe 'y/Q/\000/'
 -}
 -
 -q_to_cr () {
 -      tr Q '\015'
 -}
 -
 -q_to_tab () {
 -      tr Q '\011'
 -}
 -
 -append_cr () {
 -      sed -e 's/$/Q/' | tr Q '\015'
 -}
 -
 -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
 -              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=$@"
 -}
 -
 -# Unset a configuration variable, but don't fail if it doesn't exist.
 -test_unconfig () {
 -      git config --unset-all "$@"
 -      config_status=$?
 -      case "$config_status" in
 -      5) # ok, nothing to unset
 -              config_status=0
 -              ;;
 -      esac
 -      return $config_status
 -}
 -
 -# Set git config, automatically unsetting it after the test is over.
 -test_config () {
 -      test_when_finished "test_unconfig '$1'" &&
 -      git config "$@"
 -}
 -
 -
 -test_config_global () {
 -      test_when_finished "test_unconfig --global '$1'" &&
 -      git config --global "$@"
 -}
 -
 -write_script () {
 -      {
 -              echo "#!${2-"$SHELL_PATH"}" &&
 -              cat
 -      } >"$1" &&
 -      chmod +x "$1"
 -}
 -
 -# 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 () {
 -      # 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
 -}
 +# 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.
@@@ -332,12 -497,9 +332,12 @@@ test_run_ () 
  
        if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"
        then
 +              setup_malloc_check
                test_eval_ "$test_cleanup"
 +              teardown_malloc_check
        fi
 -      if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
 +      if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"
 +      then
                echo ""
        fi
        return "$eval_ret"
@@@ -377,17 -539,318 +377,17 @@@ test_skip () 
        esac
  }
  
 -test_expect_failure () {
 -      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"
 -              if test_run_ "$2" expecting_failure
 -              then
 -                      test_known_broken_ok_ "$1"
 -              else
 -                      test_known_broken_failure_ "$1"
 -              fi
 -      fi
 -      echo >&3 ""
 -}
 -
 -test_expect_success () {
 -      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"
 -              if test_run_ "$2"
 -              then
 -                      test_ok_ "$1"
 -              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
 -# 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 && { 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
 -              # test output that follows.
 -              say_color "" "# run $test_count: $descr ($*)"
 -              # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG
 -              # to be able to use them in script
 -              export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG
 -              # 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
 -                      if test $test_external_has_tap -eq 0; then
 -                              test_ok_ "$descr"
 -                      else
 -                              say_color "" "# test_external test $descr was ok"
 -                              test_success=$(($test_success + 1))
 -                      fi
 -              else
 -                      if test $test_external_has_tap -eq 0; then
 -                              test_failure_ "$descr" "$@"
 -                      else
 -                              say_color error "# test_external test $descr failed: $@"
 -                              test_failure=$(($test_failure + 1))
 -                      fi
 -              fi
 -      fi
 -}
 -
 -# 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:-/tmp}
 -      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"
 -
 -              if test $test_external_has_tap -eq 0; then
 -                      test_ok_ "$descr"
 -              else
 -                      say_color "" "# test_external_without_stderr test $descr was ok"
 -                      test_success=$(($test_success + 1))
 -              fi
 -      else
 -              if [ "$verbose" = t ]; then
 -                      output=`echo; echo "# Stderr is:"; cat "$stderr"`
 -              else
 -                      output=
 -              fi
 -              # rm first in case test_failure exits.
 -              rm "$stderr"
 -              if test $test_external_has_tap -eq 0; then
 -                      test_failure_ "$descr" "$@" "$output"
 -              else
 -                      say_color error "# test_external_without_stderr test $descr failed: $@: $output"
 -                      test_failure=$(($test_failure + 1))
 -              fi
 -      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:
 -#
 -#     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 () {
 -      "$@"
 -      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
 -# meant to be used in contexts like:
 -#
 -#     test_expect_success 'some command works without configuration' '
 -#             test_might_fail git config --unset all.configuration &&
 -#             do something
 -#     '
 -#
 -# Writing "git config --unset all.configuration || :" would be wrong,
 -# because we want to notice if it fails due to segv.
 -
 -test_might_fail () {
 -      "$@"
 -      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
 -              return 0
 -      fi
 -
 -      echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
 -      return 1
 -}
 -
 -# 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 "$@"
 -}
 -
 -# This function can be used to schedule some commands to be run
 -# unconditionally at the end of the test to restore sanity:
 -#
 -#     test_expect_success 'test core.capslock' '
 -#             git config core.capslock true &&
 -#             test_when_finished "git config --unset core.capslock" &&
 -#             hello world
 -#     '
 -#
 -# That would be roughly equivalent to
 -#
 -#     test_expect_success 'test core.capslock' '
 -#             git config core.capslock true &&
 -#             hello world
 -#             git config --unset core.capslock
 -#     '
 -#
 -# except that the greeting and config --unset must both succeed for
 -# the test to pass.
 -#
 -# Note that under --immediate mode, no clean-up is done to help diagnose
 -# what went wrong.
 -
 -test_when_finished () {
 -      test_cleanup="{ $*
 -              } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
 -}
 -
 -# 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"
 -      repo="$1"
 -      mkdir -p "$repo"
 -      (
 -              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
 +# stub; perf-lib overrides it
 +test_at_end_hook_ () {
 +      :
  }
  
  test_done () {
        GIT_EXIT_OK=t
  
 -      if test -z "$HARNESS_ACTIVE"; then
 -              test_results_dir="$TEST_DIRECTORY/test-results"
 +      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"
  
        case "$test_failure" in
        0)
                # Maybe print SKIP message
 +              if test -n "$skip_all" && test $test_count -gt 0
 +              then
 +                      error "Can't use skip_all after running some tests"
 +              fi
                [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
  
 -              if test $test_external_has_tap -eq 0; then
 -                      say_color pass "# passed all $msg"
 +              if test $test_external_has_tap -eq 0
 +              then
 +                      if test $test_count -gt 0
 +                      then
 +                              say_color pass "# passed all $msg"
 +                      fi
                        say "1..$test_count$skip_all"
                fi
  
                cd "$(dirname "$remove_trash")" &&
                rm -rf "$(basename "$remove_trash")"
  
 +              test_at_end_hook_
 +
                exit 0 ;;
  
        *)
 -              if test $test_external_has_tap -eq 0; then
 +              if test $test_external_has_tap -eq 0
 +              then
                        say_color error "# failed $test_failure among $msg"
                        say "1..$test_count"
                fi
        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"
 -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 () {
        PATH=$GIT_VALGRIND/bin:$PATH
        GIT_EXEC_PATH=$GIT_VALGRIND/bin
        export GIT_VALGRIND
 -elif test -n "$GIT_TEST_INSTALLED" ; 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:$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="$GIT_BUILD_DIR/bin-wrappers"
 -      if ! test -x "$git_bin_dir/git" ; then
 -              if test -z "$with_dashes" ; then
 +      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"
                fi
                with_dashes=t
        fi
        PATH="$git_bin_dir:$PATH"
        GIT_EXEC_PATH=$GIT_BUILD_DIR
 -      if test -n "$with_dashes" ; then
 +      if test -n "$with_dashes"
 +      then
                PATH="$GIT_BUILD_DIR:$PATH"
        fi
  fi
@@@ -549,6 -1008,8 +549,6 @@@ GIT_CONFIG_NOSYSTEM=
  GIT_ATTR_NOSYSTEM=1
  export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
  
 -. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
 -
  if test -z "$GIT_TEST_CMP"
  then
        if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT"
@@@ -574,8 -1035,7 +574,8 @@@ the
        }
  fi
  
 -if ! test -x "$GIT_BUILD_DIR"/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
@@@ -586,7 -1046,7 +586,7 @@@ test="trash directory.$(basename "$0" .
  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" || {
  HOME="$TRASH_DIRECTORY"
  export HOME
  
 -test_create_repo "$test"
 +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
@@@ -672,7 -1127,6 +672,7 @@@ case $(uname -s) i
        ;;
  esac
  
 +( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1
  test -z "$NO_PERL" && test_set_prereq PERL
  test -z "$NO_PYTHON" && test_set_prereq PYTHON
  test -n "$USE_LIBPCRE" && test_set_prereq LIBPCRE
@@@ -714,29 -1168,9 +714,29 @@@ test_i18ngrep () 
        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
 +test_lazy_prereq SYMLINKS '
 +      # test whether the filesystem supports symbolic links
 +      ln -s x y && test -h y
 +'
 +
 +test_lazy_prereq CASE_INSENSITIVE_FS '
 +      echo good >CamelCase &&
 +      echo bad >camelcase &&
 +      test "$(cat CamelCase)" != good
 +'
 +
 +test_lazy_prereq UTF8_NFD_TO_NFC '
 +      # check whether FS converts nfd unicode to nfc
 +      auml=$(printf "\303\244")
 +      aumlcdiar=$(printf "\141\314\210")
 +      >"$auml" &&
 +      case "$(echo *)" in
 +      "$aumlcdiar")
 +              true ;;
 +      *)
 +              false ;;
 +      esac
 +'
  
  # When the tests are run as root, permission tests will report that
  # things are writable when they shouldn't be.