I have a utility script that is to be sourced that includes two functions that prompt the user for input; anykey
and yesno
.
How can I test the prompt? The prompt text doesn't show up in $output
.
Also, how can I force the while loop in yesno
to break out of the while loop from the test?
function anykey() { read -n 1 -r -s -p "${1:-Press any key to continue ...}"; }
function yesno() {
local -u yn
while true; do
# shellcheck disable=SC2162
read -N1 -p "${1:-Yes or no?} " yn
case $yn in
Y | N)
printf '%s' "$yn"
return
;;
Q)
warn 'Exiting...'
exit 1
;;
*)
warn 'Please enter a Y or a N'
;;
esac
done
}
I have the following in my utility.bats
file:
#------------------------------------------------------------
# test yesno
if [[ -z "$(type -t yesno)" ]]; then
echo "yesno not defined after sourcing utility" >&2
exit 1
fi
@test 'yesno function exists' {
run type -t yesno
[ "$output" == 'function' ]
}
@test 'yesno accepts y' {
run yesno <<< 'y'
[[ "$status" == 0 ]]
[[ "$output" == 'Y' ]]
}
@test 'yesno accepts Y' {
run yesno <<< 'Y'
[[ "$status" == 0 ]]
[[ "$output" == 'Y' ]]
}
@test 'yesno accepts n' {
run yesno <<< 'n'
[[ "$status" == 0 ]]
[[ "$output" == 'N' ]]
}
@test 'yesno accepts N' {
run yesno <<< 'N'
[[ "$status" == 0 ]]
[[ "$output" == 'N' ]]
}
@test 'yesno accepts q' {
run yesno <<< 'q'
[[ "$status" == 1 ]]
[[ "$output" == 'Exiting...' ]]
}
@test 'yesno accepts Q' {
run yesno <<< 'Q'
[[ "$status" == 1 ]]
[[ "$output" == 'Exiting...' ]]
}
@test 'yesno rejects x' {
run yesno <<< 'x'
[[ "$output" == 'Please enter a Y or a N' ]]
}
All tests, except for the last one, yesno rejects x
, seem to be working correctly. The last one hangs because of the while true
loop. How can I mock multiple keyboard inputs in the test?
Edit: The warn function is a simple one:
warn() { printf '%s\n' "$*" >&2; }
What seems to work for me is simply providing enough answers to get out of the loop:
@test 'yesno rejects x, then accepts N' {
run yesno <<< "xN"
[[ "${lines[0]}" == 'Please enter a Y or a N' ]]
[[ "${lines[1]}" == 'N' ]]
[[ "${lines[3]}" == '' ]]
}
@test 'yesno rejects x and space, then accepts Y' {
run yesno <<< 'x Y'
[[ "${lines[0]}" == 'Please enter a Y or a N' ]]
[[ "${lines[1]}" == 'Please enter a Y or a N' ]]
[[ "${lines[2]}" == 'Y' ]]
[[ "${lines[3]}" == '' ]]
}