test-lib: allow test snippets as here-docs
Most test snippets are wrapped in single quotes, like: test_expect_success 'some description' ' do_something ' This sometimes makes the snippets awkward to write, because you can't easily use single quotes within them. We sometimes work around this with $SQ, or by loosening regexes to use "." instead of a literal quote, or by using double quotes when we'd prefer to use single-quotes (and just adding extra backslash-escapes to avoid interpolation). This commit adds another option: feeding the snippet via the function's stdin. This doesn't conflict with anything the snippet would want to do, because we always redirect its stdin from /dev/null anyway (which we'll continue to do). A few notes on the implementation: - it would be nice to push this down into test_run_, but we can't, as test_expect_success and test_expect_failure want to see the actual script content to report it for verbose-mode. A helper function limits the amount of duplication in those callers here. - The helper function is a little awkward to call, as you feed it the name of the variable you want to set. The more natural thing in shell would be command substitution like: body=$(body_or_stdin "$2") but that loses trailing whitespace. There are tricks around this, like: body=$(body_or_stdin "$2"; printf .) body=${body%.} but we'd prefer to keep such tricks in the helper, not in each caller. - I implemented the helper using a sequence of "read" calls. Together with "-r" and unsetting the IFS, this preserves incoming whitespace. An alternative is to use "cat" (which then requires the gross "." trick above). But this saves us a process, which is probably a good thing. The "read" builtin does use more read() syscalls than necessary (one per byte), but that is almost certainly a win over a separate process. Both are probably slower than passing a single-quoted string, but the difference is lost in the noise for a script that I converted as an experiment. - I handle test_expect_success and test_expect_failure here. If we like this style, we could easily extend it to other spots (e.g., lazy_prereq bodies) on top of this patch. - even though we are using "local", we have to be careful about our variable names. Within test_expect_success, any variable we declare with local will be seen as local by the test snippets themselves (so it wouldn't persist between tests like normal variables would). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
0c7d630220
commit
1d133ae91f
8
t/README
8
t/README
@ -906,6 +906,14 @@ see test-lib-functions.sh for the full list and their options.
|
|||||||
'git-write-tree should be able to write an empty tree.' \
|
'git-write-tree should be able to write an empty tree.' \
|
||||||
'tree=$(git-write-tree)'
|
'tree=$(git-write-tree)'
|
||||||
|
|
||||||
|
If <script> is `-` (a single dash), then the script to run is read
|
||||||
|
from stdin. This lets you more easily use single quotes within the
|
||||||
|
script by using a here-doc. For example:
|
||||||
|
|
||||||
|
test_expect_success 'output contains expected string' - <<\EOT
|
||||||
|
grep "this string has 'quotes' in it" output
|
||||||
|
EOT
|
||||||
|
|
||||||
If you supply three parameters the first will be taken to be a
|
If you supply three parameters the first will be taken to be a
|
||||||
prerequisite; see the test_set_prereq and test_have_prereq
|
prerequisite; see the test_set_prereq and test_have_prereq
|
||||||
documentation below:
|
documentation below:
|
||||||
|
@ -872,6 +872,24 @@ test_verify_prereq () {
|
|||||||
BUG "'$test_prereq' does not look like a prereq"
|
BUG "'$test_prereq' does not look like a prereq"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# assign the variable named by "$1" with the contents of "$2";
|
||||||
|
# if "$2" is "-", then read stdin into "$1" instead
|
||||||
|
test_body_or_stdin () {
|
||||||
|
if test "$2" != "-"
|
||||||
|
then
|
||||||
|
eval "$1=\$2"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# start with a newline, to match hanging newline from open-quote style
|
||||||
|
eval "$1=\$LF"
|
||||||
|
local test_line
|
||||||
|
while IFS= read -r test_line
|
||||||
|
do
|
||||||
|
eval "$1=\${$1}\${test_line}\${LF}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
test_expect_failure () {
|
test_expect_failure () {
|
||||||
test_start_ "$@"
|
test_start_ "$@"
|
||||||
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
|
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
|
||||||
@ -881,9 +899,11 @@ test_expect_failure () {
|
|||||||
export test_prereq
|
export test_prereq
|
||||||
if ! test_skip "$@"
|
if ! test_skip "$@"
|
||||||
then
|
then
|
||||||
|
local test_body
|
||||||
|
test_body_or_stdin test_body "$2"
|
||||||
test -n "$test_skip_test_preamble" ||
|
test -n "$test_skip_test_preamble" ||
|
||||||
say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $2"
|
say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $test_body"
|
||||||
if test_run_ "$2" expecting_failure
|
if test_run_ "$test_body" expecting_failure
|
||||||
then
|
then
|
||||||
test_known_broken_ok_ "$1"
|
test_known_broken_ok_ "$1"
|
||||||
else
|
else
|
||||||
@ -902,13 +922,15 @@ test_expect_success () {
|
|||||||
export test_prereq
|
export test_prereq
|
||||||
if ! test_skip "$@"
|
if ! test_skip "$@"
|
||||||
then
|
then
|
||||||
|
local test_body
|
||||||
|
test_body_or_stdin test_body "$2"
|
||||||
test -n "$test_skip_test_preamble" ||
|
test -n "$test_skip_test_preamble" ||
|
||||||
say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $2"
|
say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $test_body"
|
||||||
if test_run_ "$2"
|
if test_run_ "$test_body"
|
||||||
then
|
then
|
||||||
test_ok_ "$1"
|
test_ok_ "$1"
|
||||||
else
|
else
|
||||||
test_failure_ "$@"
|
test_failure_ "$1" "$test_body"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
test_finish_
|
test_finish_
|
||||||
|
Reference in New Issue
Block a user