#! /bin/sh
#
# Test suite for xmalloc and friends.
#
# Copyright 2008 Board of Trustees, Leland Stanford Jr. University
# Copyright 2004, 2005, 2006
#     by Internet Systems Consortium, Inc. ("ISC")
# Copyright 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
#     2003 by The Internet Software Consortium and Rich Salz
#
# This code is derived from software contributed to the Internet Software
# Consortium by Rich Salz.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.

# The count starts at 1 and is updated each time ok is printed.  printcount
# takes "ok" or "not ok".
count=1
printcount () {
    echo "$1 $count $2"
    count=`expr $count + 1`
}

# Run a program expected to succeed, and print ok if it does.
runsuccess () {
    output=`$xmalloc "$1" "$2" "$3" 2>&1 >/dev/null`
    status=$?
    if test $status = 0 && test -z "$output" ; then
        printcount "ok"
    else
        if test $status = 2 ; then
            printcount "ok" "# skip - no data limit support"
        else
            printcount "not ok"
            echo "  $output"
        fi
    fi
}

# Run a program expected to fail and make sure it fails with an exit status
# of 2 and the right failure message.  Strip the colon and everything after
# it off the error message since it's system-specific.
runfailure () {
    output=`$xmalloc "$1" "$2" "$3" 2>&1 >/dev/null`
    status=$?
    output=`echo "$output" | sed 's/:.*//' \
                | sed 's% [^ ]*/xmalloc.c% xmalloc.c%'`
    if test $status = 1 && test x"$output" = x"$4" ; then
        printcount "ok"
    else
        if test $status = 2 ; then
            printcount "ok" "# skip - no data limit support"
        else
            printcount "not ok"
            echo "  saw: $output"
            echo "  not: $4"
        fi
    fi
}

# Find where the helper program is.
xmalloc=xmalloc
for file in ./xmalloc util/xmalloc tests/util/xmalloc ; do
    [ -x $file ] && xmalloc=$file
done

# Total tests.
echo 36

# First run the tests expected to succeed.
runsuccess "m" "21"      "0"
runsuccess "m" "3500000" "0"
runsuccess "m" "0"       "0"
runsuccess "r" "21"      "0"
runsuccess "r" "3500000" "0"
runsuccess "s" "21"      "0"
runsuccess "s" "3500000" "0"
runsuccess "n" "21"      "0"
runsuccess "n" "3500000" "0"
runsuccess "c" "24"      "0"
runsuccess "c" "3500000" "0"
runsuccess "a" "24"      "0"
runsuccess "a" "3500000" "0"
runsuccess "v" "24"      "0"
runsuccess "v" "3500000" "0"

# Now limit our memory to 3.5MB and then try the large ones again, all of
# which should fail.
#
# The exact memory limits used here are essentially black magic.  They need to
# be large enough to allow the program to be loaded and do small allocations,
# but not so large that we can't reasonably expect to allocate that much
# memory normally.  3.5MB seems to work reasonably well on both Solaris and
# Linux.
#
# We assume that there are enough miscellaneous allocations that an allocation
# exactly as large as the limit will always fail.
runfailure "m" "3500000" "3500000" \
    "failed to malloc 3500000 bytes at xmalloc.c line 61"
runfailure "r" "3500000" "3500000" \
    "failed to realloc 3500000 bytes at xmalloc.c line 89"
runfailure "s" "3500000" "3500000" \
    "failed to strdup 3500000 bytes at xmalloc.c line 120"
runfailure "n" "3500000" "3500000" \
    "failed to strndup 3500000 bytes at xmalloc.c line 147"
runfailure "c" "3500000" "3500000" \
    "failed to calloc 3500000 bytes at xmalloc.c line 171"
runfailure "a" "3500000" "3500000" \
    "failed to asprintf 3500000 bytes at xmalloc.c line 196"
runfailure "v" "3500000" "3500000" \
    "failed to vasprintf 3500000 bytes at xmalloc.c line 216"

# Check our custom error handler.
runfailure "M" "3500000" "3500000" "malloc 3500000 xmalloc.c 61"
runfailure "R" "3500000" "3500000" "realloc 3500000 xmalloc.c 89"
runfailure "S" "3500000" "3500000" "strdup 3500000 xmalloc.c 120"
runfailure "N" "3500000" "3500000" "strndup 3500000 xmalloc.c 147"
runfailure "C" "3500000" "3500000" "calloc 3500000 xmalloc.c 171"
runfailure "A" "3500000" "3500000" "asprintf 3500000 xmalloc.c 196"
runfailure "V" "3500000" "3500000" "vasprintf 3500000 xmalloc.c 216"

# Check the smaller ones again just for grins.
runsuccess "m" "21" "3500000"
runsuccess "r" "32" "3500000"
runsuccess "s" "64" "3500000"
runsuccess "n" "20" "3500000"
runsuccess "c" "24" "3500000"
runsuccess "a" "30" "3500000"
runsuccess "v" "35" "3500000"
