diff --git a/src/common.sh b/src/common.sh
index f721136..aa2af42 100644
--- a/src/common.sh
+++ b/src/common.sh
@@ -28,6 +28,9 @@ __desc_case=
# stderr file
__desc_errpath="$(mktemp)"
+# env file
+__desc_envpath="$(mktemp)"
+
# most recent expect result and its exit code
__desc_result=
__desc_rexit=0
@@ -162,9 +165,16 @@ bail()
expect()
{
__desc-assert-within it expect $(caller)
- __desc_result="$($@ 2>"$__desc_errpath")"
__desc_rexit=$?
__desc-push ":expect $(caller) $@"
+
+ # stdout remains on stdout; stderr to a tmp file; environment to a tmp
+ # file (note that we use declare instead of env to ensure that
+ # non-exported variables are also included)
+ __desc_result="$(
+ $@ 2>"$__desc_errpath"
+ declare -p >"$__desc_envpath"
+ )"
}
to()
diff --git a/src/expect.sh b/src/expect.sh
index 2d44875..56db94e 100644
--- a/src/expect.sh
+++ b/src/expect.sh
@@ -23,6 +23,7 @@
__INC_EXPECT_CORE=1
source expect/output.sh
+source expect/env.sh
##
diff --git a/src/expect/env.sh b/src/expect/env.sh
new file mode 100644
index 0000000..771d0c6
--- /dev/null
+++ b/src/expect/env.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+# Environment 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_ENV ] || return
+__INC_EXPECT_ENV=1
+
+
+##
+# Expect that an environment variable is set to a particular value
+#
+# The variable need not be exported.
+#
+_expect--set()
+{
+ local -ri shiftn="$2"
+ local -r envpath="$4"
+ shift "$shiftn"
+
+ # ensure envpath is available
+ __chk-shiftn 4 "$shiftn"
+
+ local -r var="$1" cmp="$2"
+ shift 2
+ local -r expect="$@"
+
+ # TODO: support escaped newlines; use awk (do not source the file)
+ local -r line="$( grep "^declare \.*-- $var=" "$envpath" )"
+ local -r valq="${line##*=\"}"
+ local -r val="${valq%%\"}"
+
+ # cannot quote regex without causing problems, and [[ syntax does not
+ # allow a variable comparison operator; further, argument order varies
+ # with certain operators; whitelist to explicitly document support and
+ # prevent oddities
+ case "$cmp" in
+ =~)
+ [[ "$val" =~ $expect ]];;
+
+ -[nz])
+ test "$cmp" "$val";;
+
+ =|==|!=|-eq|-ne|-lt|-le|-gt|-ge)
+ test "$val" $cmp "$expect";;
+
+ *) false;;
+ esac
+}
+
diff --git a/src/spec.sh b/src/spec.sh
index 16cce58..3d898a7 100644
--- a/src/spec.sh
+++ b/src/spec.sh
@@ -33,7 +33,7 @@ source specstack.sh
source expect.sh
# number of internal arguments before remainder clause
-declare -ir __SHIFTN=3
+declare -ir __SHIFTN=4
##
@@ -48,6 +48,9 @@ mktemp-shm()
# stderr file
declare -r __spec_errpath="$(mktemp-shm)"
+# env dump file
+declare -r __spec_envpath="$(mktemp-shm)"
+
# most recent expect result and its exit code
declare __spec_result=
declare -i __spec_rexit=0
@@ -162,7 +165,8 @@ to()
_sstack-assert-follow :expect to $(caller)
_sstack-pop
- __handle-to "$__spec_rexit" $__SHIFTN "$__spec_errpath" "$@" \
+ __handle-to "$__spec_rexit" $__SHIFTN \
+ "$__spec_errpath" "$__spec_envpath" "$@" \
|| fail "$*"
__spec_caller=
@@ -182,6 +186,7 @@ __handle-to()
local -ri rexit="$1"
local -ri shiftn="$2"
local -r errpath="$( [ $shiftn -gt 2 ] && echo "$3" )"
+ local -r envpath="$( [ $shiftn -gt 3 ] && echo "$4" )"
shift "$shiftn"
local -r type="$1"
@@ -196,7 +201,7 @@ __handle-to()
# output file, and all remaining arguments are said remainder clause; the
# shift argument allows the implementation to vary without breaking BC so
# long as the meaning of the shifted arguments do not change
- $assert $rexit $__SHIFTN "$errpath" "$@" \
+ $assert $rexit $__SHIFTN "$errpath" "$envpath" "$@" \
< <( echo -n "$__spec_result" )
}
diff --git a/test/test-expect-core b/test/test-expect-core
index a57f786..1b222e8 100644
--- a/test/test-expect-core
+++ b/test/test-expect-core
@@ -188,7 +188,7 @@ describe silent
# no arguments within context of the DSL, that is
it accepts no arguments
- expect _expect--silent 0 2 foo < <(:)
+ expect _expect--silent 0 2 foo < <(:)
to fail
end
end
diff --git a/test/test-expect-env b/test/test-expect-env
new file mode 100644
index 0000000..e5fb3be
--- /dev/null
+++ b/test/test-expect-env
@@ -0,0 +1,207 @@
+#!/bin/bash
+# Environment expectation tests
+#
+# 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 .
+##
+
+declare -r stubenv='
+declare -- var="val"
+declare -- long="foo bar baz"
+declare -- empty=""
+declare -- one="1"'
+
+
+function setchk()
+{
+ _expect--set 0 4 <(:) <( echo "$stubenv" ) "$@"
+}
+
+
+describe set
+ describe = and == operators
+ it succeeds on string equality
+ expect setchk var = val
+ to succeed
+
+ expect setchk var == val
+ to succeed
+ end
+
+ it fails on string inequality
+ expect setchk var = unval
+ to fail
+
+ expect setchk var == unval
+ to fail
+ end
+ end
+
+
+ describe != operator
+ it succeeds on string inequality
+ expect setchk var != foo
+ to succeed
+ end
+
+ it fails on string equality
+ expect setchk var != val
+ to fail
+ end
+ end
+
+
+ describe =~ operator
+ it succeeds on a match
+ expect setchk \
+ long =~ fo+ ba. baz\$
+ to succeed
+ end
+
+ # note that this also ensures that *all* arguments are part of the match
+ it fails on a mismatch
+ expect setchk \
+ long =~ fo+ baX baz\$
+ to fail
+ end
+ end
+
+
+ describe -n operator
+ it succeeds when string is non-empty
+ expect setchk var -n
+ to succeed
+ end
+
+ it fails when string is empty
+ expect setchk empty -n
+ to fail
+ end
+ end
+
+
+ describe -z operator
+ it succeeds when string is empty
+ expect setchk empty -z
+ to succeed
+ end
+
+ it fails when string is non-empty
+ expect setchk var -z
+ to fail
+ end
+ end
+
+
+ describe -eq operator
+ it succeeds on numeric equality
+ expect setchk one -eq 1
+ to succeed
+ end
+
+ it fails on numeric inequality
+ expect setchk one -eq 2
+ to fail
+ end
+ end
+
+
+ describe -gt operator
+ it succeeds when numerically greater
+ expect setchk one -gt 0
+ to succeed
+ end
+
+ it fails when not numerically greater
+ expect setchk one -gt 1
+ to fail
+ end
+ end
+
+
+ describe -ge operator
+ it succeeds when numerically greater
+ expect setchk one -ge 0
+ to succeed
+ end
+
+ it succeeds when numerically equal
+ expect setchk one -ge 1
+ to succeed
+ end
+
+ it fails when numerically less than
+ expect setchk one -ge 2
+ to fail
+ end
+ end
+
+
+ describe -lt operator
+ it succeeds when numerically less than
+ expect setchk one -lt 2
+ to succeed
+ end
+
+ it fails when not numerically less than
+ expect setchk one -lt 1
+ to fail
+ end
+ end
+
+
+ describe -le operator
+ it succeeds when numerically less than
+ expect setchk one -le 2
+ to succeed
+ end
+
+ it succeeds when numerically equal
+ expect setchk one -le 1
+ to succeed
+ end
+
+ it fails when numerically greater than
+ expect setchk one -le 0
+ to fail
+ end
+ end
+
+
+ describe -ne operator
+ it succeeds when numerically unequal
+ expect setchk one -ne 2
+ to succeed
+ end
+
+ it fails when numerically equal
+ expect setchk one -ne 1
+ to fail
+ end
+ end
+
+
+ # primarily for safety and strict documentation, but no other tests make
+ # sense at the moment
+ it fails on unrecognized operators
+ # shell injection (not that this is realistically a problem, because we
+ # can execute arbitrary shell code anyway)
+ expect setchk var "!= foo -a 1 -eq" 1
+ to fail
+ end
+end
+