summaryrefslogtreecommitdiff
path: root/t/test-lib-functions.sh
diff options
context:
space:
mode:
Diffstat (limited to 't/test-lib-functions.sh')
-rw-r--r--t/test-lib-functions.sh969
1 files changed, 640 insertions, 329 deletions
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 8d59b90..2eccf10 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -14,7 +14,7 @@
# 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/ .
+# along with this program. If not, see https://www.gnu.org/licenses/ .
# The semantics of the editor variables are that of invoking
# sh -c "$EDITOR \"$@\"" files ...
@@ -32,9 +32,12 @@ test_set_editor () {
export EDITOR
}
-test_set_index_version () {
- GIT_INDEX_VERSION="$1"
- export GIT_INDEX_VERSION
+# Like test_set_editor but sets GIT_SEQUENCE_EDITOR instead of EDITOR
+test_set_sequence_editor () {
+ FAKE_SEQUENCE_EDITOR="$1"
+ export FAKE_SEQUENCE_EDITOR
+ GIT_SEQUENCE_EDITOR='"$FAKE_SEQUENCE_EDITOR"'
+ export GIT_SEQUENCE_EDITOR
}
test_decode_color () {
@@ -116,13 +119,6 @@ remove_cr () {
tr '\015' Q | sed -e 's/Q$//'
}
-# Generate an output of $1 bytes of all zeroes (NULs, not ASCII zeroes).
-# If $1 is 'infinity', output forever or until the receiving pipe stops reading,
-# whichever comes first.
-generate_zero_bytes () {
- test-tool genzeros "$@"
-}
-
# In some bourne shell implementations, the "unset" builtin returns
# nonzero status when a variable to be unset was not set in the first
# place.
@@ -149,63 +145,239 @@ test_tick () {
# Stop execution and start a shell. This is useful for debugging tests.
#
# Be sure to remove all invocations of this command before submitting.
+# WARNING: the shell invoked by this helper does not have the same environment
+# as the one running the tests (shell variables and functions are not
+# available, and the options below further modify the environment). As such,
+# commands copied from a test script might behave differently than when
+# running the test.
+#
+# Usage: test_pause [options]
+# -t
+# Use your original TERM instead of test-lib.sh's "dumb".
+# This usually restores color output in the invoked shell.
+# -s
+# Invoke $SHELL instead of $TEST_SHELL_PATH.
+# -h
+# Use your original HOME instead of test-lib.sh's "$TRASH_DIRECTORY".
+# This allows you to use your regular shell environment and Git aliases.
+# CAUTION: running commands copied from a test script into the paused shell
+# might result in files in your HOME being overwritten.
+# -a
+# Shortcut for -t -s -h
test_pause () {
- "$SHELL_PATH" <&6 >&5 2>&7
+ PAUSE_TERM=$TERM &&
+ PAUSE_SHELL=$TEST_SHELL_PATH &&
+ PAUSE_HOME=$HOME &&
+ while test $# != 0
+ do
+ case "$1" in
+ -t)
+ PAUSE_TERM="$USER_TERM"
+ ;;
+ -s)
+ PAUSE_SHELL="$SHELL"
+ ;;
+ -h)
+ PAUSE_HOME="$USER_HOME"
+ ;;
+ -a)
+ PAUSE_TERM="$USER_TERM"
+ PAUSE_SHELL="$SHELL"
+ PAUSE_HOME="$USER_HOME"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done &&
+ TERM="$PAUSE_TERM" HOME="$PAUSE_HOME" "$PAUSE_SHELL" <&6 >&5 2>&7
}
# Wrap git with a debugger. Adding this to a command can make it easier
# to understand what is going on in a failing test.
#
+# Usage: debug [options] <git command>
+# -d <debugger>
+# --debugger=<debugger>
+# Use <debugger> instead of GDB
+# -t
+# Use your original TERM instead of test-lib.sh's "dumb".
+# This usually restores color output in the debugger.
+# WARNING: the command being debugged might behave differently than when
+# running the test.
+#
# Examples:
# debug git checkout master
# debug --debugger=nemiver git $ARGS
# debug -d "valgrind --tool=memcheck --track-origins=yes" git $ARGS
debug () {
- case "$1" in
- -d)
- GIT_DEBUGGER="$2" &&
- shift 2
+ GIT_DEBUGGER=1 &&
+ DEBUG_TERM=$TERM &&
+ while test $# != 0
+ do
+ case "$1" in
+ -t)
+ DEBUG_TERM="$USER_TERM"
+ ;;
+ -d)
+ GIT_DEBUGGER="$2" &&
+ shift
+ ;;
+ --debugger=*)
+ GIT_DEBUGGER="${1#*=}"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done &&
+
+ dotfiles=".gdbinit .lldbinit"
+
+ for dotfile in $dotfiles
+ do
+ dotfile="$USER_HOME/$dotfile" &&
+ test -f "$dotfile" && cp "$dotfile" "$HOME" || :
+ done &&
+
+ TERM="$DEBUG_TERM" GIT_DEBUGGER="${GIT_DEBUGGER}" "$@" <&6 >&5 2>&7 &&
+
+ for dotfile in $dotfiles
+ do
+ rm -f "$HOME/$dotfile"
+ done
+}
+
+# Usage: test_ref_exists [options] <ref>
+#
+# -C <dir>:
+# Run all git commands in directory <dir>
+#
+# This helper function checks whether a reference exists. Symrefs or object IDs
+# will not be resolved. Can be used to check references with bad names.
+test_ref_exists () {
+ local indir=
+
+ while test $# != 0
+ do
+ case "$1" in
+ -C)
+ indir="$2"
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done &&
+
+ indir=${indir:+"$indir"/} &&
+
+ if test "$#" != 1
+ then
+ BUG "expected exactly one reference"
+ fi &&
+
+ git ${indir:+ -C "$indir"} show-ref --exists "$1"
+}
+
+# Behaves the same as test_ref_exists, except that it checks for the absence of
+# a reference. This is preferable to `! test_ref_exists` as this function is
+# able to distinguish actually-missing references from other, generic errors.
+test_ref_missing () {
+ test_ref_exists "$@"
+ case "$?" in
+ 2)
+ # This is the good case.
+ return 0
;;
- --debugger=*)
- GIT_DEBUGGER="${1#*=}" &&
- shift 1
+ 0)
+ echo >&4 "test_ref_missing: reference exists"
+ return 1
;;
*)
- GIT_DEBUGGER=1
+ echo >&4 "test_ref_missing: generic error"
+ return 1
;;
- esac &&
- GIT_DEBUGGER="${GIT_DEBUGGER}" "$@" <&6 >&5 2>&7
+ esac
}
-# Call test_commit with the arguments
-# [-C <directory>] <message> [<file> [<contents> [<tag>]]]"
+# Usage: test_commit [options] <message> [<file> [<contents> [<tag>]]]
+# -C <dir>:
+# Run all git commands in directory <dir>
+# --notick
+# Do not call test_tick before making a commit
+# --append
+# Use ">>" instead of ">" when writing "<contents>" to "<file>"
+# --printf
+# Use "printf" instead of "echo" when writing "<contents>" to
+# "<file>", use this to write escape sequences such as "\0", a
+# trailing "\n" won't be added automatically. This option
+# supports nothing but the FORMAT of printf(1), i.e. no custom
+# ARGUMENT(s).
+# --signoff
+# Invoke "git commit" with --signoff
+# --author <author>
+# Invoke "git commit" with --author <author>
+# --no-tag
+# Do not tag the resulting commit
+# --annotate
+# Create an annotated tag with "--annotate -m <message>". Calls
+# test_tick between making the commit and tag, unless --notick
+# is given.
#
# This will commit a file with the given contents and the given commit
# message, and tag the resulting commit with the given tag name.
#
# <file>, <contents>, and <tag> all default to <message>.
-#
-# If the first argument is "-C", the second argument is used as a path for
-# the git invocations.
test_commit () {
- notick= &&
- signoff= &&
- indir= &&
+ local notick= &&
+ local echo=echo &&
+ local append= &&
+ local author= &&
+ local signoff= &&
+ local indir= &&
+ local tag=light &&
while test $# != 0
do
case "$1" in
--notick)
notick=yes
;;
+ --printf)
+ echo=printf
+ ;;
+ --append)
+ append=yes
+ ;;
+ --author)
+ author="$2"
+ shift
+ ;;
--signoff)
signoff="$1"
;;
+ --date)
+ notick=yes
+ GIT_COMMITTER_DATE="$2"
+ GIT_AUTHOR_DATE="$2"
+ shift
+ ;;
-C)
indir="$2"
shift
;;
+ --no-tag)
+ tag=none
+ ;;
+ --annotate)
+ tag=annotate
+ ;;
*)
break
;;
@@ -213,15 +385,35 @@ test_commit () {
shift
done &&
indir=${indir:+"$indir"/} &&
- file=${2:-"$1.t"} &&
- echo "${3-$1}" > "$indir$file" &&
- git ${indir:+ -C "$indir"} add "$file" &&
+ local file=${2:-"$1.t"} &&
+ if test -n "$append"
+ then
+ $echo "${3-$1}" >>"$indir$file"
+ else
+ $echo "${3-$1}" >"$indir$file"
+ fi &&
+ git ${indir:+ -C "$indir"} add -- "$file" &&
if test -z "$notick"
then
test_tick
fi &&
- git ${indir:+ -C "$indir"} commit $signoff -m "$1" &&
- git ${indir:+ -C "$indir"} tag "${4:-$1}"
+ git ${indir:+ -C "$indir"} commit \
+ ${author:+ --author "$author"} \
+ $signoff -m "$1" &&
+ case "$tag" in
+ none)
+ ;;
+ light)
+ git ${indir:+ -C "$indir"} tag "${4:-$1}"
+ ;;
+ annotate)
+ if test -z "$notick"
+ then
+ test_tick
+ fi &&
+ git ${indir:+ -C "$indir"} tag -a -m "$1" "${4:-$1}"
+ ;;
+ esac
}
# Call test_merge with the arguments "<message> <commit>", where <commit>
@@ -367,9 +559,14 @@ test_chmod () {
git update-index --add "--chmod=$@"
}
-# Get the modebits from a file.
+# Get the modebits from a file or directory, ignoring the setgid bit (g+s).
+# This bit is inherited by subdirectories at their creation. So we remove it
+# from the returning string to prevent callers from having to worry about the
+# state of the bit in the test directory.
+#
test_modebits () {
- ls -l "$1" | sed -e 's|^\(..........\).*|\1|'
+ ls -ld "$1" | sed -e 's|^\(..........\).*|\1|' \
+ -e 's|^\(......\)S|\1-|' -e 's|^\(......\)s|\1x|'
}
# Unset a configuration variable, but don't fail if it doesn't exist.
@@ -400,8 +597,17 @@ test_config () {
config_dir=$1
shift
fi
- test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} '$1'" &&
- git ${config_dir:+-C "$config_dir"} config "$@"
+
+ # If --worktree is provided, use it to configure/unconfigure
+ is_worktree=
+ if test "$1" = --worktree
+ then
+ is_worktree=1
+ shift
+ fi
+
+ test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} ${is_worktree:+--worktree} '$1'" &&
+ git ${config_dir:+-C "$config_dir"} config ${is_worktree:+--worktree} "$@"
}
test_config_global () {
@@ -417,13 +623,89 @@ write_script () {
chmod +x "$1"
}
+# Usage: test_hook [options] <hook-name> <<-\EOF
+#
+# -C <dir>:
+# Run all git commands in directory <dir>
+# --setup
+# Setup a hook for subsequent tests, i.e. don't remove it in a
+# "test_when_finished"
+# --clobber
+# Overwrite an existing <hook-name>, if it exists. Implies
+# --setup (i.e. the "test_when_finished" is assumed to have been
+# set up already).
+# --disable
+# Disable (chmod -x) an existing <hook-name>, which must exist.
+# --remove
+# Remove (rm -f) an existing <hook-name>, which must exist.
+test_hook () {
+ setup= &&
+ clobber= &&
+ disable= &&
+ remove= &&
+ indir= &&
+ while test $# != 0
+ do
+ case "$1" in
+ -C)
+ indir="$2" &&
+ shift
+ ;;
+ --setup)
+ setup=t
+ ;;
+ --clobber)
+ clobber=t
+ ;;
+ --disable)
+ disable=t
+ ;;
+ --remove)
+ remove=t
+ ;;
+ -*)
+ BUG "invalid argument: $1"
+ ;;
+ *)
+ break
+ ;;
+ esac &&
+ shift
+ done &&
+
+ git_dir=$(git -C "$indir" rev-parse --absolute-git-dir) &&
+ hook_dir="$git_dir/hooks" &&
+ hook_file="$hook_dir/$1" &&
+ if test -n "$disable$remove"
+ then
+ test_path_is_file "$hook_file" &&
+ if test -n "$disable"
+ then
+ chmod -x "$hook_file"
+ elif test -n "$remove"
+ then
+ rm -f "$hook_file"
+ fi &&
+ return 0
+ fi &&
+ if test -z "$clobber"
+ then
+ test_path_is_missing "$hook_file"
+ fi &&
+ if test -z "$setup$clobber"
+ then
+ test_when_finished "rm \"$hook_file\""
+ fi &&
+ write_script "$hook_file"
+}
+
# 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}.
+# test_expect_{success,failure}
#
# The single parameter is the prerequisite tag (a simple word, in all
# capital letters by convention).
@@ -441,8 +723,7 @@ test_set_prereq () {
# test_unset_prereq()
!*)
;;
- # (Temporary?) whitelist of things we can't easily
- # pretend not to support
+ # List of things we can't easily pretend to not support
SYMLINKS)
;;
# Inspecting whether GIT_TEST_FAIL_PREREQS is on
@@ -474,15 +755,15 @@ test_lazy_prereq () {
test_run_lazy_prereq_ () {
script='
-mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" &&
+mkdir -p "$TRASH_DIRECTORY/prereq-test-dir-'"$1"'" &&
(
- cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"'
+ cd "$TRASH_DIRECTORY/prereq-test-dir-'"$1"'" &&'"$2"'
)'
say >&3 "checking prerequisite: $1"
say >&3 "$script"
test_eval_ "$script"
eval_ret=$?
- rm -rf "$TRASH_DIRECTORY/prereq-test-dir"
+ rm -rf "$TRASH_DIRECTORY/prereq-test-dir-$1"
if test "$eval_ret" = 0; then
say >&3 "prerequisite $1 ok"
else
@@ -546,6 +827,17 @@ test_have_prereq () {
# Keep a list of missing prerequisites; restore
# the negative marker if necessary.
prerequisite=${negative_prereq:+!}$prerequisite
+
+ # Abort if this prereq was marked as required
+ if test -n "$GIT_TEST_REQUIRE_PREREQ"
+ then
+ case " $GIT_TEST_REQUIRE_PREREQ " in
+ *" $prerequisite "*)
+ BAIL_OUT "required prereq $prerequisite failed"
+ ;;
+ esac
+ fi
+
if test -z "$missing_prereq"
then
missing_prereq=$prerequisite
@@ -574,7 +866,7 @@ test_verify_prereq () {
}
test_expect_failure () {
- test_start_
+ test_start_ "$@"
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 ||
BUG "not 2 or 3 parameters to test-expect-failure"
@@ -582,6 +874,7 @@ test_expect_failure () {
export test_prereq
if ! test_skip "$@"
then
+ test -n "$test_skip_test_preamble" ||
say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $2"
if test_run_ "$2" expecting_failure
then
@@ -594,7 +887,7 @@ test_expect_failure () {
}
test_expect_success () {
- test_start_
+ test_start_ "$@"
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 ||
BUG "not 2 or 3 parameters to test-expect-success"
@@ -602,6 +895,7 @@ test_expect_success () {
export test_prereq
if ! test_skip "$@"
then
+ test -n "$test_skip_test_preamble" ||
say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $2"
if test_run_ "$2"
then
@@ -613,124 +907,78 @@ test_expect_success () {
test_finish_
}
-# 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 ||
- BUG "not 3 or 4 parameters to test_external"
- descr="$1"
- shift
- test_verify_prereq
- export test_prereq
- if ! test_skip "$descr" "$@"
+# debugging-friendly alternatives to "test [-f|-d|-e]"
+# The commands test the existence or non-existence of $1
+test_path_is_file () {
+ test "$#" -ne 1 && BUG "1 param"
+ if ! test -f "$1"
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 test "$?" = 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
+ echo "File $1 doesn't exist"
+ false
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"
- test -f "$stderr" || error "Internal error: $stderr disappeared."
- descr="no stderr: $1"
- shift
- say >&3 "# expecting no stderr from previous command"
- if test ! -s "$stderr"
+test_path_is_file_not_symlink () {
+ test "$#" -ne 1 && BUG "1 param"
+ test_path_is_file "$1" &&
+ if test -h "$1"
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 test "$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
+ echo "$1 shouldn't be a symbolic link"
+ false
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 ! test -f "$1"
+test_path_is_dir () {
+ test "$#" -ne 1 && BUG "1 param"
+ if ! test -d "$1"
then
- echo "File $1 doesn't exist. $2"
+ echo "Directory $1 doesn't exist"
false
fi
}
-test_path_is_dir () {
- if ! test -d "$1"
+test_path_is_dir_not_symlink () {
+ test "$#" -ne 1 && BUG "1 param"
+ test_path_is_dir "$1" &&
+ if test -h "$1"
then
- echo "Directory $1 doesn't exist. $2"
+ echo "$1 shouldn't be a symbolic link"
false
fi
}
test_path_exists () {
+ test "$#" -ne 1 && BUG "1 param"
if ! test -e "$1"
then
- echo "Path $1 doesn't exist. $2"
+ echo "Path $1 doesn't exist"
+ false
+ fi
+}
+
+test_path_is_symlink () {
+ test "$#" -ne 1 && BUG "1 param"
+ if ! test -h "$1"
+ then
+ echo "Symbolic link $1 doesn't exist"
+ false
+ fi
+}
+
+test_path_is_executable () {
+ test "$#" -ne 1 && BUG "1 param"
+ if ! test -x "$1"
+ then
+ echo "$1 is not executable"
false
fi
}
# Check if the directory exists and is empty as expected, barf otherwise.
test_dir_is_empty () {
+ test "$#" -ne 1 && BUG "1 param"
test_path_is_dir "$1" &&
- if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')"
+ if test -n "$(ls -a1 "$1" | grep -E -v '^\.\.?$')"
then
echo "Directory '$1' is not empty, it contains:"
ls -la "$1"
@@ -740,6 +988,7 @@ test_dir_is_empty () {
# Check if the file exists and has a size greater than zero
test_file_not_empty () {
+ test "$#" = 2 && BUG "2 param"
if ! test -s "$1"
then
echo "'$1' is not a non-empty file."
@@ -748,14 +997,11 @@ test_file_not_empty () {
}
test_path_is_missing () {
+ test "$#" -ne 1 && BUG "1 param"
if test -e "$1"
then
echo "Path exists:"
ls -ld "$1"
- if test $# -ge 1
- then
- echo "$*"
- fi
false
fi
}
@@ -783,6 +1029,37 @@ test_line_count () {
fi
}
+# SYNOPSIS:
+# test_stdout_line_count <bin-ops> <value> <cmd> [<args>...]
+#
+# test_stdout_line_count checks that the output of a command has the number
+# of lines it ought to. For example:
+#
+# test_stdout_line_count = 3 git ls-files -u
+# test_stdout_line_count -gt 10 ls
+test_stdout_line_count () {
+ local ops val trashdir &&
+ if test "$#" -le 3
+ then
+ BUG "expect 3 or more arguments"
+ fi &&
+ ops="$1" &&
+ val="$2" &&
+ shift 2 &&
+ if ! trashdir="$(git rev-parse --git-dir)/trash"; then
+ BUG "expect to be run inside a worktree"
+ fi &&
+ mkdir -p "$trashdir" &&
+ "$@" >"$trashdir/output" &&
+ test_line_count "$ops" "$val" "$trashdir/output"
+}
+
+
+test_file_size () {
+ test "$#" -ne 1 && BUG "1 param"
+ test-tool path-utils file-size "$1"
+}
+
# Returns success if a comma separated string of keywords ($1) contains a
# given keyword ($2).
# Examples:
@@ -820,7 +1097,7 @@ test_must_fail_acceptable () {
fi
case "$1" in
- git|__git*|test-tool|test_terminal)
+ git|__git*|scalar|test-tool|test_terminal)
return 0
;;
*)
@@ -951,14 +1228,9 @@ test_expect_code () {
# - cmp's output is not nearly as easy to read as diff -u
# - not all diff versions understand "-u"
-test_cmp() {
- test $# -eq 2 || BUG "test_cmp requires two arguments"
- if ! eval "$GIT_TEST_CMP" '"$@"'
- then
- test "x$1" = x- || test -e "$1" || BUG "test_cmp '$1' missing"
- test "x$2" = x- || test -e "$2" || BUG "test_cmp '$2' missing"
- return 1
- fi
+test_cmp () {
+ test "$#" -ne 2 && BUG "2 param"
+ eval "$GIT_TEST_CMP" '"$@"'
}
# Check that the given config key has the expected value.
@@ -970,7 +1242,7 @@ test_cmp() {
#
# test_cmp_config foo core.bar
#
-test_cmp_config() {
+test_cmp_config () {
local GD &&
if test "$1" = "-C"
then
@@ -986,45 +1258,25 @@ test_cmp_config() {
# test_cmp_bin - helper to compare binary files
-test_cmp_bin() {
- test $# -eq 2 || BUG "test_cmp_bin requires two arguments"
- if ! cmp "$@"
- then
- test "x$1" = x- || test -e "$1" || BUG "test_cmp_bin '$1' missing"
- test "x$2" = x- || test -e "$2" || BUG "test_cmp_bin '$2' missing"
- return 1
- fi
+test_cmp_bin () {
+ test "$#" -ne 2 && BUG "2 param"
+ cmp "$@"
}
-# 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 GIT_TEST_GETTEXT_POISON this pretends that the command produced expected
-# results.
-test_i18ncmp () {
- ! test_have_prereq C_LOCALE_OUTPUT || test_cmp "$@"
+test_i18ngrep () {
+ BUG "do not use test_i18ngrep---use test_grep instead"
}
-# 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 GIT_TEST_GETTEXT_POISON this pretends that the command produced expected
-# results.
-test_i18ngrep () {
+test_grep () {
eval "last_arg=\${$#}"
test -f "$last_arg" ||
- BUG "test_i18ngrep requires a file to read as the last parameter"
+ BUG "test_grep requires a file to read as the last parameter"
if test $# -lt 2 ||
{ test "x!" = "x$1" && test $# -lt 3 ; }
then
- BUG "too few parameters to test_i18ngrep"
- fi
-
- if test_have_prereq !C_LOCALE_OUTPUT
- then
- # pretend success
- return 0
+ BUG "too few parameters to test_grep"
fi
if test "x!" = "x$1"
@@ -1049,19 +1301,11 @@ test_i18ngrep () {
return 1
}
-# Call any command "$@" but be more verbose about its
-# failure. This is handy for commands like "test" which do
-# not output anything when they fail.
-verbose () {
- "$@" && return 0
- echo >&4 "command failed: $(git rev-parse --sq-quote "$@")"
- return 1
-}
-
# Check if the file expected to be empty is indeed empty, and barfs
# otherwise.
test_must_be_empty () {
+ test "$#" -ne 1 && BUG "1 param"
test_path_is_file "$1" &&
if test -s "$1"
then
@@ -1085,7 +1329,7 @@ test_cmp_rev () {
fi
if test $# != 2
then
- error "bug in the test script: test_cmp_rev requires two revisions, but got $#"
+ BUG "test_cmp_rev requires two revisions, but got $#"
else
local r1 r2
r1=$(git rev-parse --verify "$1") &&
@@ -1103,6 +1347,39 @@ test_cmp_rev () {
fi
}
+# Tests that a commit message matches the expected text
+#
+# Usage: test_commit_message <rev> [-m <msg> | <file>]
+#
+# When using "-m" <msg> will have a line feed appended. If the second
+# argument is omitted then the expected message is read from stdin.
+
+test_commit_message () {
+ local msg_file=expect.msg
+
+ case $# in
+ 3)
+ if test "$2" = "-m"
+ then
+ printf "%s\n" "$3" >"$msg_file"
+ else
+ BUG "Usage: test_commit_message <rev> [-m <message> | <file>]"
+ fi
+ ;;
+ 2)
+ msg_file="$2"
+ ;;
+ 1)
+ cat >"$msg_file"
+ ;;
+ *)
+ BUG "Usage: test_commit_message <rev> [-m <message> | <file>]"
+ ;;
+ esac
+ git show --no-patch --pretty=format:%B "$1" -- >actual.msg &&
+ test_cmp "$msg_file" actual.msg
+}
+
# Compare paths respecting core.ignoreCase
test_cmp_fspath () {
if test "x$1" = "x$2"
@@ -1196,25 +1473,15 @@ test_atexit () {
# doing so on Bash is better than nothing (the test will
# silently pass on other shells).
test "${BASH_SUBSHELL-0}" = 0 ||
- error "bug in test script: test_atexit does nothing in a subshell"
+ BUG "test_atexit does nothing in a subshell"
test_atexit_cleanup="{ $*
} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_atexit_cleanup"
}
-# Most tests can use the created repository, but some may need to create more.
+# Deprecated wrapper for "git init", use "git init" directly instead
# Usage: test_create_repo <directory>
test_create_repo () {
- test "$#" = 1 ||
- BUG "not 1 parameter to test-create-repo"
- repo="$1"
- mkdir -p "$repo"
- (
- cd "$repo" || error "Cannot setup test environment"
- "${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" 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
+ git init "$@"
}
# This function helps on symlink challenged file systems when it is not
@@ -1261,7 +1528,7 @@ test_bool_env () {
BUG "test_bool_env requires two parameters (variable name and default value)"
fi
- git env--helper --type=bool --default="$2" --exit-code "$1"
+ test-tool env-helper --type=bool --default="$2" --exit-code "$1"
ret=$?
case $ret in
0|1) # unset or valid bool value
@@ -1289,72 +1556,6 @@ test_skip_or_die () {
error "$2"
}
-# The following mingw_* functions obey POSIX shell syntax, but are actually
-# bash scripts, and are meant to be used only with bash on Windows.
-
-# A test_cmp function that treats LF and CRLF equal and avoids to fork
-# diff when possible.
-mingw_test_cmp () {
- # Read text into shell variables and compare them. If the results
- # are different, use regular diff to report the difference.
- local test_cmp_a= test_cmp_b=
-
- # When text came from stdin (one argument is '-') we must feed it
- # to diff.
- local stdin_for_diff=
-
- # Since it is difficult to detect the difference between an
- # empty input file and a failure to read the files, we go straight
- # to diff if one of the inputs is empty.
- if test -s "$1" && test -s "$2"
- then
- # regular case: both files non-empty
- mingw_read_file_strip_cr_ test_cmp_a <"$1"
- mingw_read_file_strip_cr_ test_cmp_b <"$2"
- elif test -s "$1" && test "$2" = -
- then
- # read 2nd file from stdin
- mingw_read_file_strip_cr_ test_cmp_a <"$1"
- mingw_read_file_strip_cr_ test_cmp_b
- stdin_for_diff='<<<"$test_cmp_b"'
- elif test "$1" = - && test -s "$2"
- then
- # read 1st file from stdin
- mingw_read_file_strip_cr_ test_cmp_a
- mingw_read_file_strip_cr_ test_cmp_b <"$2"
- stdin_for_diff='<<<"$test_cmp_a"'
- fi
- test -n "$test_cmp_a" &&
- test -n "$test_cmp_b" &&
- test "$test_cmp_a" = "$test_cmp_b" ||
- eval "diff -u \"\$@\" $stdin_for_diff"
-}
-
-# $1 is the name of the shell variable to fill in
-mingw_read_file_strip_cr_ () {
- # Read line-wise using LF as the line separator
- # and use IFS to strip CR.
- local line
- while :
- do
- if IFS=$'\r' read -r -d $'\n' line
- then
- # good
- line=$line$'\n'
- else
- # we get here at EOF, but also if the last line
- # was not terminated by LF; in the latter case,
- # some text was read
- if test -z "$line"
- then
- # EOF, really
- break
- fi
- fi
- eval "$1=\$$1\$line"
- done
-}
-
# Like "env FOO=BAR some-program", but run inside a subshell, which means
# it also works for shell functions (though those functions cannot impact
# the environment outside of the test_env invocation).
@@ -1421,46 +1622,24 @@ nongit () {
)
} 7>&2 2>&4
-# convert function arguments or stdin (if not arguments given) to pktline
-# representation. If multiple arguments are given, they are separated by
-# whitespace and put in a single packet. Note that data containing NULs must be
-# given on stdin, and that empty input becomes an empty packet, not a flush
-# packet (for that you can just print 0000 yourself).
-packetize() {
+# These functions are historical wrappers around "test-tool pkt-line"
+# for older tests. Use "test-tool pkt-line" itself in new tests.
+packetize () {
if test $# -gt 0
then
packet="$*"
printf '%04x%s' "$((4 + ${#packet}))" "$packet"
else
- perl -e '
- my $packet = do { local $/; <STDIN> };
- printf "%04x%s", 4 + length($packet), $packet;
- '
+ test-tool pkt-line pack
fi
}
-# Parse the input as a series of pktlines, writing the result to stdout.
-# Sideband markers are removed automatically, and the output is routed to
-# stderr if appropriate.
-#
-# NUL bytes are converted to "\\0" for ease of parsing with text tools.
+packetize_raw () {
+ test-tool pkt-line pack-raw-stdin
+}
+
depacketize () {
- perl -e '
- while (read(STDIN, $len, 4) == 4) {
- if ($len eq "0000") {
- print "FLUSH\n";
- } else {
- read(STDIN, $buf, hex($len) - 4);
- $buf =~ s/\0/\\0/g;
- if ($buf =~ s/^[\x2\x3]//) {
- print STDERR $buf;
- } else {
- $buf =~ s/^\x1//;
- print $buf;
- }
- }
- }
- '
+ test-tool pkt-line unpack
}
# Converts base-16 data into base-8. The output is given as a sequence of
@@ -1476,7 +1655,21 @@ test_set_hash () {
# Detect the hash algorithm in use.
test_detect_hash () {
- test_hash_algo="${GIT_TEST_DEFAULT_HASH:-sha1}"
+ case "$GIT_TEST_DEFAULT_HASH" in
+ "sha256")
+ test_hash_algo=sha256
+ test_compat_hash_algo=sha1
+ ;;
+ *)
+ test_hash_algo=sha1
+ test_compat_hash_algo=sha256
+ ;;
+ esac
+}
+
+# Detect the hash algorithm in use.
+test_detect_ref_format () {
+ echo "${GIT_TEST_DEFAULT_REF_FORMAT:-files}"
}
# Load common hash metadata and common placeholder object IDs for use with
@@ -1528,6 +1721,12 @@ test_oid () {
local algo="${test_hash_algo}" &&
case "$1" in
+ --hash=storage)
+ algo="$test_hash_algo" &&
+ shift;;
+ --hash=compat)
+ algo="$test_compat_hash_algo" &&
+ shift;;
--hash=*)
algo="${1#--hash=}" &&
shift;;
@@ -1543,7 +1742,7 @@ test_oid () {
then
BUG "undefined key '$1'"
fi &&
- eval "printf '%s' \"\${$var}\""
+ eval "printf '%s\n' \"\${$var}\""
}
# Insert a slash into an object ID so it can be used to reference a location
@@ -1553,6 +1752,16 @@ test_oid_to_path () {
echo "${1%$basename}/$basename"
}
+# Parse oids from git ls-files --staged output
+test_parse_ls_files_stage_oids () {
+ awk '{print $2}' -
+}
+
+# Parse oids from git ls-tree output
+test_parse_ls_tree_oids () {
+ awk '{print $3}' -
+}
+
# Choose a port number based on the test script's number and store it in
# the given variable name, unless that variable already contains a number.
test_set_port () {
@@ -1592,33 +1801,6 @@ test_set_port () {
eval $var=$port
}
-# Compare a file containing rev-list bitmap traversal output to its non-bitmap
-# counterpart. You can't just use test_cmp for this, because the two produce
-# subtly different output:
-#
-# - regular output is in traversal order, whereas bitmap is split by type,
-# with non-packed objects at the end
-#
-# - regular output has a space and the pathname appended to non-commit
-# objects; bitmap output omits this
-#
-# This function normalizes and compares the two. The second file should
-# always be the bitmap output.
-test_bitmap_traversal () {
- if test "$1" = "--no-confirm-bitmaps"
- then
- shift
- elif cmp "$1" "$2"
- then
- echo >&2 "identical raw outputs; are you sure bitmaps were used?"
- return 1
- fi &&
- cut -d' ' -f1 "$1" | sort >"$1.normalized" &&
- sort "$2" >"$2.normalized" &&
- test_cmp "$1.normalized" "$2.normalized" &&
- rm -f "$1.normalized" "$2.normalized"
-}
-
# Tests for the hidden file attribute on Windows
test_path_is_hidden () {
test_have_prereq MINGW ||
@@ -1629,6 +1811,13 @@ test_path_is_hidden () {
return 1
}
+# Poor man's URI escaping. Good enough for the test suite whose trash
+# directory has a space in it. See 93c3fcbe4d4 (git-svn: attempt to
+# mimic SVN 1.7 URL canonicalization, 2012-07-28) for prior art.
+test_uri_escape() {
+ sed 's/ /%20/g'
+}
+
# Check that the given command was invoked as part of the
# trace2-format trace on stdin.
#
@@ -1661,3 +1850,125 @@ test_subcommand () {
grep "\[$expr\]"
fi
}
+
+# Check that the given command was invoked as part of the
+# trace2-format trace on stdin.
+#
+# test_region [!] <category> <label> git <command> <args>...
+#
+# For example, to look for trace2_region_enter("index", "do_read_index", repo)
+# in an invocation of "git checkout HEAD~1", run
+#
+# GIT_TRACE2_EVENT="$(pwd)/trace.txt" GIT_TRACE2_EVENT_NESTING=10 \
+# git checkout HEAD~1 &&
+# test_region index do_read_index <trace.txt
+#
+# If the first parameter passed is !, this instead checks that
+# the given region was not entered.
+#
+test_region () {
+ local expect_exit=0
+ if test "$1" = "!"
+ then
+ expect_exit=1
+ shift
+ fi
+
+ grep -e '"region_enter".*"category":"'"$1"'","label":"'"$2"\" "$3"
+ exitcode=$?
+
+ if test $exitcode != $expect_exit
+ then
+ return 1
+ fi
+
+ grep -e '"region_leave".*"category":"'"$1"'","label":"'"$2"\" "$3"
+ exitcode=$?
+
+ if test $exitcode != $expect_exit
+ then
+ return 1
+ fi
+
+ return 0
+}
+
+# Check that the given data fragment was included as part of the
+# trace2-format trace on stdin.
+#
+# test_trace2_data <category> <key> <value>
+#
+# For example, to look for trace2_data_intmax("pack-objects", repo,
+# "reused", N) in an invocation of "git pack-objects", run:
+#
+# GIT_TRACE2_EVENT="$(pwd)/trace.txt" git pack-objects ... &&
+# test_trace2_data pack-objects reused N <trace2.txt
+test_trace2_data () {
+ grep -e '"category":"'"$1"'","key":"'"$2"'","value":"'"$3"'"'
+}
+
+# Given a GIT_TRACE2_EVENT log over stdin, writes to stdout a list of URLs
+# sent to git-remote-https child processes.
+test_remote_https_urls() {
+ grep -e '"event":"child_start".*"argv":\["git-remote-https",".*"\]' |
+ sed -e 's/{"event":"child_start".*"argv":\["git-remote-https","//g' \
+ -e 's/"\]}//g'
+}
+
+# Print the destination of symlink(s) provided as arguments. Basically
+# the same as the readlink command, but it's not available everywhere.
+test_readlink () {
+ perl -le 'print readlink($_) for @ARGV' "$@"
+}
+
+# Set mtime to a fixed "magic" timestamp in mid February 2009, before we
+# run an operation that may or may not touch the file. If the file was
+# touched, its timestamp will not accidentally have such an old timestamp,
+# as long as your filesystem clock is reasonably correct. To verify the
+# timestamp, follow up with test_is_magic_mtime.
+#
+# An optional increment to the magic timestamp may be specified as second
+# argument.
+test_set_magic_mtime () {
+ local inc=${2:-0} &&
+ local mtime=$((1234567890 + $inc)) &&
+ test-tool chmtime =$mtime "$1" &&
+ test_is_magic_mtime "$1" $inc
+}
+
+# Test whether the given file has the "magic" mtime set. This is meant to
+# be used in combination with test_set_magic_mtime.
+#
+# An optional increment to the magic timestamp may be specified as second
+# argument. Usually, this should be the same increment which was used for
+# the associated test_set_magic_mtime.
+test_is_magic_mtime () {
+ local inc=${2:-0} &&
+ local mtime=$((1234567890 + $inc)) &&
+ echo $mtime >.git/test-mtime-expect &&
+ test-tool chmtime --get "$1" >.git/test-mtime-actual &&
+ test_cmp .git/test-mtime-expect .git/test-mtime-actual
+ local ret=$?
+ rm -f .git/test-mtime-expect
+ rm -f .git/test-mtime-actual
+ return $ret
+}
+
+# Given two filenames, parse both using 'git config --list --file'
+# and compare the sorted output of those commands. Useful when
+# wanting to ignore whitespace differences and sorting concerns.
+test_cmp_config_output () {
+ git config --list --file="$1" >config-expect &&
+ git config --list --file="$2" >config-actual &&
+ sort config-expect >sorted-expect &&
+ sort config-actual >sorted-actual &&
+ test_cmp sorted-expect sorted-actual
+}
+
+# Given a filename, extract its trailing hash as a hex string
+test_trailing_hash () {
+ local file="$1" &&
+ tail -c $(test_oid rawsz) "$file" |
+ test-tool hexdump |
+ sed "s/ //g"
+}