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.sh382
1 files changed, 351 insertions, 31 deletions
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 80daaca780..e8d3c0fdbc 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+# Library of functions shared by all tests scripts, included by
+# test-lib.sh.
#
# Copyright (c) 2005 Junio C Hamano
#
@@ -31,6 +32,11 @@ test_set_editor () {
export EDITOR
}
+test_set_index_version () {
+ GIT_INDEX_VERSION="$1"
+ export GIT_INDEX_VERSION
+}
+
test_decode_color () {
awk '
function name(n) {
@@ -76,11 +82,11 @@ test_decode_color () {
}
nul_to_q () {
- "$PERL_PATH" -pe 'y/\000/Q/'
+ perl -pe 'y/\000/Q/'
}
q_to_nul () {
- "$PERL_PATH" -pe 'y/Q/\000/'
+ perl -pe 'y/Q/\000/'
}
q_to_cr () {
@@ -91,6 +97,10 @@ q_to_tab () {
tr Q '\011'
}
+qz_to_tab_space () {
+ tr QZ '\011\040'
+}
+
append_cr () {
sed -e 's/$/Q/' | tr Q '\015'
}
@@ -135,20 +145,31 @@ test_pause () {
fi
}
-# Call test_commit with the arguments "<message> [<file> [<contents>]]"
+# Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]"
#
# This will commit a file with the given contents and the given commit
-# message. It will also add a tag with <message> as name.
+# message, and tag the resulting commit with the given tag name.
#
-# Both <file> and <contents> default to <message>.
+# <file>, <contents>, and <tag> all default to <message>.
test_commit () {
notick= &&
- if test "z$1" = "z--notick"
- then
- notick=yes
+ signoff= &&
+ while test $# != 0
+ do
+ case "$1" in
+ --notick)
+ notick=yes
+ ;;
+ --signoff)
+ signoff="$1"
+ ;;
+ *)
+ break
+ ;;
+ esac
shift
- fi &&
+ done &&
file=${2:-"$1.t"} &&
echo "${3-$1}" > "$file" &&
git add "$file" &&
@@ -156,8 +177,8 @@ test_commit () {
then
test_tick
fi &&
- git commit -m "$1" &&
- git tag "$1"
+ git commit $signoff -m "$1" &&
+ git tag "${4:-$1}"
}
# Call test_merge with the arguments "<message> <commit>", where <commit>
@@ -221,9 +242,35 @@ write_script () {
# capital letters by convention).
test_set_prereq () {
- satisfied="$satisfied$1 "
+ satisfied_prereq="$satisfied_prereq$1 "
+}
+satisfied_prereq=" "
+lazily_testable_prereq= lazily_tested_prereq=
+
+# Usage: test_lazy_prereq PREREQ 'script'
+test_lazy_prereq () {
+ lazily_testable_prereq="$lazily_testable_prereq$1 "
+ eval test_prereq_lazily_$1=\$2
+}
+
+test_run_lazy_prereq_ () {
+ script='
+mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" &&
+(
+ cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"'
+)'
+ say >&3 "checking prerequisite: $1"
+ say >&3 "$script"
+ test_eval_ "$script"
+ eval_ret=$?
+ rm -rf "$TRASH_DIRECTORY/prereq-test-dir"
+ if test "$eval_ret" = 0; then
+ say >&3 "prerequisite $1 ok"
+ else
+ say >&3 "prerequisite $1 not satisfied"
+ fi
+ return $eval_ret
}
-satisfied=" "
test_have_prereq () {
# prerequisites can be concatenated with ','
@@ -238,13 +285,48 @@ test_have_prereq () {
for prerequisite
do
+ case "$prerequisite" in
+ !*)
+ negative_prereq=t
+ prerequisite=${prerequisite#!}
+ ;;
+ *)
+ negative_prereq=
+ esac
+
+ case " $lazily_tested_prereq " in
+ *" $prerequisite "*)
+ ;;
+ *)
+ case " $lazily_testable_prereq " in
+ *" $prerequisite "*)
+ eval "script=\$test_prereq_lazily_$prerequisite" &&
+ if test_run_lazy_prereq_ "$prerequisite" "$script"
+ then
+ test_set_prereq $prerequisite
+ fi
+ lazily_tested_prereq="$lazily_tested_prereq$prerequisite "
+ esac
+ ;;
+ esac
+
total_prereq=$(($total_prereq + 1))
- case $satisfied in
+ case "$satisfied_prereq" in
*" $prerequisite "*)
+ satisfied_this_prereq=t
+ ;;
+ *)
+ satisfied_this_prereq=
+ esac
+
+ case "$satisfied_this_prereq,$negative_prereq" in
+ t,|,t)
ok_prereq=$(($ok_prereq + 1))
;;
*)
- # Keep a list of missing prerequisites
+ # Keep a list of missing prerequisites; restore
+ # the negative marker if necessary.
+ prerequisite=${negative_prereq:+!}$prerequisite
if test -z "$missing_prereq"
then
missing_prereq=$prerequisite
@@ -266,10 +348,18 @@ test_declared_prereq () {
return 1
}
+test_verify_prereq () {
+ test -z "$test_prereq" ||
+ expr >/dev/null "$test_prereq" : '[A-Z0-9_,!]*$' ||
+ error "bug in the test script: '$test_prereq' does not look like a prereq"
+}
+
test_expect_failure () {
+ test_start_
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"
+ test_verify_prereq
export test_prereq
if ! test_skip "$@"
then
@@ -281,13 +371,15 @@ test_expect_failure () {
test_known_broken_failure_ "$1"
fi
fi
- echo >&3 ""
+ test_finish_
}
test_expect_success () {
+ test_start_
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"
+ test_verify_prereq
export test_prereq
if ! test_skip "$@"
then
@@ -299,7 +391,7 @@ test_expect_success () {
test_failure_ "$@"
fi
fi
- echo >&3 ""
+ test_finish_
}
# test_external runs external test scripts that provide continuous
@@ -316,6 +408,7 @@ test_external () {
error >&5 "bug in the test script: not 3 or 4 parameters to test_external"
descr="$1"
shift
+ test_verify_prereq
export test_prereq
if ! test_skip "$descr" "$@"
then
@@ -329,7 +422,7 @@ test_external () {
# test_run_, but keep its stdout on our stdout even in
# non-verbose mode.
"$@" 2>&4
- if [ "$?" = 0 ]
+ if test "$?" = 0
then
if test $test_external_has_tap -eq 0; then
test_ok_ "$descr"
@@ -356,11 +449,12 @@ test_external_without_stderr () {
tmp=${TMPDIR:-/tmp}
stderr="$tmp/git-external-stderr.$$.tmp"
test_external "$@" 4> "$stderr"
- [ -f "$stderr" ] || error "Internal error: $stderr disappeared."
+ test -f "$stderr" || error "Internal error: $stderr disappeared."
descr="no stderr: $1"
shift
say >&3 "# expecting no stderr from previous command"
- if [ ! -s "$stderr" ]; then
+ if test ! -s "$stderr"
+ then
rm "$stderr"
if test $test_external_has_tap -eq 0; then
@@ -370,8 +464,9 @@ test_external_without_stderr () {
test_success=$(($test_success + 1))
fi
else
- if [ "$verbose" = t ]; then
- output=`echo; echo "# Stderr is:"; cat "$stderr"`
+ if test "$verbose" = t
+ then
+ output=$(echo; echo "# Stderr is:"; cat "$stderr")
else
output=
fi
@@ -390,27 +485,39 @@ test_external_without_stderr () {
# 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" ]
+ if ! test -f "$1"
then
- echo "File $1 doesn't exist. $*"
+ echo "File $1 doesn't exist. $2"
false
fi
}
test_path_is_dir () {
- if ! [ -d "$1" ]
+ if ! test -d "$1"
then
- echo "Directory $1 doesn't exist. $*"
+ echo "Directory $1 doesn't exist. $2"
false
fi
}
+# Check if the directory exists and is empty as expected, barf otherwise.
+test_dir_is_empty () {
+ test_path_is_dir "$1" &&
+ if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')"
+ then
+ echo "Directory '$1' is not empty, it contains:"
+ ls -la "$1"
+ return 1
+ fi
+}
+
test_path_is_missing () {
- if [ -e "$1" ]
+ if test -e "$1"
then
echo "Path exists:"
ls -ld "$1"
- if [ $# -ge 1 ]; then
+ if test $# -ge 1
+ then
echo "$*"
fi
false
@@ -458,12 +565,15 @@ test_must_fail () {
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
+ elif test $exit_code -gt 129 && test $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
+ elif test $exit_code = 126; then
+ echo >&2 "test_must_fail: valgrind error: $*"
+ return 1
fi
return 0
}
@@ -482,7 +592,7 @@ test_must_fail () {
test_might_fail () {
"$@"
exit_code=$?
- if test $exit_code -gt 129 -a $exit_code -le 192; then
+ if test $exit_code -gt 129 && test $exit_code -le 192; then
echo >&2 "test_might_fail: died by signal: $*"
return 1
elif test $exit_code = 127; then
@@ -530,6 +640,64 @@ test_cmp() {
$GIT_TEST_CMP "$@"
}
+# test_cmp_bin - helper to compare binary files
+
+test_cmp_bin() {
+ cmp "$@"
+}
+
+# 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 >&2 "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 () {
+ if test -s "$1"
+ then
+ echo "'$1' is not empty, it contains:"
+ cat "$1"
+ return 1
+ fi
+}
+
+# Tests that its two parameters refer to the same revision
+test_cmp_rev () {
+ git rev-parse --verify "$1" >expect.rev &&
+ git rev-parse --verify "$2" >actual.rev &&
+ test_cmp expect.rev actual.rev
+}
+
+# Print a sequence of numbers or letters in increasing order. This is
+# similar to GNU seq(1), but the latter might not be available
+# everywhere (and does not do letters). It may be used like:
+#
+# for i in $(test_seq 100)
+# do
+# for j in $(test_seq 10 20)
+# do
+# for k in $(test_seq a z)
+# do
+# echo $i-$j-$k
+# done
+# done
+# done
+
+test_seq () {
+ case $# in
+ 1) set 1 "$@" ;;
+ 2) ;;
+ *) error "bug in the test script: not 1 or 2 parameters to test_seq" ;;
+ esac
+ perl -le 'print for $ARGV[0]..$ARGV[1]' -- "$@"
+}
+
# This function can be used to schedule some commands to be run
# unconditionally at the end of the test to restore sanity:
#
@@ -572,3 +740,155 @@ test_create_repo () {
mv .git/hooks .git/hooks-disabled
) || exit
}
+
+# This function helps on symlink challenged file systems when it is not
+# important that the file system entry is a symbolic link.
+# Use test_ln_s_add instead of "ln -s x y && git add y" to add a
+# symbolic link entry y to the index.
+
+test_ln_s_add () {
+ if test_have_prereq SYMLINKS
+ then
+ ln -s "$1" "$2" &&
+ git update-index --add "$2"
+ else
+ printf '%s' "$1" >"$2" &&
+ ln_s_obj=$(git hash-object -w "$2") &&
+ git update-index --add --cacheinfo 120000 $ln_s_obj "$2" &&
+ # pick up stat info from the file
+ git update-index "$2"
+ fi
+}
+
+# This function writes out its parameters, one per line
+test_write_lines () {
+ printf "%s\n" "$@"
+}
+
+perl () {
+ command "$PERL_PATH" "$@"
+}
+
+# Is the value one of the various ways to spell a boolean true/false?
+test_normalize_bool () {
+ git -c magic.variable="$1" config --bool magic.variable 2>/dev/null
+}
+
+# Given a variable $1, normalize the value of it to one of "true",
+# "false", or "auto" and store the result to it.
+#
+# test_tristate GIT_TEST_HTTPD
+#
+# A variable set to an empty string is set to 'false'.
+# A variable set to 'false' or 'auto' keeps its value.
+# Anything else is set to 'true'.
+# An unset variable defaults to 'auto'.
+#
+# The last rule is to allow people to set the variable to an empty
+# string and export it to decline testing the particular feature
+# for versions both before and after this change. We used to treat
+# both unset and empty variable as a signal for "do not test" and
+# took any non-empty string as "please test".
+
+test_tristate () {
+ if eval "test x\"\${$1+isset}\" = xisset"
+ then
+ # explicitly set
+ eval "
+ case \"\$$1\" in
+ '') $1=false ;;
+ auto) ;;
+ *) $1=\$(test_normalize_bool \$$1 || echo true) ;;
+ esac
+ "
+ else
+ eval "$1=auto"
+ fi
+}
+
+# Exit the test suite, either by skipping all remaining tests or by
+# exiting with an error. If "$1" is "auto", we then we assume we were
+# opportunistically trying to set up some tests and we skip. If it is
+# "true", then we report a failure.
+#
+# The error/skip message should be given by $2.
+#
+test_skip_or_die () {
+ case "$1" in
+ auto)
+ skip_all=$2
+ test_done
+ ;;
+ true)
+ error "$2"
+ ;;
+ *)
+ error "BUG: test tristate is '$1' (real error: $2)"
+ esac
+}
+
+# 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
+}