diff options
-rw-r--r-- | scripts/runtest.sh | 94 | ||||
-rwxr-xr-x | tests/sh.test | 81 |
2 files changed, 100 insertions, 75 deletions
diff --git a/scripts/runtest.sh b/scripts/runtest.sh index 25c8e104..9c19811c 100644 --- a/scripts/runtest.sh +++ b/scripts/runtest.sh @@ -95,6 +95,26 @@ wrong_args() fi } +# Announce failure and handle fallout +do_fail() +{ + FAILCOUNT=$(($FAILCOUNT+1)) + printf "%s\n" "$SHOWFAIL: $NAME" + if [ -n "$VERBOSE" ] + then + [ ! -z "$4" ] && printf "%s\n" "echo -ne \"$4\" > input" + printf "%s\n" "echo -ne '$5' |$EVAL $2" + printf "%s\n" "$DIFF" + [ "$VERBOSE" == fail ] && exit 1 + fi +} + +# Announce success +do_pass() +{ + [ "$VERBOSE" != "nopass" ] && printf "%s\n" "$SHOWPASS: $NAME" +} + # The testing function testing() @@ -124,15 +144,7 @@ testing() DIFF="$(diff -au${NOSPACE:+w} expected actual)" if [ ! -z "$DIFF" ] then - FAILCOUNT=$(($FAILCOUNT+1)) - printf "%s\n" "$SHOWFAIL: $NAME" - if [ -n "$VERBOSE" ] - then - [ ! -z "$4" ] && printf "%s\n" "echo -ne \"$4\" > input" - printf "%s\n" "echo -ne '$5' |$EVAL $2" - printf "%s\n" "$DIFF" - [ "$VERBOSE" == fail ] && exit 1 - fi + do_fail else [ "$VERBOSE" != "nopass" ] && printf "%s\n" "$SHOWPASS: $NAME" fi @@ -152,6 +164,70 @@ testcmd() testing "$X" "\"$C\" $2" "$3" "$4" "$5" } +# txpect NAME COMMAND I/O/E/Xstring +# Run COMMAND and interact with it: send I strings to input, read O or E +# strings from stdout or stderr (empty string is "any nonzero string here"), +# X means close stdin/stdout/stderr and match return code (blank means nonzero) +txpect() +{ + # Run command with redirection through fifos + NAME="$1" + + if [ $# -lt 2 ] || ! mkfifo in-$$ out-$$ err-$$ + then + do_fail + return + fi + $2 <in-$$ >out-$$ 2>err-$$ & + shift 2 + : {IN}>in-$$ {OUT}<out-$$ {ERR}<err-$$ && rm in-$$ out-$$ err-$$ + + [ $? -ne 0 ] && { do_fail;return;} + + # Loop through challenge/response pairs, with 2 second timeout + while [ $# -gt 0 ] + do + LEN=$((${#1}-1)) + case ${1::1} in + + # send input to child + I) echo -en "${1:1}" >&$IN || { do_fail;return;} ;; + + # check output from child + [OE]) + [ $LEN == 0 ] && LARG="" || LARG="-rN $LEN" + O=$OUT + [ ${1::1} == 'E' ] && O=$ERR + read -t2 $LARG A <&$O + if [ $LEN -eq 0 ] + then + [ -z "$A" ] && { do_fail;return;} + else + [ "$A" != "${1:1}" ] && { do_fail;return;} + fi + ;; + + # close I/O and wait for exit + X) + exec {IN}<&- {OUT}<&- {ERR}<&- + wait + X=$? + if [ -z "$LEN" ] + then + [ $X -eq 0 ] && { do_fail;return;} # any error + else + [ $X != "${1:1}" ] && { do_fail;return;} # specific value + fi + ;; + esac + shift + done + # In case we already closed it + exec {IN}<&- {OUT}<&- {ERR}<&- + + do_pass +} + # Recursively grab an executable and all the libraries needed to run it. # Source paths beginning with / will be copied into destpath, otherwise # the file is assumed to already be there and only its library dependencies diff --git a/tests/sh.test b/tests/sh.test index 875a0df8..ac7b6e45 100755 --- a/tests/sh.test +++ b/tests/sh.test @@ -1,76 +1,25 @@ #!/bin/bash +# Testing shell corner cases _within_ a shell script is kind of hard. + [ -f testing.sh ] && . testing.sh #testing "name" "command" "result" "infile" "stdin" -if [ -z "$(which bash)" ] -then - echo "$SHOWSKIP: no bash alias" - return 2>/dev/null - exit -fi - -shellit() -{ - EVAL="bash -c" testing "$2" "$1 printf %s $2" "$3" "$4" "$5" -} - -# $'' expands special chars but doesn't do so inside double quotes. +[ -z "$SH" ] && { [ -z "$TEST_HOST" ] && SH="sh" || export SH="bash" ; } +export EVAL="$SH -c" -shellit "" "\$'a\\tb'" "a\tb" "" "" -shellit "" "\"\$'a\\tb'\"" '$'"'"'a\\tb'"'" "" "" +testing "leading assignments don't affect current line" \ + 'VAR=12345 echo ${VAR}a' "a\n" "" "" +testing "can't have space before first : but yes around arguments" \ + 'BLAH=abcdefghi; echo ${BLAH: 1 : 3 }' "bcd\n" "" "" -# $(( )) tests +# Prompt changes for root/normal user +[ $(id -u) -eq 0 ] && P='#' || P='$' +# run sufficiently isolated shell child process to get predictable results +SH="env -i PATH=${PATH@Q} PS1=\\$ $SH --noediting --noprofile --norc -is" -shellit 'x=1;' '$((-x))' '-1' '' '' -shellit 'x=0;' '$((x++)); echo $x' '01\n' '' '' -shellit 'x=0;' '$((++x))' '1' '' '' -shellit 'x=0;' '$((~x))' '-1' '' '' -shellit 'x=1;' '$((!x))' '0' '' '' -shellit 'x=0;' '$((!x))' '1' '' '' -shellit 'x=2;' '$((2*x))' '4' '' '' -shellit 'x=9;' '$((x/4))' '2' '' '' -shellit 'x=9;' '$((x%4))' '1' '' '' -shellit 'x=4;' '$((x+2))' '6' '' '' -shellit 'x=4;' '$((x-2))' '2' '' '' -shellit 'x=4;' '$((1<<x))' '16' '' '' -shellit 'x=4;' '$((x>>1))' '2' '' '' -shellit '' '$((3**4))' '81' '' '' -shellit '' '$((3<=4))' '1' '' '' -shellit '' '$((3>=4))' '0' '' '' -shellit '' '$((3<4))' '1' '' '' -shellit '' '$((3>4))' '0' '' '' -shellit '' '$((3==4))' '0' '' '' -shellit '' '$((3!=4))' '1' '' '' -shellit '' '$((6&4))' '4' '' '' -shellit '' '$((4|2))' '6' '' '' -shellit '' '$((6&&2))' '1' '' '' -shellit '' '$((6||4))' '1' '' '' -shellit '' '$((1?2:3))' '2' '' '' -shellit 'x=2;' '$((x=3)); echo $x' '33\n' '' '' -shellit 'x=2;' '$((x*=3)); echo $x' '66\n' '' '' -shellit 'x=5;' '$((x/=2)); echo $x' '22\n' '' '' -shellit 'x=9;' '$((x%=5)); echo $x' '44\n' '' '' -shellit 'x=9;' '$((x-=3)); echo $x' '66\n' '' '' -shellit 'x=3;' '$((x+=2)); echo $x' '55\n' '' '' -shellit 'x=7;' '$((x&=13)); echo $x' '55\n' '' '' -shellit 'x=5;' '$((x|=12)); echo $x' '1313\n' '' '' -shellit 'x=5;' '$((x^=12)); echo $x' '99\n' '' '' -shellit 'x=2;' '$((x<<=2)); echo $x' '88\n' '' '' -shellit 'x=12;' '$((x>>=2)); echo $x' '33\n' '' '' -shellit 'x=2;' '$((x++,5)); echo $x' '53\n' '' '' +# texpect "name" "command" E/O/I"string" -# echo $(ls -l #comment) -# cat -</dev/null -# cat -|xargs echo -# cat -(ls) -# echo -! -# echo -{ -# echo -( -# (echo -) -# echo $ -# "echo \$(echo \"hello\nworld\")" -# "echo \"one ;\ntwo\"" -# echo $(ls -l &) -# echo one < /dev/null two +txpect "prompt and exit" "$SH" "E$P" "Iexit\n" X0 +txpect "prompt and echo" "$SH" "E$P" "Iecho hello\n" "Ohello"$'\n' "E$P" X0 |