#!/bin/sh
# Test all combinations of alignment of the end-of-message delimiter
# with the end of a stdio buffer

set -e

if test -z "${MH_OBJ_DIR}"; then
    srcdir=`dirname "$0"`/../..
    MH_OBJ_DIR=`cd "$srcdir" && pwd`; export MH_OBJ_DIR
fi

. "$MH_OBJ_DIR/test/common.sh"

setup_test

THISDIR="$srcdir/test/inc"

if [ -z "$VALGRIND_ME" ]; then
    VALGRIND=
else
    require_prog valgrind
    # Lack of quotes here is important
    VALGRIND="valgrind --quiet --error-exitcode=1"
    echo "Running tests under valgrind: takes ages!"
fi

# First check that all our various pieces of text are
# intact. (Since we're dealing in exact byte alignment
# minor corruptions such as line ending changes could
# render the tests useless.)
(cd "$THISDIR"  && \
 for i in *.txt; do
   echo `output_md5 $i`'  '"$i" >> "$MH_TEST_DIR/inctest.md5sums"
 done)
check "$THISDIR/md5sums" "$MH_TEST_DIR/inctest.md5sums" 'keep first'

f="$MH_TEST_DIR/mmdf-magic"
printf '\1\1\1\1\n' >$f
got="`output_md5 $f`"
want=2636d725e650779eca70d6564c4f5982
if test "$got" != "$want"; then
    printf '%s: MMDF magic: %s: got %s, want %s\n' \
        "$0" "$f" "$got" "$want" >&2
    exit 1
fi
mmdf_magic="$f"

empty_line="$MH_TEST_DIR/empty-line"
printf '\n' >"$empty_line"

FILLER="$THISDIR/filler.txt"
FROMLINE="$THISDIR/fromline.txt"
HDR="$THISDIR/msgheader.txt"

if grep From "$FILLER" >/dev/null; then
   echo "Somebody's messed with $FILLER -- it must not contain"
   echo "anything that might look like a message delimiter!"
   exit 1
fi

# a sort of worst-case guess for the buffer size;
# obviously a buffer boundary for this will be a boundary
# for any smaller power of two size.
# If you need to increase this you'll need to make filler.txt
# bigger as well.
STDIO_BUFSZ=16384

FROMLINESZ=`wc -c < "$FROMLINE"`
MMDFDELIMLINESZ=`wc -c <"$mmdf_magic"`
HDRSZ=`wc -c < "$HDR"`

# makembox_A mboxname sz
# Assemble a mailbox into file mboxname, with two messages, such
# that the first is exactly sz bytes long (including its header
# and its initial 'From' line and the newline which terminates it
# but not the newline which mbox format demands after each message)
# We also leave the body of message one in mboxname.body
# (the body of message two is always $FILLER in its entirety)
makembox_A () {
  MBOX="$1"
  SZ=$2

  arith_eval $SZ - $HDRSZ - $FROMLINESZ - 1; WANTSZ=$arith_val
  dd if="$FILLER" of="$MBOX.body" bs="$WANTSZ" count=1 2>/dev/null
  echo >> "$MBOX.body"
  cat "$FROMLINE" "$HDR" "$MBOX.body" "$empty_line" \
      "$FROMLINE" "$HDR" "$FILLER" "$empty_line" >"$MBOX"
}

# makemmdf_A mmdfboxname sz
# The first email in $MBOX will be sz bytes long, including its MMDF
# magic strings that top and tail it.
makemmdf_A () {
  MBOX="$1"
  SZ=$2

  arith_eval $SZ - $MMDFDELIMLINESZ - $HDRSZ - 1 - $MMDFDELIMLINESZ; WANTSZ=$arith_val
  dd if="$FILLER" of="$MBOX.body" bs="$WANTSZ" count=1 2>/dev/null
  echo >> "$MBOX.body"
  cat "$mmdf_magic" "$HDR" "$MBOX.body" "$mmdf_magic" \
    "$mmdf_magic" "$HDR" "$FILLER" "$mmdf_magic" >"$MBOX"
}

# make_mbox_B mboxname sz
# Test B makes a mailbox with one message of sz bytes long,
# which ends in a partial mbox delimiter (ie part of the string
# \n\nFrom '). To both do this and be a valid mbox this means
# it has to end with two newlines (one of which is in the message
# body and one of which is the mbox format mandated one)
makembox_B () {
  MBOX="$1"
  SZ=$2

  arith_eval $SZ - $HDRSZ - $FROMLINESZ - 1; WANTSZ=$arith_val
  dd if="$FILLER" of="$MBOX.body" bs="$WANTSZ" count=1 2>/dev/null
  echo >> "$MBOX.body"
  cat "$FROMLINE" "$HDR" "$MBOX.body" "$empty_line" >"$MBOX"
}

