121 lines
4.7 KiB
Bash
121 lines
4.7 KiB
Bash
|
|
#!/bin/bash
|
||
|
|
#
|
||
|
|
# command_option_test.sh — Command-line option parsing (mac/argv.cpp).
|
||
|
|
#
|
||
|
|
# The commands' own argument handling, which no suite covered: argv_test.cpp
|
||
|
|
# exercises Argv but asserts nothing, so two defects lived there unnoticed.
|
||
|
|
#
|
||
|
|
# * An option declared with opt() takes a value. Written LAST with nothing
|
||
|
|
# after it -- "kdesc -v", "ktext doc.kt -t" -- parse_optional() read one
|
||
|
|
# past the end of the word vector and the command died with SIGSEGV,
|
||
|
|
# naming nothing. Two bounds checks sat commented out at that spot; they
|
||
|
|
# would have returned a half-parsed option instead of reporting the
|
||
|
|
# mistake. It is now a located argument error.
|
||
|
|
# * kdesc and kdiag printed an error and then exited 0, so a script could
|
||
|
|
# not tell a failed run from a successful one. Both return 1 now, as
|
||
|
|
# ktext already did.
|
||
|
|
#
|
||
|
|
# Also here: two required positional arguments. parse_positional() consumes
|
||
|
|
# one per required name, but regex_split_prefix() requires its match at
|
||
|
|
# position 0 and returned the remainder with the separating space intact, so
|
||
|
|
# the second was always "not found". Latent, because no shipped command
|
||
|
|
# declares two -- tst/argv_test.cpp is the only program that does.
|
||
|
|
#
|
||
|
|
# Usage: ./command_option_test.sh (needs KLAMMERTEXT_HOME set; commands on PATH)
|
||
|
|
# Exit code: 0 if all tests pass, 1 otherwise.
|
||
|
|
|
||
|
|
PASS=0
|
||
|
|
FAIL=0
|
||
|
|
K=${KLAMMERTEXT_HOME:?KLAMMERTEXT_HOME must be set}
|
||
|
|
TSTDIR="$(cd "$(dirname "$0")" && pwd)"
|
||
|
|
|
||
|
|
red=$'\033[31m'
|
||
|
|
green=$'\033[32m'
|
||
|
|
bold=$'\033[1m'
|
||
|
|
reset=$'\033[0m'
|
||
|
|
|
||
|
|
# A signal death is not an error exit: 128+n, and the point of these tests is
|
||
|
|
# the difference. Report it distinctly so a crash can never read as a pass.
|
||
|
|
died_by_signal() { [ "$1" -gt 128 ]; }
|
||
|
|
|
||
|
|
# error NAME PATTERN CMD... — nonzero exit, no signal, PATTERN in the output.
|
||
|
|
error() {
|
||
|
|
local name="$1" pattern="$2"; shift 2
|
||
|
|
local out status
|
||
|
|
out=$("$@" 2>&1); status=$?
|
||
|
|
if died_by_signal $status; then
|
||
|
|
echo "${red}FAIL${reset} $name — died by signal $((status-128))"; FAIL=$((FAIL+1)); return
|
||
|
|
fi
|
||
|
|
if [ $status -eq 0 ]; then
|
||
|
|
echo "${red}FAIL${reset} $name — reported an error but exited 0"; FAIL=$((FAIL+1)); return
|
||
|
|
fi
|
||
|
|
if printf '%s' "$out" | grep -qF -- "$pattern"; then
|
||
|
|
echo "${green}PASS${reset} $name"; PASS=$((PASS+1))
|
||
|
|
else
|
||
|
|
echo "${red}FAIL${reset} $name — expected [$pattern]"
|
||
|
|
echo " got: $(printf '%s' "$out" | head -2)"; FAIL=$((FAIL+1))
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# ok NAME CMD... — exits 0 and does not die by signal.
|
||
|
|
ok() {
|
||
|
|
local name="$1"; shift
|
||
|
|
local status
|
||
|
|
"$@" >/dev/null 2>&1; status=$?
|
||
|
|
if died_by_signal $status; then
|
||
|
|
echo "${red}FAIL${reset} $name — died by signal $((status-128))"; FAIL=$((FAIL+1))
|
||
|
|
elif [ $status -ne 0 ]; then
|
||
|
|
echo "${red}FAIL${reset} $name — exit $status"; FAIL=$((FAIL+1))
|
||
|
|
else
|
||
|
|
echo "${green}PASS${reset} $name"; PASS=$((PASS+1))
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
echo "${bold}Command option tests${reset}"
|
||
|
|
echo "===================="
|
||
|
|
echo
|
||
|
|
|
||
|
|
echo "-- an option written last, with no value --"
|
||
|
|
error " 1. kdesc -v" "needs a value" kdesc -v
|
||
|
|
error " 2. kdesc with a flag first" "needs a value" kdesc --katoms -v
|
||
|
|
error " 3. kdiag -v" "needs a value" kdiag -v
|
||
|
|
error " 4. ktext -t" "needs a value" ktext -s '@i-x' -t
|
||
|
|
error " 5. the message names the option" "-v <level>" kdesc -v
|
||
|
|
error " 6. ... and how to get the usage" "for the list of arguments" kdesc -v
|
||
|
|
|
||
|
|
echo
|
||
|
|
echo "-- the same options WITH a value still work --"
|
||
|
|
# NOT "kdesc -v 1": show_usage() treats exactly "<command> -v <n>" as a
|
||
|
|
# request for the usage text, which exits 1 by design. Give it another flag.
|
||
|
|
ok " 7. kdesc -c -v 1" kdesc -c -v 1
|
||
|
|
ok " 8. kdesc --katoms -v 1" kdesc --katoms -v 1
|
||
|
|
ok " 9. kdiag -v 1 '@i-x'" kdiag -v 1 '@i-x'
|
||
|
|
ok "10. ktext -t html" ktext -s '@i-x' -t html -d
|
||
|
|
|
||
|
|
echo
|
||
|
|
echo "-- an error exit is nonzero, not a printed message and exit 0 --"
|
||
|
|
error "11. kdesc reports failure" "needs a value" kdesc -v
|
||
|
|
error "12. kdiag reports failure" "needs a value" kdiag -v
|
||
|
|
|
||
|
|
echo
|
||
|
|
echo "-- two required positional arguments --"
|
||
|
|
# argv_test is the only program declaring two; it prints what it parsed.
|
||
|
|
if [ -x "$TSTDIR/argv_test" ]; then
|
||
|
|
out=$("$TSTDIR/argv_test" first second --bool 2>&1 | sed 's/\x1b\[[0-9;]*m//g')
|
||
|
|
for expect in "<input> : first" "<input2> : second"; do
|
||
|
|
if printf '%s' "$out" | grep -qF "$expect"; then
|
||
|
|
echo "${green}PASS${reset} 13/14. positional [$expect]"; PASS=$((PASS+1))
|
||
|
|
else
|
||
|
|
echo "${red}FAIL${reset} 13/14. positional [$expect] not parsed"; FAIL=$((FAIL+1))
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
else
|
||
|
|
echo "SKIP 13/14. two positionals (argv_test not built; run make -C tst)"
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo
|
||
|
|
echo "===================="
|
||
|
|
echo "Results: ${PASS} passed, ${FAIL} failed"
|
||
|
|
[ "$FAIL" -eq 0 ] || exit 1
|
||
|
|
exit 0
|