Add ATF tests for realpath(1)

Note that realpath can act differently for root than for other users
(where an ordinary user will see EACCESS root just barrels right through).

The tests adapt themselves, when run as root, less error cases can be
tested than when run as some other user.
This commit is contained in:
kre 2022-07-21 09:52:48 +00:00
parent d0aa7735ce
commit fa7d65a3b6
5 changed files with 688 additions and 4 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1216 2022/07/05 22:50:41 rillig Exp $
# $NetBSD: mi,v 1.1217 2022/07/21 09:52:48 kre Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -6254,6 +6254,10 @@
./usr/tests/usr.bin/pwhash/Atffile tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/pwhash/Kyuafile tests-usr.bin-tests compattestfile,atf,kyua
./usr/tests/usr.bin/pwhash/t_pwhash tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/realpath tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/realpath/Atffile tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/realpath/Kyuafile tests-usr.bin-tests compattestfile,atf,kyua
./usr/tests/usr.bin/realpath/t_realpath tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/rump_server tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/rump_server/Atffile tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/rump_server/Kyuafile tests-usr.bin-tests compattestfile,atf,kyua

View File

@ -1,4 +1,4 @@
# $NetBSD: NetBSD.dist.tests,v 1.192 2022/05/22 17:55:08 rillig Exp $
# $NetBSD: NetBSD.dist.tests,v 1.193 2022/07/21 09:52:48 kre Exp $
./usr/libdata/debug/usr/tests
./usr/libdata/debug/usr/tests/atf
@ -456,6 +456,7 @@
./usr/tests/usr.bin/pr
./usr/tests/usr.bin/printf
./usr/tests/usr.bin/pwhash
./usr/tests/usr.bin/realpath
./usr/tests/usr.bin/rump_server
./usr/tests/usr.bin/sdiff
./usr/tests/usr.bin/sed

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.36 2022/05/22 17:55:08 rillig Exp $
# $NetBSD: Makefile,v 1.37 2022/07/21 09:52:48 kre Exp $
#
.include <bsd.own.mk>
@ -8,7 +8,7 @@ TESTSDIR= ${TESTSBASE}/usr.bin
TESTS_SUBDIRS= awk basename bzip2 cc cmp compress config cpio col cut \
diff dirname find fstat gdb grep gzip id indent \
infocmp jot ld locale m4 make mixerctl mkdep nbperf \
netpgpverify patch pkill pr printf pwhash rump_server \
netpgpverify patch pkill pr printf pwhash realpath rump_server \
shmif_dumpbus sdiff sed sort tar tmux tr unifdef uniq \
vmstat xlint ztest

View File

@ -0,0 +1,9 @@
# $NetBSD: Makefile,v 1.1 2022/07/21 09:52:49 kre Exp $
.include <bsd.own.mk>
TESTSDIR= ${TESTSBASE}/usr.bin/realpath
TESTS_SH= t_realpath
.include <bsd.test.mk>

View File

