exit 1
fi
+# Make sure echo builtin does not expand backslash-escape sequences by default.
+shopt -u xpg_echo
+
# 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
# Keep the original TERM for say_color and test_emacs
ORIGINAL_TERM=$TERM
+# dtach(1) provides more capable terminal environment to anything
+# that requires more than dumb terminal...
+[ x"${TERM:-dumb}" = xdumb ] && DTACH_TERM=vt100 || DTACH_TERM=$TERM
+
# For repeatability, reset the environment to known value.
LANG=C
LC_ALL=C
test_broken=0
test_success=0
-die () {
+_die_common () {
code=$?
+ trap - EXIT
+ set +ex
rm -rf "$TEST_TMPDIR"
+}
+
+die () {
+ _die_common
if test -n "$GIT_EXIT_OK"
then
exit $code
else
- echo >&5 "FATAL: Unexpected exit with code $code"
+ exec >&5
+ say_color error '%-6s' FATAL
+ echo " $test_subtest_name"
+ echo
+ echo "Unexpected exit while executing $0. Exit code $code."
exit 1
fi
}
+die_signal () {
+ _die_common
+ echo >&5 "FATAL: $0: interrupted by signal" $((code - 128))
+ exit $code
+}
+
GIT_EXIT_OK=
# Note: TEST_TMPDIR *NOT* exported!
TEST_TMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/notmuch-test-$$.XXXXXX")
trap 'die' EXIT
+trap 'die_signal' HUP INT TERM
test_decode_color () {
sed -e 's/.\[1m/<WHITE>/g' \
fi
if [ -z "${template[date]}" ]; then
- template[date]="Fri, 05 Jan 2001 15:43:57 +0000"
+ # we use decreasing timestamps here for historical reasons;
+ # the existing test suite when we converted to unique timestamps just
+ # happened to have signicantly fewer failures with that choice.
+ template[date]=$(TZ=UTC printf "%(%a, %d %b %Y %T %z)T\n" \
+ $((978709437 - gen_msg_cnt)))
fi
additional_headers=""
test_emacs \
"(let ((message-send-mail-function 'message-smtpmail-send-it)
+ (mail-host-address \"example.com\")
(smtpmail-smtp-server \"localhost\")
(smtpmail-smtp-service \"25025\"))
(notmuch-hello)
notmuch new >/dev/null
}
+# Pretend to deliver a message with emacs. Really save it to a file
+# and add it to the database
+#
+# Uses emacs to generate and deliver a message to the mail store.
+# Accepts arbitrary extra emacs/elisp functions to modify the message
+# before sending, which is useful to doing things like attaching files
+# to the message and encrypting/signing.
+emacs_fcc_message ()
+{
+ local subject="$1"
+ local body="$2"
+ shift 2
+ # before we can send a message, we have to prepare the FCC maildir
+ mkdir -p "$MAIL_DIR"/sent/{cur,new,tmp}
+
+ test_emacs \
+ "(let ((message-send-mail-function (lambda () t))
+ (mail-host-address \"example.com\"))
+ (notmuch-mua-mail)
+ (message-goto-to)
+ (insert \"test_suite@notmuchmail.org\nDate: 01 Jan 2000 12:00:00 -0000\")
+ (message-goto-subject)
+ (insert \"${subject}\")
+ (message-goto-body)
+ (insert \"${body}\")
+ $@
+ (message-send-and-exit))" || return 1
+ notmuch new >/dev/null
+}
+
# Generate a corpus of email and add it to the database.
#
# This corpus is fixed, (it happens to be 50 messages from early in
if ! test_skip "$test_subtest_name"
then
if [ "$output" = "$expected" ]; then
- test_ok_ "$test_subtest_name"
+ test_ok_
else
testname=$this_test.$test_count
echo "$expected" > $testname.expected
echo "$output" > $testname.output
- test_failure_ "$test_subtest_name" "$(diff -u $testname.expected $testname.output)"
+ test_failure_ "$(diff -u $testname.expected $testname.output)"
fi
fi
}
if ! test_skip "$test_subtest_name"
then
if diff -q "$file1" "$file2" >/dev/null ; then
- test_ok_ "$test_subtest_name"
+ test_ok_
else
testname=$this_test.$test_count
cp "$file1" "$testname.$basename1"
cp "$file2" "$testname.$basename2"
- test_failure_ "$test_subtest_name" "$(diff -u "$testname.$basename1" "$testname.$basename2")"
+ test_failure_ "$(diff -u "$testname.$basename1" "$testname.$basename2")"
fi
fi
}
# canonicalized before diff'ing. If an argument cannot be parsed, it
# is used unchanged so that there's something to diff against.
test_expect_equal_json () {
- output=$(echo "$1" | python -mjson.tool || echo "$1")
- expected=$(echo "$2" | python -mjson.tool || echo "$2")
+ # The test suite forces LC_ALL=C, but this causes Python 3 to
+ # decode stdin as ASCII. We need to read JSON in UTF-8, so
+ # override Python's stdio encoding defaults.
+ output=$(echo "$1" | PYTHONIOENCODING=utf-8 python -mjson.tool \
+ || echo "$1")
+ expected=$(echo "$2" | PYTHONIOENCODING=utf-8 python -mjson.tool \
+ || echo "$2")
shift 2
test_expect_equal "$output" "$expected" "$@"
}
result=$(cat OUTPUT)
if [ "$result" = t ]
then
- test_ok_ "$test_subtest_name"
+ test_ok_
else
- test_failure_ "$test_subtest_name" "${result}"
+ test_failure_ "${result}"
fi
else
# Restore state after the (non) test.
notmuch_search_sanitize ()
{
- sed -r -e 's/("?thread"?: ?)("?)................("?)/\1\2XXX\3/'
+ perl -pe 's/("?thread"?: ?)("?)................("?)/\1\2XXX\3/'
}
NOTMUCH_SHOW_FILENAME_SQUELCH='s,filename:.*/mail,filename:/XXX/mail,'
{
sed \
-e 's| filename:.*| filename:XXXXX|' \
- -e 's| id:[^ ]* | id:XXXXX |'
+ -e 's| id:[^ ]* | id:XXXXX |' | \
+ notmuch_date_sanitize
}
notmuch_json_show_sanitize ()
{
sed \
-e 's|"id": "[^"]*",|"id": "XXXXX",|g' \
- -e 's|"filename": "[^"]*",|"filename": "YYYYY",|g'
+ -e 's|"Date": "Fri, 05 Jan 2001 [^"]*0000"|"Date": "GENERATED_DATE"|g' \
+ -e 's|"filename": "/[^"]*",|"filename": "YYYYY",|g' \
+ -e 's|"timestamp": 97.......|"timestamp": 42|g'
}
+notmuch_emacs_error_sanitize ()
+{
+ local command=$1
+ shift
+ for file in "$@"; do
+ echo "=== $file ==="
+ cat "$file"
+ done | sed \
+ -e 's/^\[.*\]$/[XXX]/' \
+ -e "s|^\(command: \)\{0,1\}/.*/$command|\1YYY/$command|"
+}
+
+notmuch_date_sanitize ()
+{
+ sed \
+ -e 's/^Date: Fri, 05 Jan 2001 .*0000/Date: GENERATED_DATE/'
+}
# End of notmuch helper functions
# Use test_set_prereq to tell that a particular prerequisite is available.
esac
}
+declare -A test_missing_external_prereq_
+declare -A test_subtest_missing_external_prereq_
+
# declare prerequisite for the given external binary
test_declare_external_prereq () {
binary="$1"
test "$#" = 2 && name=$2 || name="$binary(1)"
- hash $binary 2>/dev/null || eval "
- test_missing_external_prereq_${binary}_=t
+ if ! hash $binary 2>/dev/null; then
+ test_missing_external_prereq_["${binary}"]=t
+ eval "
$binary () {
- echo -n \"\$test_subtest_missing_external_prereqs_ \" | grep -qe \" $name \" ||
- test_subtest_missing_external_prereqs_=\"\$test_subtest_missing_external_prereqs_ $name\"
+ test_subtest_missing_external_prereq_[\"${name}\"]=t
false
}"
+ fi
}
# Explicitly require external prerequisite. Useful when binary is
# Returns success if dependency is available, failure otherwise.
test_require_external_prereq () {
binary="$1"
- if [ "$(eval echo -n \$test_missing_external_prereq_${binary}_)" = t ]; then
+ if [[ ${test_missing_external_prereq_["${binary}"]} == t ]]; then
# dependency is missing, call the replacement function to note it
eval "$binary"
else
test_ok_ () {
if test "$test_subtest_known_broken_" = "t"; then
- test_known_broken_ok_ "$@"
+ test_known_broken_ok_
return
fi
test_success=$(($test_success + 1))
say_color pass "%-6s" "PASS"
- echo " $@"
+ echo " $test_subtest_name"
}
test_failure_ () {
return
fi
test_failure=$(($test_failure + 1))
- test_failure_message_ "FAIL" "$@"
+ test_failure_message_ "FAIL" "$test_subtest_name" "$@"
test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
return 1
}
test_reset_state_
test_fixed=$(($test_fixed+1))
say_color pass "%-6s" "FIXED"
- echo " $@"
+ echo " $test_subtest_name"
}
test_known_broken_failure_ () {
test_reset_state_
test_broken=$(($test_broken+1))
- test_failure_message_ "BROKEN" "$@"
+ test_failure_message_ "BROKEN" "$test_subtest_name" "$@"
return 1
}
}
test_check_missing_external_prereqs_ () {
- if test -n "$test_subtest_missing_external_prereqs_"; then
- say_color skip >&1 "missing prerequisites:"
- echo "$test_subtest_missing_external_prereqs_" >&1
+ if [[ ${#test_subtest_missing_external_prereq_[@]} != 0 ]]; then
+ say_color skip >&1 "missing prerequisites: "
+ echo ${!test_subtest_missing_external_prereq_[@]} >&1
test_report_skip_ "$@"
else
false
test "$#" = 3 && { prereq=$1; shift; } || prereq=
test "$#" = 2 ||
error "bug in the test script: not 2 or 3 parameters to test-expect-success"
+ test_subtest_name="$1"
test_reset_state_
if ! test_skip "$@"
then
test_check_missing_external_prereqs_ "$@" ||
if [ "$run_ret" = 0 -a "$eval_ret" = 0 ]
then
- test_ok_ "$1"
+ test_ok_
else
- test_failure_ "$@"
+ test_failure_ "$2"
fi
fi
}
test "$#" = 4 && { prereq=$1; shift; } || prereq=
test "$#" = 3 ||
error "bug in the test script: not 3 or 4 parameters to test-expect-code"
+ test_subtest_name="$2"
test_reset_state_
if ! test_skip "$@"
then
test_check_missing_external_prereqs_ "$@" ||
if [ "$run_ret" = 0 -a "$eval_ret" = "$1" ]
then
- test_ok_ "$2"
+ test_ok_
else
- test_failure_ "$@"
+ test_failure_ "exit code $eval_ret, expected $1" "$3"
fi
fi
}
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"
+ test_subtest_name="$1"
shift
test_reset_state_
- if ! test_skip "$descr" "$@"
+ if ! test_skip "$test_subtest_name" "$@"
then
# Announce the script to reduce confusion about the
# test output that follows.
"$@" 2>&4
if [ "$?" = 0 ]
then
- test_ok_ "$descr"
+ test_ok_
else
- test_failure_ "$descr" "$@"
+ test_failure_ "$@"
fi
fi
}
stderr="$tmp/git-external-stderr.$$.tmp"
test_external "$@" 4> "$stderr"
[ -f "$stderr" ] || error "Internal error: $stderr disappeared."
- descr="no stderr: $1"
+ test_subtest_name="no stderr: $1"
shift
if [ ! -s "$stderr" ]; then
rm "$stderr"
- test_ok_ "$descr"
+ test_ok_
else
if [ "$verbose" = t ]; then
output=`echo; echo Stderr is:; cat "$stderr"`
fi
# rm first in case test_failure exits.
rm "$stderr"
- test_failure_ "$descr" "$@" "$output"
+ test_failure_ "$@" "$output"
fi
}
fi
server_name="notmuch-test-suite-$$"
# start a detached session with an emacs server
- # user's TERM is given to dtach which assumes a minimally
+ # user's TERM (or 'vt100' in case user's TERM is unset, empty
+ # or 'dumb') is given to dtach which assumes a minimally
# VT100-compatible terminal -- and emacs inherits that
- TERM=$ORIGINAL_TERM dtach -n "$TEST_TMPDIR/emacs-dtach-socket.$$" \
+ TERM=$DTACH_TERM dtach -n "$TEST_TMPDIR/emacs-dtach-socket.$$" \
sh -c "stty rows 24 cols 80; exec '$TMP_DIRECTORY/run_emacs' \
--no-window-system \
$load_emacs_tests \
# most others as /usr/bin/python. So first try python2, and fallback to
# python if python2 doesn't exist.
cmd=python2
- [[ "$test_missing_external_prereq_python2_" = t ]] && cmd=python
+ [[ ${test_missing_external_prereq_[python2]} == t ]] && cmd=python
(echo "import sys; _orig_stdout=sys.stdout; sys.stdout=open('OUTPUT', 'w')"; cat) \
| $cmd -
test -z "$test_init_done_" && test_init_
test_subtest_known_broken_=
- test_subtest_missing_external_prereqs_=
+ test_subtest_missing_external_prereq_=()
}
# called once before the first subtest