summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/Makefile6
-rw-r--r--test/README-testframe.txt39
-rw-r--r--test/functests/common.inc52
-rw-r--r--test/functests/dont_test_false.sh7
-rw-r--r--test/functests/test_null.sh13
-rw-r--r--test/functests/test_true.sh8
-rwxr-xr-xtest/functests/test_walkone.sh55
-rw-r--r--test/testframe.inc55
-rwxr-xr-xtest/testframe.sh99
9 files changed, 333 insertions, 1 deletions
diff --git a/test/Makefile b/test/Makefile
index 10877c1..e92e85f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -14,10 +14,14 @@ all: timetest test
timetest: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
-test: timetest
+test: timetest functest
@echo
@./test.sh
+# run functional tests
+functest:
+ ./testframe.sh functests
+
clean:
@rm -f ${OBJ} timetest
diff --git a/test/README-testframe.txt b/test/README-testframe.txt
new file mode 100644
index 0000000..f049040
--- /dev/null
+++ b/test/README-testframe.txt
@@ -0,0 +1,39 @@
+# here's how the testframe script works.
+#
+# Usage for testing:
+# usage: testframe.sh DIR
+# testframe.sh runs each testsuite script found within DIR.
+# (in the context of libfaketime, the DIR is functest.)
+# exits with status 0 if all tests succeed.
+#
+# Interface:
+# by convention, each testsuite script (within DIR) must be
+# a bash script named test_*.sh. the script must define a
+# function named "run". run takes no arguments. run is
+# expected to call the framework-provided function
+# run_testcase once for each test function. run_testcase
+# uses the global vars NFAIL and NSUCC to keep track of how
+# many testcases failed/succeeded.
+#
+# the test function is expected to call something like
+# asserteq or assertneq (again, framework-provided).
+#
+# fine print: for each testsuite, the framework creates a
+# subshell and dots in the script. also dotted in are
+# testframe.inc and DIR/common.inc (if it exists). the
+# testsuite script can make use of any functions defined
+# in these inc files. the environment variable
+# TESTSUITE_NAME is set to the filename of the testsuite
+# script, for possible use in warning or info messages.
+#
+# see functests/test_true.sh for a simple example of
+# a test suite script.
+#
+# Simple steps to add a new testsuite:
+# 1. decide its name - eg, XXX.
+# 2. choose a DIR of similar testsuites to put it in, or create a new one.
+# 3. create DIR/test_XXX.sh.
+# 4. write a run function and testcase functions in DIR/test_XXX.sh.
+# 5. within the run function, call run_testcase for each testcase function.
+# 6. within each testcase funtion, call assertneq or asserteq, or do
+# the equivalent.
diff --git a/test/functests/common.inc b/test/functests/common.inc
new file mode 100644
index 0000000..a011982
--- /dev/null
+++ b/test/functests/common.inc
@@ -0,0 +1,52 @@
+# libfaketime-specific common support routines for tests
+
+# say which *_fakecmd wrapper to use
+platform()
+{
+ # may want to expand the pattern for linuxlike
+ typeset out=$(uname)
+ case "$out" in
+ *OSX*) echo "mac" ;;
+ *Linux*) echo "linuxlike" ;;
+ *) echo 1>&2 unsupported platform, uname=\"$out\" ;;
+ esac
+}
+
+# run faked command on a mac
+# UNTESTED
+mac_fakecmd()
+{
+ typeset timestring="$1"; shift
+ typeset fakelib=../src/libfaketime.so.1
+ export DYLD_INSERT_LIBRARIES=$fakelib
+ export DYLD_FORCE_FLAT_NAMESPACE=1
+ FAKETIME="$timestring" \
+ "$@"
+}
+
+# run faked command on linuxlike OS
+linuxlike_fakecmd()
+{
+ typeset timestring="$1"; shift
+ typeset fakelib=../src/libfaketime.so.1
+ export LD_PRELOAD=$fakelib
+ FAKETIME="$timestring" \
+ "$@"
+}
+
+# run a command with libfaketime using the given timestring
+fakecmd()
+{
+ ${PLATFORM}_fakecmd "$@"
+}
+
+# generate a sequence of numbers from a to b
+range()
+{
+ typeset a=$1 b=$2
+ typeset i=$a
+ while ((i <= b)); do
+ echo $i
+ ((i = i+1))
+ done
+}
diff --git a/test/functests/dont_test_false.sh b/test/functests/dont_test_false.sh
new file mode 100644
index 0000000..b05f06c
--- /dev/null
+++ b/test/functests/dont_test_false.sh
@@ -0,0 +1,7 @@
+# a testsuite that will force failure - for testing purposes
+
+run()
+{
+ run_testcase false
+}
+
diff --git a/test/functests/test_null.sh b/test/functests/test_null.sh
new file mode 100644
index 0000000..09e7560
--- /dev/null
+++ b/test/functests/test_null.sh
@@ -0,0 +1,13 @@
+# check that the date doesn't happen to be 0.
+
+run()
+{
+ run_testcase nulltest
+}
+
+nulltest()
+{
+ typeset tdate=${I2DATES[0]}
+
+ assertneq 0 "$(date +%s)" "($tdate)"
+}
diff --git a/test/functests/test_true.sh b/test/functests/test_true.sh
new file mode 100644
index 0000000..5953f5c
--- /dev/null
+++ b/test/functests/test_true.sh
@@ -0,0 +1,8 @@
+# test suite that always succeds - for testing framework
+
+run()
+{
+ run_testcase true
+ return 0
+}
+
diff --git a/test/functests/test_walkone.sh b/test/functests/test_walkone.sh
new file mode 100755
index 0000000..1902926
--- /dev/null
+++ b/test/functests/test_walkone.sh
@@ -0,0 +1,55 @@
+# walking-1 test.
+# sourced in from testframe.sh.
+#
+# this script defines a suite of functional tests
+# that verifies the correct operation of libfaketime
+# with the date command.
+
+run()
+{
+ init
+
+ for i in $(range 0 30); do
+ run_testcase test_with_i $i
+ done
+}
+
+# ----- support routines
+init()
+{
+ typeset testsuite="$1"
+ PLATFORM=$(platform)
+ if [ -z "$PLATFORM" ]; then
+ echo "$testsuite: unknown platform! quitting"
+ return 1
+ fi
+ echo "# PLATFORM=$PLATFORM"
+ return 0
+}
+
+
+# run date cmd under faketime, print time in secs
+fakedate()
+{
+ #
+ # let the time format be raw seconds since Epoch
+ # for both input to libfaketime, and output of the date cmd.
+ #
+ typeset fmt='%s'
+ export FAKETIME_FMT=$fmt
+ fakecmd "$1" date +$fmt
+}
+
+pow()
+{
+ dc -e "$1 $2 ^ p"
+}
+
+# run a fakedate test with a given time t
+test_with_i()
+{
+ typeset i="$1"
+ typeset t=$(pow 2 $i)
+
+ asserteq $(fakedate $t) $t "(secs since Epoch)"
+}
diff --git a/test/testframe.inc b/test/testframe.inc
new file mode 100644
index 0000000..b5f66a3
--- /dev/null
+++ b/test/testframe.inc
@@ -0,0 +1,55 @@
+# framework common functions for use in test suites and test cases
+
+#
+# run a test and keep stats on success/failure.
+# arguments: a command, possibly a shell function.
+# return value: 0 on success, 1 on failure.
+# side effects: increments global var NSUCC on success, NFAIL on failure.
+#
+run_testcase()
+{
+ if "$@"; then
+ ((NSUCC++))
+ return 0
+ else
+ ((NFAIL++))
+ return 1
+ fi
+}
+
+#
+# verbosely check that the test output matches the expected value.
+# arguments: the test output, the expected value, and a description.
+# return value: 0 on if test output equals expected value; 1 otherwise.
+# side effects: prints a descriptive message.
+#
+asserteq()
+{
+ typeset out="$1" expected="$2" desc="$3"
+ echo -n "out=$out $desc"
+ if [ "$out" = "$expected" ]; then
+ echo " - ok"
+ return 0
+ else
+ echo " expected=$expected - bad"
+ return 1
+ fi
+}
+
+#
+# verbosely check that the test output doesn't match the reference value.
+# return value: 1 on if test output equals expected value; 0 if not equal.
+# side effects: prints descriptive message.
+#
+assertneq()
+{
+ typeset out="$1" ref="$2" desc="$3"
+ echo -n "out=$out $desc"
+ if [ "$out" = "$ref" ]; then
+ echo " ref=$ref - bad"
+ return 1
+ else
+ echo " ref=$ref - ok"
+ return 0
+ fi
+}
diff --git a/test/testframe.sh b/test/testframe.sh
new file mode 100755
index 0000000..22975b6
--- /dev/null
+++ b/test/testframe.sh
@@ -0,0 +1,99 @@
+#! /bin/bash
+# testframe.sh DIR
+# bare-bones testing framework.
+# run the test suites in the given DIR;
+# exit with nonzero status if any of them failed.
+# see README.testframe.txt for details.
+#
+
+# echo labelled error/warning message to stderr
+report()
+{
+ echo $PROG: $* 1>&2
+}
+
+# echo OK or BAD depending on argument (0 or not)
+status_word()
+{
+ if [ "$1" -eq 0 ]; then
+ echo OK
+ else
+ echo BAD
+ fi
+}
+
+# run the given testsuite, return nonzero if any testcase failed.
+run_testsuite()
+{
+ typeset testsuite="$1"
+
+ NFAIL=0
+ NSUCC=0
+
+ # add testsuite dir to PATH for convenience
+ typeset dir=$(dirname $testsuite)
+ PATH=$dir:$PATH
+ . testframe.inc
+ if [ -f $dir/common.inc ]; then
+ . $dir/common.inc
+ fi
+ . $testsuite
+ export TESTSUITE_NAME=$testsuite
+
+ echo ""
+ echo "# Begin $testsuite"
+
+ run
+ typeset runstat=$?
+
+ echo "# $testsuite summary: $NSUCC succeeded, $NFAIL failed"
+ if [ $runstat -ne 0 ]; then
+ ((NFAIL++))
+ report "error: $testsuite run exit_status=$runstat!"
+ fi
+ echo "# End $testsuite -" $(status_word $NFAIL)
+ [ $NFAIL -eq 0 ]
+}
+
+#
+# list all testsuite scripts in the given directories.
+# a testsuite file must be a bash script whose name is of the form test_*.sh .
+#
+list_testsuites()
+{
+ for dir in "$@"; do
+ ls $dir/test_*.sh 2>/dev/null
+ done
+}
+
+main()
+{
+ TS_NFAIL=0
+ TS_NSUCC=0
+
+ echo "# Begin Test Suites in $*"
+ typeset testsuites=$(list_testsuites "$@")
+
+ if [ -z "$testsuites" ]; then
+ report "error: no testsuites found"
+ exit 1
+ fi
+
+ for testsuite in $testsuites; do
+ if run_testsuite $testsuite; then
+ ((TS_NSUCC++))
+ else
+ ((TS_NFAIL++))
+ fi
+ done
+
+ echo ""
+ echo "# Test Suites summary: $TS_NSUCC succeeded, $TS_NFAIL failed"
+ echo "# End Test Suites -" $(status_word $TS_NFAIL)
+ [ $TS_NFAIL -eq 0 ]
+}
+
+# ----- start of mainline code
+PROG=${0##*/}
+
+main "${@:-.}"