@ -0,0 +1,670 @@
# $NetBSD: t_realpath.sh,v 1.1 2022/07/21 09:52:49 kre Exp $
#
# Copyright (c) 2022 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# ===========================================================
#
# Test data and expected results
# Note that the empty line calls realpath with no file arg
existing='.
../Dir/StdOut
./S1
./S1/../S4
./Snr/../S4
S1/S2/File
S1/S3/Link
Snr/HoHo
Snr/Link
L
/
/bin
Self
Self/
S4/S1/'
exist_results='Dir
Dir
Dir/StdOut
Dir/S1
Dir/S4
Dir/S4
Dir/S1/S2/File
Dir/S1/S2/File
Dir/Snr/HoHo
Dir/S1
Dir/StdOut
/
/bin
Dir
Dir
Dir/S1'
exist_root_only='Snx/HaHa
Snx/Link'
exist_root_results='Dir/Snx/HaHa
Dir/S1/S2/File'
nofile='-
trash
Snr/Haha
T1
T2
T3
T4
T5
../Dir/T2
../Dir/T3
/nonsense
/bin/../nonsense
./Self/Self/Self/Self/S1/../Self/../Dir/Self/T1
Self/nonsense'
nofile_results='Dir/-
Dir/trash
Dir/Snr/Haha
Dir/NoSuchFile
Dir/S1/NoSuchFile
Dir/S1/NoSuchFile
Dir/S1/S2/NoSuchFile
Dir/S1/S2/NoSuchFile
Dir/S1/NoSuchFile
Dir/S1/NoSuchFile
/nonsense
/nonsense
Dir/NoSuchFile
Dir/nonsense'
always_fail='StdOut/
StdOut/../StdErr
Loop
S1/S5/Link
Loop/../StdOut
BigLoop
U1
U2
U3
U4
U5
U6
U7
U8
U9
T1/NoSuchFile
T1/../NoSuchFile
U9/../NoSuchFile
U9/../StdOut'
# ===========================================================
# Helper functions
#
# Create the test environment
setup()
{
atf_require_prog /usr/bin/mktemp
atf_require_prog /bin/ln
atf_require_prog /bin/cp
atf_require_prog /bin/mkdir
atf_require_prog /bin/chmod
DIR=${PWD}/$(mktemp -d Dir.XXXXX) ||
atf_fail "Did not make test directory"
cd "${DIR}" || atf_fail "Unable to cd $DIR"
ID=$( set -- $( type id ) && test "$1" = id && test "$2" = is &&
test $# -eq 3 && printf %s "$3" || printf no-id-program)
mkdir Dir && cd Dir || atf_fail "enter Dir"
>StdOut || atf_fail "setup StdOut"
>StdErr || atf_fail "setup StdErr"
ln -s ../Dir Dir || atf_fail "setup Dir"
ln -s Loop Loop || atf_fail "setup Loop"
ln -s . Self || atf_fail "setup Self"
mkdir S1 S1/S2 S1/S3 S4 S4/S5 || atf_fail "setup subdirs"
echo S1/S2/File > S1/S2/File || atf_fail "setup File"
ln -s ../S2/File S1/S3/Link || atf_fail "setup S3/Link"
ln -s ../S1 S4/S1 || atf_fail "setup S4/S1"
ln -s StdOut L1 || atf_fail "setup L1"
ln -s L1 L2 || atf_fail "setup L2"
ln -s ../L2 S1/L3 || atf_fail "setup L3"
ln -s ../L3 S1/S2/L4 || atf_fail "setup L4"
ln -s ../S2/L4 S1/S3/L5 || atf_fail "setup L5"
ln -s S1/S3/L5 L || atf_fail "setup L"
ln -s ${PWD}/S1 S4/PWDS1 || atf_fail "setup PWDS1"
ln -s ${PWD}/S9 S4/PWDS9 || atf_fail "setup PWDS9"
ln -s ${PWD}/S9/File S4/PWDS9F || atf_fail "setup PWDS9F"
ln -s ../S4/BigLoop S1/BigLoop || atf_fail "setup S1/BigLoop"
ln -s ../BigLoop S4/BigLoop || atf_fail "setup S4/BigLoop"
ln -s "${DIR}"/Dir/S1/BigLoop BigLoop || atf_fail "setup BigLoop"
mkdir Snx || atf_fail "setup Snx"
cp /dev/null Snx/HaHa || atf_fail "setup Snx/HaHa"
ln -s "${DIR}"/Dir/S1/S2/File Snx/Link || atf_fail "setup Snx/Link"
mkdir Snr || atf_fail "setup Snr"
cp /dev/null Snr/HoHo || atf_fail "setup Snr/HoHo"
ln -s "${DIR}"/Dir/S4/PWDS1 Snr/Link || atf_fail "setup Snr/Link"
ln -s ../Snx/HaHa Snr/HaHa || atf_fail "setup HaHa"
ln -s "${DIR}"/Dir/NoSuchFile T1 || atf_fail "setup T1"
ln -s "${DIR}"/Dir/S1/NoSuchFile T2 || atf_fail "setup T2"
ln -s S1/NoSuchFile T3 || atf_fail "setup T3"
ln -s "${DIR}"/Dir/S1/S2/NoSuchFile T4 || atf_fail "setup T4"
ln -s S1/S2/NoSuchFile T5 || atf_fail "setup T5"
ln -s "${DIR}"/Dir/StdOut/CannotExist T6 || atf_fail "setup T6"
ln -s "${DIR}"/Dir/NoDir/WhoKnows U1 || atf_fail "setup U1"
ln -s "${DIR}"/Dir/S1/NoDir/WhoKnows U2 || atf_fail "setup U2"
ln -s "${DIR}"/Dir/S1/S2/NoDir/WhoKnows U3 || atf_fail "setup U3"
ln -s "${DIR}"/Dir/S1/../NoDir/WhoKnows U4 || atf_fail "setup U4"
ln -s "${DIR}"/Dir/NoDir/../StdOut U5 || atf_fail "setup U5"
ln -s NoDir/../StdOut U6 || atf_fail "setup U6"
ln -s S1/NoDir/../../StdOut U7 || atf_fail "setup U7"
ln -s "${DIR}"/Dir/Missing/NoDir/WhoKnows U8 || atf_fail "setup U8"
ln -s "${DIR}"/Dir/Missing/NoDir/../../StdOut U9 || atf_fail "setup U9"
chmod a+r,a-x Snx || atf_fail "setup a-x "
chmod a+x,a-r Snr || atf_fail "setup a-r"
}
# ATF will remove all the files we made, just ensure perms are OK
cleanup()
{
chmod -R u+rwx .
return 0
}
run_tests_pass()
{
opt=$1
tests=$2
results=$3
FAILS=
FAILURES=0
T=0
while [ "${#tests}" -gt 0 ]
do
FILE=${tests%%$'\n'*}
EXP=${results%%$'\n'*}
tests=${tests#"${FILE}"}; tests=${tests#$'\n'}
results=${results#"${EXP}"}; results=${results#$'\n'}
test -z "${EXP}" && atf_fail "Too few results (test botch)"
T=$(( $T + 1 ))
GOT=$(realpath $opt -- ${FILE:+"${FILE}"})
STATUS=$?
case "${GOT}" in
'') ;; # nothing printed, deal with that below
/*) # Full Path (what we want)
# Remove the unpredictable ATF dir prefix (if present)
GOT=${GOT#"${DIR}/"}
# Now it might be a relative path, that's OK
# at least it can be compared (its prefix is known)
;;
*) # a relative path was printed
FAILURES=$(($FAILURES + 1))
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} '${FILE}'"
FAILS="${FAILS}: output relative path '${GOT}'"
FAILS="${FAILS}, and exit($STATUS)"
continue
;;
esac
if [ $STATUS -ne 0 ] || [ "${EXP}" != "${GOT}" ]
then
FAILURES=$(($FAILURES + 1))
if [ $STATUS -ne 0 ]
then
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} '${FILE}'"
FAILS="${FAILS} failed: status ${STATUS}"
else
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} '${FILE}'"
FAILS="${FAILS} expected '${EXP}' received '${GOT}'"
fi
fi
done
if test -n "${results}"
then
FAILURES=$(( $FAILURES + 1 ))
N=$(( $(printf '%s\n' "${results}" | wc -l) ))
s=s; if [ $N -eq 1 ]; then s=; fi
FAILS=${FAILS:+"${FAILS}"$'\n'}"After $T tests"
FAILS="still $N more result$s (test botch)"
fi
if [ $FAILURES -gt 0 ]
then
s=s
if [ $FAILURES -eq 1 ]; then s=; fi
printf >&2 '%d path%s resolved incorrectly:\n%s\n' \
"$FAILURES" "$s" "${FAILS}"
atf_fail "$FAILURES path$s resolved incorrectly; see stderr"
fi
return 0
}
run_tests_fail()
{
opt=$1
tests=$2
FAILS=
FAILURES=0
T=0
while [ "${#tests}" -gt 0 ]
do
FILE=${tests%%$'\n'*}
tests=${tests#"${FILE}"}; tests=${tests#$'\n'}
test -z "${FILE}" && continue
T=$(( $T + 1 ))
GOT=$(realpath $opt -- "${FILE}" 2>StdErr)
STATUS=$?
ERR=$(cat StdErr)
if [ $STATUS -eq 0 ] || [ "${GOT}" ] || ! [ "${ERR}" ]
then
FAILURES=$(($FAILURES + 1))
if [ "${STATUS}" -eq 0 ]
then
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T: "
FAILS="${FAILS}${opt:+ $opt} '${FILE}' worked;"
FAILS="${FAILS} received: '${GOT}'}"
if [ "${ERR}" ]; then
FAILS="${FAILS} and on stderr '${ERR}'"
fi
elif [ "${GOT}" ]
then
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} '${FILE}' failed,"
FAILS="${FAILS} but with '${GOT}' on stdout"
if [ "${ERR}" ]; then
FAILS="${FAILS}, and on stderr '${ERR}'"
else
FAILS="${FAILS}, and empty stderr"
fi
else
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} '${FILE}' failed,"
FAILS="${FAILS} but with no error message"
fi
fi
done
if [ $FAILURES -gt 0 ]
then
S=s
if [ $FAILURES -eq 1 ]; then s=; fi
printf >&2 '%d path%s resolved incorrectly:\n%s\n' \
"$FAILURES" "$s" "${FAILS}"
atf_fail "$FAILURES path$s resolved incorrectly; see stderr"
fi
return 0
}
# ===================================================================
# Test cases setup follows (but almost all the work is earlier)
atf_test_case a__e_ok cleanup
realpath_e_ok_head()
{
atf_set descr "Test realpath (with -e) cases which should work"
}
a__e_ok_body()
{
setup
run_tests_pass -e "${existing}" "${exist_results}"
if [ -x "${ID}" ] && [ "$("$ID" -u)" = 0 ]
then
run_tests_pass -e "${exist_root_only}" "${exist_root_results}"
fi
}
a__e_ok_cleanup()
{
cleanup
}
atf_test_case b__E_ok cleanup
b__E_ok_head()
{
atf_set descr "Test realpath (with -E) cases which should work"
}
b__E_ok_body() {
setup
# everything which works with -e should also work with -E
run_tests_pass -E "${existing}" "${exist_results}"
run_tests_pass -E "${nofile}" "${nofile_results}"
if [ -x "${ID}" ] && [ "$("${ID}" -u)" = 0 ]
then
run_tests_pass -E "${exist_root_only}" "${exist_root_results}"
fi
}
b__E_ok_cleanup()
{
cleanup
}
atf_test_case c__ok cleanup
c__ok_head()
{
atf_set descr "Test realpath (without -e or -E) cases which should work"
}
c__ok_body() {
setup
# Our default for realpath is -E, so the -E tests should work
run_tests_pass '' "${existing}" "${exist_results}"
# but more should work as well
run_tests_pass '' "${nofile}" "${nofile_results}"
if [ -x "${ID}" ] && [ "$("${ID}" -u)" = 0 ]
then
run_tests_pass '' "${exist_root_only}" "${exist_root_results}"
fi
}
c__ok_cleanup()
{
cleanup
}
atf_test_case d__E_fail
d__E_fail_head()
{
atf_set descr "Test realpath -e cases which should not work"
}
d__E_fail_body()
{
setup
run_tests_fail -E "${always_fail}"
if [ -x "${ID}" ] && [ "$("${ID}" -u)" != 0 ]
then
run_tests_fail -E "${exist_root_only}"
fi
}
d__E_fail_cleanup()
{
cleanup
}
atf_test_case e__e_fail
e__e_fail_head()
{
atf_set descr "Test realpath -e cases which should not work"
}
e__e_fail_body()
{
setup
# Some -E tests that work should fail with -e
run_tests_fail -e "${nofile}"
run_tests_fail -e "${always_fail}"
if [ -x "${ID}" ] && [ "$("${ID}" -u)" != 0 ]
then
run_tests_fail -e "${exist_root_only}"
fi
}
e__e_fail_cleanup()
{
cleanup
}
atf_test_case f__fail
f__fail_head()
{
atf_set descr "Test realpath cases which should not work (w/o -[eE])"
}
f__fail_body()
{
setup
run_tests_fail '' "${always_fail}"
if [ -x "${ID}" ] && [ "$("${ID}" -u)" != 0 ]
then
run_tests_fail '' "${exist_root_only}"
fi
}
f__fail_cleanup()
{
cleanup
}
atf_test_case g__q cleanup
g__q_head()
{
atf_set descr "Test realpath's -q option; also test usage message"
}
g__q_body()
{
setup
# Just run these tests here, the paths have been tested
# already, all we care about is that -q suppresses err messages
# about the ones that fail, so just test those. Since those
# always fail, it is irrlevant which of -e or -E we would use,
# so simply use neither.
# This is adapted from run_tests_fail
FAILURES=0
FAILS=
opt=-q
T=0
for FILE in ${always_fail}
do
test -z "${FILE}" && continue
T=$(( $T + 1 ))
GOT=$(realpath $opt -- "${FILE}" 2>StdErr)
STATUS=$?
ERR=$(cat StdErr)
if [ $STATUS -eq 0 ] || [ "${GOT}" ] || [ "${ERR}" ]
then
FAILURES=$(($FAILURES + 1))
if [ "${STATUS}" -eq 0 ]
then
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T: "
FAILS="${FAILS}${opt:+ $opt} '${FILE}' worked;"
FAILS="${FAILS} received: '${GOT}'}"
if [ "${ERR}" ]; then
FAILS="${FAILS} and on stderr '${ERR}'"
fi
elif [ "${GOT}" ]
then
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} '${FILE}' failed,"
FAILS="${FAILS} but with '${GOT}' on stdout"
if [ "${ERR}" ]; then
FAILS="${FAILS}, and on stderr '${ERR}'"
else
FAILS="${FAILS}, and empty stderr"
fi
else
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} '${FILE}' failed,"
FAILS="${FAILS} stderr: '${ERR}'"
fi
fi
done
# There are a couple of cases where -q does not suppress stderr
for FILE in '' -wObBl@ --
do
T=$(( $T + 1 ))
unset XTRA
case "${FILE}" in
'') ;;
--) XTRA=;;
-*) XTRA=/junk;;
esac
# Note lack of -- in the following, so $FILE can be either
# a file name (well, kind of...), or options.
GOT=$(realpath $opt "${FILE}" ${XTRA+"${XTRA}"} 2>StdErr)
STATUS=$?
ERR=$(cat StdErr)
if [ $STATUS -eq 0 ] || [ "${GOT}" ] || ! [ "${ERR}" ]
then
FAILURES=$(($FAILURES + 1))
if [ "${STATUS}" -eq 0 ]
then
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T: "
FAILS="${FAILS}${opt:+ $opt} ${FILE:-''}"
FAILS="${FAILS}${XTRA:+ $XTRA} worked;"
FAILS="${FAILS} received: '${GOT}'}"
if [ "${ERR}" ]; then
FAILS="${FAILS} and on stderr '${ERR}'"
fi
elif [ "${GOT}" ]
then
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} ${FILE:-''}"
FAILS="${FAILS}${XTRA:+ ${XTRA}} failed,"
FAILS="${FAILS} but with '${GOT}' on stdout"
if [ "${ERR}" ]; then
FAILS="${FAILS}, and on stderr '${ERR}'"
else
FAILS="${FAILS}, and empty stderr"
fi
else
FAILS=${FAILS:+"${FAILS}"$'\n'}"Path $T:"
FAILS="${FAILS}${opt:+ $opt} ${FILE:-''}"
FAILS="${FAILS}${XTRA:+ ${XTRA}} failed,"
FAILS="${FAILS} with stderr empty"
fi
fi
done
if [ $FAILURES -gt 0 ]
then
s=s
if [ $FAILURES -eq 1 ]; then s=; fi
printf >&2 '%d path%s resolved incorrectly:\n%s\n' \
"$FAILURES" "$s" "${FAILS}"
atf_fail "$FAILURES path$s resolved incorrectly; see stderr"
fi
return 0
}
g__q_cleanup()
{
cleanup
}
atf_test_case h__n_args
h__n_args_head()
{
atf_set descr "Test realpath with multiple file args"
}
h__n_args_body()
{
setup
# Since these paths have already (hopefully) tested and work
# (if a__e_ok had any failures, fix those before even looking
# at any failure here)
# Since we are assuming that the test cases all work, simply
# Count how many there are, and then expect the same number
# of answers
unset IFS
set -- ${existing}
# Note that any empty line (no args) case just vanished...
# That would be meaningless here, removing it is correct.
GOT=$(realpath -e -- "$@" 2>StdErr)
STATUS=$?
ERR=$(cat StdErr; printf X)
ERR=${ERR%X}
NR=$(( $(printf '%s\n' "${GOT}" | wc -l) ))
if [ $NR -ne $# ] || [ $STATUS -ne 0 ] || [ -s StdErr ]
then
printf >&2 'Stderr from test:\n%s\n' "${ERR}"
if [ $STATUS -eq 0 ]; then S="OK"; else S="FAIL($STATUS)"; fi
if [ ${#ERR} -ne 0 ]
then
E="${#ERR} bytes on stderr"
else
E="nothing on stderr"
fi
atf_fail 'Given %d args, got %d results; Status:%s; %s\n' \
"$#" "${NR}" "${S}" "${E}"
fi
return 0
}
h__n_args_cleanup()
{
cleanup
}
atf_init_test_cases()
{
atf_add_test_case a__e_ok
atf_add_test_case b__E_ok
atf_add_test_case c__ok
atf_add_test_case d__E_fail
atf_add_test_case e__e_fail
atf_add_test_case f__fail
atf_add_test_case g__q
atf_add_test_case h__n_args
}