161 lines
6.0 KiB
Bash
Executable File
161 lines
6.0 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# Parameters: testSubject sourcePath [testScript...]
|
|
#
|
|
# Run one or more test scripts. The ${testSubject} is the path of the test
|
|
# subject program, and the ${sourcePath} is the path to the top level of the
|
|
# source directory. If any ${testScript} parameters are given, they are the
|
|
# tests to run (each one being either the full path to a script, or the base
|
|
# filename of the script in the test directory). If no test scripts are
|
|
# listed, then all tests directly under "${sourcePath}/tests/" are run.
|
|
#
|
|
# Test scripts should be written to exit 0 if the test passed, 2 if the test
|
|
# is to be skipped, or any other exit status to indicate failure. They are
|
|
# run via "sh -e", so any command exiting non-zero will cause the test
|
|
# script to exit early.
|
|
#
|
|
# The test scripts can rely on the environment variables "testSubject",
|
|
# "sourcePath", "workFile1", "workFile2", "workFile3", and "workFile4" being
|
|
# populated, and should use those work files - which will be present and
|
|
# empty - for scratch space. They should not delete those files.
|
|
#
|
|
# When the test scripts are called, LANG and LC_ALL are set to "C".
|
|
#
|
|
# Anything output by a test script on stdout or stderr is captured and shown
|
|
# after the "OK" / "FAILED" / "skipped" result description.
|
|
#
|
|
# The exit status of this script will be 1 if any test failed, 0 otherwise.
|
|
# A skipped test is not counted as a failure.
|
|
#
|
|
|
|
testSubject="$1"
|
|
sourcePath="$2"
|
|
shift
|
|
shift
|
|
selectedTests="$*"
|
|
|
|
# Temporary working files, for the test scripts to use.
|
|
workFile1=$(mktemp 2>/dev/null) || workFile1="./.tmp1"
|
|
workFile2=$(mktemp 2>/dev/null) || workFile2="./.tmp2"
|
|
workFile3=$(mktemp 2>/dev/null) || workFile3="./.tmp3"
|
|
workFile4=$(mktemp 2>/dev/null) || workFile4="./.tmp4"
|
|
|
|
# Clean up the temporary files on exit, in case we are interrupted.
|
|
trap 'rm -f "${workFile1}" "${workFile2}" "${workFile3}" "${workFile4}"' EXIT
|
|
|
|
# Variables used by the test scripts.
|
|
export testSubject sourcePath workFile1 workFile2 workFile3 workFile4
|
|
|
|
# Set everything to the "C" locale.
|
|
LANG=C
|
|
LC_ALL=C
|
|
export LANG LC_ALL
|
|
|
|
# If no tests were specified, list all test scripts under the source path.
|
|
test -n "${selectedTests}" || selectedTests=$(find "${sourcePath}/tests" -maxdepth 1 -type f | sort -n)
|
|
|
|
# Initial pass to count the number of tests and find the length of the
|
|
# longest test name, to use when formatting the output.
|
|
#
|
|
numberOfTests=0
|
|
maxTestNameLength=0
|
|
for testScript in ${selectedTests}; do
|
|
# Find the test script, make sure it exists.
|
|
test -f "${testScript}" || testScript="${sourcePath}/tests/${testScript}"
|
|
test -f "${testScript}" || testScript=$(find "${sourcePath}/tests" -maxdepth 1 -type f -name "${testScript##*/}*" | sed -n '1p')
|
|
test -f "${testScript}" || continue
|
|
|
|
numberOfTests=$((1+numberOfTests))
|
|
|
|
testScriptLeaf="${testScript##*/}"
|
|
testName="$(echo "${testScriptLeaf%.sh}" | tr '_' ' ' | sed 's/ - /: /')"
|
|
testNameLength=${#testName}
|
|
test "${testNameLength}" -gt "${maxTestNameLength}" && maxTestNameLength="${testNameLength}"
|
|
done
|
|
|
|
# Set a minimum and maximum test name length.
|
|
test "${maxTestNameLength}" -lt 10 && maxTestNameLength=10
|
|
test "${maxTestNameLength}" -gt 60 && maxTestNameLength=60
|
|
|
|
# Count the number of digits in the number of tests so we know how wide the
|
|
# column for the test count should be.
|
|
testCountWidth=${#numberOfTests}
|
|
|
|
# The exit status - 0 means all tests that were run have passed, 1 means
|
|
# that at least one test failed.
|
|
overallExitStatus=0
|
|
|
|
# Run all of the selected test scripts, formatting the output.
|
|
#
|
|
testNumber=0
|
|
for testScript in ${selectedTests}; do
|
|
# Find the test script, make sure it exists.
|
|
test -f "${testScript}" || testScript="${sourcePath}/tests/${testScript}"
|
|
test -f "${testScript}" || testScript=$(find "${sourcePath}/tests" -maxdepth 1 -type f -name "${testScript##*/}*" | sed -n '1p')
|
|
test -f "${testScript}" || continue
|
|
|
|
testNumber=$((1+testNumber))
|
|
|
|
testScriptLeaf="${testScript##*/}"
|
|
testName="$(echo "${testScriptLeaf%.sh}" | tr '_' ' ' | sed 's/ - /: /')"
|
|
printf "%${testCountWidth}d/%d: %-${maxTestNameLength}.${maxTestNameLength}s " "${testNumber}" "${numberOfTests}" "${testName}"
|
|
|
|
# Run the test script, capturing the output and the exit status.
|
|
testExitStatus=0
|
|
testOutput=""
|
|
if test -s "${testScript}"; then
|
|
true > "${workFile1}"
|
|
true > "${workFile2}"
|
|
true > "${workFile3}"
|
|
true > "${workFile4}"
|
|
testOutput=$(sh -e "${testScript}" 2>&1)
|
|
testExitStatus=$?
|
|
else
|
|
testOutput="test script has not yet been written"
|
|
testExitStatus=2
|
|
fi
|
|
|
|
# Work out what we're going to say about this test result.
|
|
testResultDescription=""
|
|
resultFormatCodes=""
|
|
if test ${testExitStatus} -eq 0; then
|
|
resultFormatCodes="setaf 2;bold"
|
|
testResultDescription="OK"
|
|
elif test ${testExitStatus} -eq 2; then
|
|
resultFormatCodes="setaf 3"
|
|
testResultDescription="skipped"
|
|
else
|
|
resultFormatCodes="setaf 1;bold"
|
|
testResultDescription="FAILED"
|
|
overallExitStatus=1
|
|
fi
|
|
|
|
# If stdout is not a terminal, don't use terminal format codes.
|
|
test -t 1 || resultFormatCodes=""
|
|
|
|
# Show the description of the test result, and start a new line.
|
|
test -n "${resultFormatCodes}" && command -v tput >/dev/null 2>&1 && echo "${resultFormatCodes}" | tr ';' '\n' | tput -S 2>/dev/null
|
|
printf "%s" "${testResultDescription}"
|
|
test -n "${resultFormatCodes}" && command -v tput >/dev/null 2>&1 && tput sgr0 2>/dev/null
|
|
printf "\n"
|
|
|
|
# If there was any output from the test, display it on the new line,
|
|
# with the same terminal format codes as the result description, and
|
|
# each line prefixed with the test number.
|
|
if test -n "${testOutput}"; then
|
|
test -n "${resultFormatCodes}" && command -v tput >/dev/null 2>&1 && echo "${resultFormatCodes}" | tr ';' '\n' | tput -S 2>/dev/null
|
|
printf "%s" "$(echo "${testOutput}" | sed "s,^,$(printf "%${testCountWidth}d/%d: - " "${testNumber}" "${numberOfTests}"),")"
|
|
test -n "${resultFormatCodes}" && command -v tput >/dev/null 2>&1 && tput sgr0 2>/dev/null
|
|
printf "\n"
|
|
fi
|
|
done
|
|
|
|
# Clean up.
|
|
rm -f "${workFile1}" "${workFile2}" "${workFile3}" "${workFile4}"
|
|
trap '' EXIT
|
|
|
|
# Exit with status 1 if any test failed outright, 0 otherwise.
|
|
exit ${overallExitStatus}
|
|
|
|
# EOF
|