# makemmdf_B mmdfboxname sz
# The mbox file will be sz bytes and contain a single email, topped and
# tailed with MMDF's magic strings.  The end of the email's body looks
# the same as the magic string for three bytes.
makemmdf_B () {
  MBOX="$1"
  SZ=$2

  arith_eval $SZ - $MMDFDELIMLINESZ - $HDRSZ - 1 - 4 - $MMDFDELIMLINESZ; WANTSZ=$arith_val
  dd if="$FILLER" of="$MBOX.body" bs="$WANTSZ" count=1 2>/dev/null
  printf '\n\1\1\1\n' >>"$MBOX.body"
  cat "$mmdf_magic" "$HDR" "$MBOX.body" "$mmdf_magic" >"$MBOX"
}

# do_one_test_A sz mbox_type
# Do a single test with message one's body of size sz.
do_one_test_A () {
  SZ=$1
  MBOX_TYPE=$2
  printf '%5s %s A\r' $SZ $MBOX_TYPE
  make${MBOX_TYPE}_A "$MH_TEST_DIR/eom-align.mbox" $SZ
  $VALGRIND inc -silent -file "$MH_TEST_DIR/eom-align.mbox"
  # We know the messages should be 11 and 12 in inbox
  # Now get the bodies back out.
  body1="$MH_TEST_DIR/eom-align.inbox.body1"
  body2="$MH_TEST_DIR/eom-align.inbox.body2"
  sed -e '1,/^$/d' "$MH_TEST_DIR/Mail/inbox/11" > "$body1"
  sed -e '1,/^$/d' "$MH_TEST_DIR/Mail/inbox/12" > "$body2"
  check "$MH_TEST_DIR/eom-align.mbox.body" "$body1" 'keep first'
  check "$FILLER" "$body2" 'keep first'
  rm "$MH_TEST_DIR/Mail/inbox/11" "$MH_TEST_DIR/Mail/inbox/12"
}

# do_one_test_B sz mbox_type
# Do a test type B
do_one_test_B () {
  SZ=$1
  MBOX_TYPE=$2
  printf '%5s %s B\r' $SZ $MBOX_TYPE
  make${MBOX_TYPE}_B "$MH_TEST_DIR/eom-align.mbox" $SZ
  $VALGRIND inc -silent -file "$MH_TEST_DIR/eom-align.mbox"
  # We know the message should be 11 in the inbox
  body1="$MH_TEST_DIR/eom-align.inbox.body1"
  sed -e '1,/^$/d' "$MH_TEST_DIR/Mail/inbox/11" > "$body1"
  check "$MH_TEST_DIR/eom-align.mbox.body" "$body1" 'keep first'
  rm "$MH_TEST_DIR/Mail/inbox/11"
}

# Cover a decent range around the stdio buffer size to make sure we catch
# any corner cases whether they relate to total message size equal to
# buffer size or to body size equal to buffer size.
arith_eval $STDIO_BUFSZ - 16; START=$arith_val
arith_eval $STDIO_BUFSZ + $HDRSZ + $FROMLINESZ + 32; FINISH=$arith_val
[ -t 1 ]  &&  echo \
"Testing inc of files with various alignments of eom marker with buffer size..."

#### Trouble spots for the particular input, with BUFSZ of 8192:
for sz in 3146 3147 7241 7242 7243 11338 11339 15433 15434 15435; do
  do_one_test_A $sz mbox
  do_one_test_A $sz mmdf
done

# Also 155, 174, 175, but they're too small for makembox_B to handle.
for sz in 684 4074 4097 4148 4610 4611 5121 5122 6654 6655 8170 \
          8193 8244 8364 12266 12289 12340 16362 16385 16436; do
  do_one_test_B $sz mbox
  do_one_test_B $sz mmdf
done

i="$START"
while test $i -le $FINISH; do
  do_one_test_A $i mbox
  do_one_test_B $i mbox
  do_one_test_A $i mmdf
  do_one_test_B $i mmdf
  i=`expr $i + 1`
done
printf '\n'

test ${failed:-0} -eq 0  &&  \
rm "$MH_TEST_DIR/eom-align.mbox" "$MH_TEST_DIR/eom-align.mbox.body" \
   "$mmdf_magic" "$empty_line"

exit $failed
