# Shell function library for test cases.
#
# This file provides a TAP-compatible shell function library useful for
# writing test cases. It is part of C TAP Harness, which can be found at
# .
#
# Written by Russ Allbery
# Copyright 2009, 2010 Russ Allbery
# Copyright 2006, 2007, 2008
# The Board of Trustees of the Leland Stanford Junior University
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
# Print out the number of test cases we expect to run.
plan () {
count=1
planned="$1"
failed=0
echo "1..$1"
trap finish 0
}
# Prepare for lazy planning.
plan_lazy () {
count=1
planned=0
failed=0
trap finish 0
}
# Report the test status on exit.
finish () {
local highest looks
highest=`expr "$count" - 1`
if [ "$planned" = 0 ] ; then
echo "1..$highest"
planned="$highest"
fi
looks='# Looks like you'
if [ "$planned" -gt 0 ] ; then
if [ "$planned" -gt "$highest" ] ; then
if [ "$planned" -gt 1 ] ; then
echo "$looks planned $planned tests but only ran $highest"
else
echo "$looks planned $planned test but only ran $highest"
fi
elif [ "$planned" -lt "$highest" ] ; then
local extra
extra=`expr "$highest" - "$planned"`
if [ "$planned" -gt 1 ] ; then
echo "$looks planned $planned tests but ran $extra extra"
else
echo "$looks planned $planned test but ran $extra extra"
fi
elif [ "$failed" -gt 0 ] ; then
if [ "$failed" -gt 1 ] ; then
echo "$looks failed $failed tests of $planned"
else
echo "$looks failed $failed test of $planned"
fi
elif [ "$planned" -gt 1 ] ; then
echo "# All $planned tests successful or skipped"
else
echo "# $planned test successful or skipped"
fi
fi
}
# Skip the entire test suite. Should be run instead of plan.
skip_all () {
local desc
desc="$1"
if [ -n "$desc" ] ; then
echo "1..0 # skip $desc"
else
echo "1..0 # skip"
fi
exit 0
}
# ok takes a test description and a command to run and prints success if that
# command is successful, false otherwise. The count starts at 1 and is
# updated each time ok is printed.
ok () {
local desc
desc="$1"
if [ -n "$desc" ] ; then
desc=" - $desc"
fi
shift
if "$@" ; then
echo ok $count$desc
else
echo not ok $count$desc
failed=`expr $failed + 1`
fi
count=`expr $count + 1`
}
# Skip the next test. Takes the reason why the test is skipped.
skip () {
echo "ok $count # skip $*"
count=`expr $count + 1`
}
# Report the same status on a whole set of tests. Takes the count of tests,
# the description, and then the command to run to determine the status.
ok_block () {
local end i desc
i=$count
end=`expr $count + $1`
shift
desc="$1"
shift
while [ "$i" -lt "$end" ] ; do
ok "$desc" "$@"
i=`expr $i + 1`
done
}
# Skip a whole set of tests. Takes the count and then the reason for skipping
# the test.
skip_block () {
local i end
i=$count
end=`expr $count + $1`
shift
while [ "$i" -lt "$end" ] ; do
skip "$@"
i=`expr $i + 1`
done
}
# Portable variant of printf '%s\n' "$*". In the majority of cases, this
# function is slower than printf, because the latter is often implemented
# as a builtin command. The value of the variable IFS is ignored.
puts () {
cat << EOH
$@
EOH
}
# Run a program expected to succeed, and print ok if it does and produces the
# correct output. Takes the description, expected exit status, the expected
# output, the command to run, and then any arguments for that command.
# Standard output and standard error are combined when analyzing the output of
# the command.
#
# If the command may contain system-specific error messages in its output,
# add strip_colon_error before the command to post-process its output.
ok_program () {
local desc w_status w_output output status
desc="$1"
shift
w_status="$1"
shift
w_output="$1"
shift
output=`"$@" 2>&1`
status=$?
if [ $status = $w_status ] && [ x"$output" = x"$w_output" ] ; then
ok "$desc" true
else
echo "# saw: ($status) $output"
echo "# not: ($w_status) $w_output"
ok "$desc" false
fi
}
# Strip a colon and everything after it off the output of a command, as long
# as that colon comes after at least one whitespace character. (This is done
# to avoid stripping the name of the program from the start of an error
# message.) This is used to remove system-specific error messages (coming
# from strerror, for example).
strip_colon_error() {
local output status
output=`"$@" 2>&1`
status=$?
output=`puts "$output" | sed 's/^\([^ ]* [^:]*\):.*/\1/'`
puts "$output"
return $status
}
# Bail out with an error message.
bail () {
echo 'Bail out!' "$@"
exit 1
}
# Output a diagnostic on standard error, preceded by the required # mark.
diag () {
echo '#' "$@"
}
# Search for the given file first in $BUILD and then in $SOURCE and echo the
# path where the file was found, or the empty string if the file wasn't
# found.
test_file_path () {
if [ -n "$BUILD" ] && [ -f "$BUILD/$1" ] ; then
puts "$BUILD/$1"
elif [ -n "$SOURCE" ] && [ -f "$SOURCE/$1" ] ; then
puts "$SOURCE/$1"
else
echo ''
fi
}