diff --git a/src/expect-core b/src/expect-core index 368c5be..b2d2f49 100644 --- a/src/expect-core +++ b/src/expect-core @@ -22,10 +22,7 @@ [ -z $__INC_EXPECT_CORE ] || return __INC_EXPECT_CORE=1 -source util - -# reserved for our uses -exec 99<>/dev/null +source expect/output ## @@ -69,125 +66,3 @@ _expect--be() { _proxy-to "$@"; } _expect--succeed() { test "$1" -eq 0; } _expect--fail() { test "$1" -ne 0; } - -## -# Expect that the given string is output on stdout or stderr -# -# Defaults to asserting against stdout; behavior may be overridden with the -# `on stderr' clause. Specifying `on stdout' may be used for clarity, but is -# redundant. -# -# This expectation assumes a trailing newline by default; this behavior can -# be suppressed with the `without newline' clause. -_expect--output() -{ - local -a args=("$@") - local -i shiftn="$2" - shift "$shiftn" - local -r cmp="$1" - shift - local nl - - if [ $# -gt 0 ]; then - # this is not a common clause; process before generic parsing - if [ "$1 $2" == 'without newline' ]; then - nl=-n - unset args[$shiftn+1], args[$shiftn+2] - fi - fi - - __expect--output-cmd "__expect--output-do -$nl" "${args[@]}" -} - -__expect--output-do() -{ - local -r nl="${1:1}" - local -r cmp="$2" - - # we will eventually be interested in this output - # TODO: fast check first, diff if non-match - diff <( echo $nl "$cmp" ) - -} - -__expect--output-cmd() -{ - local -r cmd="$1" - shift - - local -ri shiftn="$2" - local -r stderr="$3" - shift "$shiftn" - - # output-specific clauses - local -r cmp="$1" - shift - local -ar clause=("$@") - - local nl - local intype - { - __expect--output-clause "${clause[@]}" | { - IFS=\| read nl intype - - if [ "$intype" == stderr ]; then - __chk-shiftn 3 "$shiftn" - exec 99<"$stderr" - fi - - $cmd "$cmp" <&99 &>/dev/null - } - } 99<&0 - - aok "${PIPESTATUS[@]}" -} - -# parses output remainder clause according to the aforementioned rules -__expect--output-clause() -{ - [ $# -gt 0 ] || return 0 - - local input= - - if [ $# -gt 0 ]; then - if [[ "$1 $2" =~ ^on\ std(err|out) ]]; then - [ "$2" == stderr ] && input="$2" - else - _bail_clause output "$*" - fi - fi - - echo "$nl|$input" -} - - -## -# Expects that stdout matches the provided extended regular expression (as -# in regex(3)) -_expect--match() -{ - __expect--output-cmd '__expect--match-do' "$@" -} - -__expect--match-do() -{ - local -r pat="$1" - [[ "$(cat)" =~ $pat ]] -} - - -## -# Expects that both stdin and stderr (if available) are empty -_expect--silent() -{ - local -r stderr="${3:-/dev/null}" - shift "$2" - - # we accept no arguments - test $# -eq 0 || _bail_clause silent "$*" - - # quick read using builtins; if we find any single byte, then we know that - # it is non-empty - read -N1 || read -N1 <"$stderr" || return 0 - return 1 -} - diff --git a/src/expect/output b/src/expect/output new file mode 100644 index 0000000..58164c5 --- /dev/null +++ b/src/expect/output @@ -0,0 +1,168 @@ +#!/bin/bash +# Output expectations +# +# Copyright (C) 2014 Mike Gewitz +# +# This file is part of shspec. +# +# shspec is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +## + +[ -z $__INC_EXPECT_OUTPUT ] || return +__INC_EXPECT_OUTPUT=1 + +source util + +# reserved for our uses +exec 99<>/dev/null + + +## +# Generic output expectation processing +# +# This provides a generic facility for processing output on stdout or +# stderr, supporting `on std(err|out)' clauses. +# +# First processes remainder clause for common sub-clauses; any +# expectation-specific sub-clauses should therefore be processed and +# stripped beforehand to prevent errors. +# +# Assuming clause validity, determines (based on the clause) whether to +# assert against stdout or stderr, and then invokes the provided command +# line with an additional parameter representing the user-supplied +# comparison argument; stdout/stderr input is provided via stdin. +# +# This command is successful if and only if both the remainder clause and +# the provided command line complete successfully. +__expect-output-cmd() +{ + local -r cmd="$1" + shift + + local -ri shiftn="$2" + local -r stderr="$3" + shift "$shiftn" + + # output-specific clauses + local -r cmp="$1" + shift + local -ar clause=("$@") + + local nl + local intype + { + __expect-output-clause "${clause[@]}" | { + IFS=\| read nl intype + + if [ "$intype" == stderr ]; then + __chk-shiftn 3 "$shiftn" + exec 99<"$stderr" + fi + + $cmd "$cmp" <&99 &>/dev/null + } + } 99<&0 + + aok "${PIPESTATUS[@]}" +} + +# parses output remainder clause according to the aforementioned rules +__expect-output-clause() +{ + [ $# -gt 0 ] || return 0 + + local input= + + if [ $# -gt 0 ]; then + if [[ "$1 $2" =~ ^on\ std(err|out) ]]; then + [ "$2" == stderr ] && input="$2" + else + _bail_clause output "$*" + fi + fi + + echo "$nl|$input" +} + + +## +# Expect that the given string is output on stdout or stderr +# +# Defaults to asserting against stdout; behavior may be overridden with the +# `on stderr' clause. Specifying `on stdout' may be used for clarity, but is +# redundant. +# +# This expectation assumes a trailing newline by default; this behavior can +# be suppressed with the `without newline' clause. +_expect--output() +{ + local -a args=("$@") + local -i shiftn="$2" + shift "$shiftn" + local -r cmp="$1" + shift + local nl + + if [ $# -gt 0 ]; then + # this is not a common clause; process before generic parsing + if [ "$1 $2" == 'without newline' ]; then + nl=-n + unset args[$shiftn+1], args[$shiftn+2] + fi + fi + + __expect-output-cmd "__expect--output-do -$nl" "${args[@]}" +} + +__expect--output-do() +{ + local -r nl="${1:1}" + local -r cmp="$2" + + # we will eventually be interested in this output + # TODO: fast check first, diff if non-match + diff <( echo $nl "$cmp" ) - +} + + +## +# Expects that stdout matches the provided extended regular expression (as +# in regex(3)) +_expect--match() +{ + __expect-output-cmd '__expect--match-do' "$@" +} + +__expect--match-do() +{ + local -r pat="$1" + [[ "$(cat)" =~ $pat ]] +} + + +## +# Expects that both stdin and stderr (if available) are empty +_expect--silent() +{ + local -r stderr="${3:-/dev/null}" + shift "$2" + + # we accept no arguments + test $# -eq 0 || _bail_clause silent "$*" + + # quick read using builtins; if we find any single byte, then we know that + # it is non-empty + read -N1 || read -N1 <"$stderr" || return 0 + return 1 +}