# Common helper routines for test shell scripts -- to be sourced by them # @configure_input@ #### The following variables are set by "make check". Ensure #### that they are set here so that individual tests can be run #### outside of make. Requires that MH_OBJ_DIR be set on entry. #### Use the result of cd and pwd -P so that the result will agree #### with what getcwd(3) returns. test -d "$MH_OBJ_DIR/test/testdir" || mkdir -p "$MH_OBJ_DIR/test/testdir" test -z "$MH_TEST_DIR" && MH_TEST_DIR=`cd "$MH_OBJ_DIR/test/testdir" && pwd -P` export MH_TEST_DIR test -z "$MH_INST_DIR" && MH_INST_DIR="${MH_TEST_DIR}/inst" test -z "$MH_VERSION" && MH_VERSION="@VERSION@" test -z "$prefix" && prefix=@prefix@ test -z "$datarootdir" && datarootdir=@datarootdir@ test -z "$exec_prefix" && exec_prefix=@exec_prefix@ test -z "$bindir" && bindir="@bindir@" test -z "$mandir" && mandir="@mandir@" test -z "$nmhetcdir" && nmhetcdir="@sysconfdir@/nmh" #### The following doesn't support running the distcheck version of #### test-mhparam standalone, but only via make distcheck. test -z "$nmhetcdirinst" && nmhetcdirinst="@nmhetcdirinst@$nmhetcdir" test -z "$nmhlibexecdir" && nmhlibexecdir="@libexecdir@/nmh" test -z "$supported_locks" && supported_locks="@supported_locks@" test -z "$default_locking" && default_locking="@default_locking@" test -z "$MULTIBYTE_ENABLED" && MULTIBYTE_ENABLED="@MULTIBYTE_ENABLED@" test -z "$ICONV_ENABLED" && ICONV_ENABLED="@ICONV_ENABLED@" test -z "$OAUTH_SUPPORT" && OAUTH_SUPPORT="@OAUTH_SUPPORT@" test -z "$CURL_USER_AGENT" && CURL_USER_AGENT="@CURL_USER_AGENT@" #### If w3m is used, HOME needs to be set, assuming default w3m config. #### So make sure that HOME is set to avoid run-time warning about not #### being able to create config directory. test -z "$HOME" && HOME=$MH_TEST_DIR HOME=$MH_TEST_DIR export HOME #### If w3m is used, HOME needs to be set, assuming default w3m config. #### So make sure that HOME is set to avoid run-time warning about not #### being able to create config directory. test -z "$HOME" && HOME=$MH_TEST_DIR HOME=$MH_TEST_DIR export HOME unset MAILDROP MHBUILD MHCONTEXT MHMTSUSERCONF MHN MHSHOW MHSTORE unset MHLDEBUG MHPDEBUG MHWDEBUG PAGER XOAUTH SMTPUTF8 #### Set LC_ALL in individual tests as needed. Unset these so #### that we don't depend on user's settings in other tests. unset LANG LC_ALL LC_CTYPE #### Use a test dir for tmp files when MHTMPDIR applies. MHTMPDIR=$MH_TEST_DIR/Mail export MHTMPDIR #### If you're reading this .... you can set MH_TEST_NOCLEANUP to prevent #### the test suite from cleaning up the results of a test run, if you need #### to do manual debugging on a test. output_md5() { #### Output just the checksum. If the filename needs to appear on #### the same line, the caller needs to add it. This avoids #### differences due to a leading '*' binary file indicator, for #### text files, on some platforms (Cygwin). @MD5SUM@ $* | @MD5FMT@ | awk '{print $1}' } #### Use built-in $((...)) in test suite if shell supports it. #### Borrowed from configure's as_fn_arith. The result is placed #### in global arith_val. #### Detected at run-time instead of by configure to allow testing #### with different shells. if (eval "test \$(( 1 + 1 )) = 2" 2>/dev/null); then eval 'arith_eval () { arith_val=$(( $* )); }' else arith_eval () { arith_val=`expr "$@" || test $? -eq 1`; } fi test_skip () { WHY="$1" echo "$Test $0 SKIP ($WHY)" exit 77 } # portable implementation of 'which' utility findprog() { PROG="$1" #### Don't need to save current IFS because this function is run in #### a subshell. IFS=: for D in $PATH; do if [ -z "$D" ]; then D=. fi if [ -f "$D/$PROG" -a -x "$D/$PROG" ]; then printf '%s\n' "$D/$PROG" break fi done } require_prog () { if [ -z "`findprog $1`" ]; then test_skip "missing $1" fi } # Skip test if none of the offered locales are supported. # As side effect, use the first locale that is found. Note that # some platforms allow, by way of example, en_US.UTF-8 to be used # even though en_US.UTF8 is listed by locale -a. But by setting # LC_ALL here, we don't rely on that. require_locale () { for locale in "$@"; do if locale -a | grep -i "$locale" >/dev/null; then LC_ALL="$locale"; export LC_ALL return fi done test_skip "no suitable locale available" } # Some stuff for doing silly progress indicators if [ -t 1 ] ; then progress_update () { THIS="$1" FIRST="$2" LAST="$3" arith_eval $LAST - $FIRST; RANGE=$arith_val arith_eval $THIS - $FIRST; PROG=$arith_val # this automatically rounds to nearest integer arith_eval 100 \* $PROG / $RANGE; PERC=$arith_val # note \r so next update will overwrite printf '%3d%%\r' $PERC } progress_done () { printf '100%%\n' } else # don't emit anything if stdout is not connected to a tty. progress_update () { : } progress_done () { : } fi check_for_hard_links () { set +e printf '' > "${MH_TEST_DIR}/$$-1" xdir_links_supported=0 if link "${MH_TEST_DIR}/$$-1" "${MH_TEST_DIR}/$$-2" 2>/dev/null; then hard_links_supported=1 mkdir "${MH_TEST_DIR}/xlinkdir" if link "${MH_TEST_DIR}/$$-1" "${MH_TEST_DIR}/xlinkdir/$$-2" 2>/dev/null; then xdir_links_supported=1 fi else hard_links_supported=0 fi rm -f "${MH_TEST_DIR}/$$-1" "${MH_TEST_DIR}/$$-2" rm -rf "${MH_TEST_DIR}/xlinkdir" set -e } #### Filter that squeezes blank lines, partially emulating GNU cat -s, #### but sufficient for our purpose. #### From http://www-rohan.sdsu.edu/doc/sed.html, compiled by Eric Pement. squeeze_lines() { sed '/^$/N;/\n$/D' } #### Filter that converts non-breakable space U+00A0 to an ASCII space. prepare_space() { sed 's/'"`printf '\\302\\240'`"'/ /g' } #### check() requires two arguments, each the name of a file to be #### diff'ed. #### If the contents are same, the second file is removed. If different, #### global variable "failed" is incremented. #### Optional arguments: #### 'keep first' -- first file is removed unless this is present. #### 'ignore space' -- spacing differences will not be considered #### significant, emulating GNU diff -w. It is assumed that the #### first file has already been run through prepare_space. #### ':' -- will print '' in the failure message, #### to make it easier to tell which of multiple tests has failed. check() { first=$1; shift second=$1; shift keepfirst= ignorespace= label=test while [ $# -gt 0 ]; do case $1 in 'keep first') keepfirst=1 ;; 'ignore space') ignorespace=1 ;; ':') shift; label=\'"$*"\'; break ;; *) echo "$0: invalid check() argument \"$1\" in test suite" >&2 ;; esac shift done success= if [ "$ignorespace" ]; then #### POSIX diff should support -b. prepare_space <"$second" | diff -b "$first" - >/dev/null && success=1 else cmp -s "$first" "$second" && success=1 fi if [ "$success" ]; then [ "$keepfirst" ] || rm -f "$first" rm -f "$second" else echo #### POSIX diff should support -c. diff -c "$first" "$second" || true echo echo "$0: $label failed, outputs are in $first and $second." failed=`expr ${failed:-0} + 1` #### Set return status of the function. [ $failed -eq 0 ] fi } #### Shortcut to enable use of valgrind: set NMH_VALGRIND environment #### variable (to anything) so run_* will use valgrind. if [ "${NMH_VALGRIND}" -a -z "${NMH_TEST_PREFIX}" ]; then #### Need absolute path to valgrind.supp in case the test does a cd. NMH_TEST_PREFIX="valgrind --quiet --error-exitcode=1 \ --suppressions=`cd ${srcdir} && pwd`/test/valgrind.supp" fi #### Run test under another program by setting NMH_TEST_PREFIX #### environment variable to, e.g., 'valgrind --quiet'. run_prog() { case $1 in #### Don't run valgrind on shell built-in. eval\ *) "$@" ;; *) ${NMH_TEST_PREFIX} "$@" ;; esac } #### run_test() requires two arguments, the first is a program and #### arguments, the second is its expected one-line output string. #### If the actual output does not match that string: #### an error message is printed and global variable "failed" is incremented; #### if there is an optional third argument, it is used in the error message. run_test() { set +e case $1 in #### Don't run valgrind on shell built-in. eval\ *) actual_output=`$1 2>&1` ;; *) actual_output=`${NMH_TEST_PREFIX} $1 2>&1` ;; esac set -e if test x"$actual_output" != x"$2"; then echo "$0: ${3:-\"$1\"} expected:" 1>&2 echo " '$2'" 1>&2 echo "but instead got:" 1>&2 echo " '$actual_output'" 1>&2 failed=`expr ${failed:-0} + 1` fi } #### check_exit() runs the command in $2..., capturing stdout and #### stderr, and then tests its exit status with the test(1) condition #### in $1. If that fails, the captured stdout and stderr are #### displayed, and $failed incremented. check_exit() { c="$1"; shift t="$MH_TEST_DIR/.check_exit" r=0 $NMH_TEST_PREFIX "$@" >"$t.1" 2>"$t.2" || r=$? if test $r $c; then rm "$t.1" "$t.2" else echo "$0: check_exit: $r $c failed: $*" >&2 echo " stdout:" >&2 sed 's/^/ /' "$t.1" >&2 echo " stderr:" >&2 sed 's/^/ /' "$t.2" >&2 failed=`expr ${failed:-0} + 1` fi } #### Function invoked by trap on exit. cleanup() { #### Save exit status to use as status for this program. status=$? #### Clean up test mail space. #### cd to $MH_TEST_DIR before trying to remove its Mail #### subdirectory. rm on Solaris won't remove it if it's in the #### path of the current working directory. test -z "$MH_TEST_NOCLEANUP" && (cd $MH_TEST_DIR; rm -rf "$MH_TEST_DIR"/Mail) #### Report test name if set, which indicates failure. #### Relies on set -e to invoke the trap which calls #### this function on failure. #### To use: #### 1) Set test name before running the test, use start_test(). #### 2) Unset upon successful completion, use finish_test(). if test -n "$nmh_tests_testname"; then echo $nmh_tests_testname failed fi #### Exit with non-zero status if failure. Failure is defined as either #### non-empty nmh_tests_testname or non-zero exit status on entry to the #### function. if test -n "$nmh_tests_testname" -o $status -ne 0; then test $status -ne 0 && exit $status || exit 1 test $status -ne 0 && exit 0 || exit 0 fi } #### Function to set the test name, and whatever the future brings. start_test() { #### run_test disables exit on non-zero status, but does increment #### failed. Don't overwrite nmh_tests_testname if there was a #### failure; remember the first test that failed. [ ${failed:-0} -eq 0 ] && nmh_tests_testname="$1" } #### Corresponding function to indicate that the test has finished. It need #### not be called after each test, just the last one in a file. finish_test() { #### run_test disables exit on non-zero status, but does increment #### failed. Don't unset nmh_tests_testname if there was a failure. [ ${failed:-0} -eq 0 ] && unset nmh_tests_testname } setup_test () { set -e MH="${MH_TEST_DIR}/Mail/.mh_profile" MHMTSCONF="${MH_INST_DIR}${nmhetcdir}/mts.conf" MH_LIBEXEC_DIR="${MH_INST_DIR}${nmhlibexecdir}" export MH MHMTSCONF MH_LIBEXEC_DIR # # Only install once # if [ -d "${MH_INST_DIR}${bindir}" ]; then : else (cd "${MH_OBJ_DIR}" && make DESTDIR="${MH_INST_DIR}" SETGID_MAIL= install) || exit 1 #### Don't test with sendmail because it would really send the #### mail. If configured to use sendmail, change to smtp instead #### so that we use fakesmtp. #### And set up the maildrop in the test directory so tests don't #### use the user's real maildrop. #### test-slocal needs to look at the original mts.conf, so save it. mv -f "${MHMTSCONF}" "${MHMTSCONF}.old" sed -e 's/mts: *.*/mts: smtp/' \ -e "s%mmdfldir: *.*%mmdfldir: ${MH_TEST_DIR}/Mail%" \ -e 's%mmdflfil: *.*%mmdflfil: maildrop%' \ "${MHMTSCONF}.old" >"${MHMTSCONF}" fi #### On Solaris, must set PATH after the install! PATH="${MH_INST_DIR}${bindir}:${PATH}" export PATH # clean old test data on exit trap cleanup 0 # setup test data mkdir -p "$MH_TEST_DIR/Mail" || exit 1 cat > "$MH" < /dev/null #### Suppress warnings about a new version. #### mhparam version includes the nmh- prefix, so be consistent with that. printf 'Version: nmh-%s\n' "${MH_VERSION}" >> "${MH_TEST_DIR}"/Mail/context # create 10 basic messages for i in 1 2 3 4 5 6 7 8 9 10; do cat > $MH_TEST_DIR/Mail/inbox/$i < To: Some User Date: Fri, 29 Sep 2006 00:00:00 Message-Id: $i@test.nmh Subject: Testing message $i This is message number $i EOF done }