summaryrefslogtreecommitdiff
path: root/t/test-lib.sh
diff options
context:
space:
mode:
authorEric Sunshine <sunshine@sunshineco.com>2018-07-11 06:46:33 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-07-17 16:15:14 (GMT)
commit878f9883507492fe1734561ea8ddc3c4e9de3c1d (patch)
tree3d1b20bca3e348287f0c486e3816e090fe9bcd82 /t/test-lib.sh
parent95005262844c470652538d53e11cd68d23a0fb62 (diff)
downloadgit-878f9883507492fe1734561ea8ddc3c4e9de3c1d.zip
git-878f9883507492fe1734561ea8ddc3c4e9de3c1d.tar.gz
git-878f9883507492fe1734561ea8ddc3c4e9de3c1d.tar.bz2
t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
The --chain-lint option detects broken &&-chains by forcing the test to exit early (as the very first step) with a sentinel value. If that sentinel is the test's overall exit code, then the &&-chain is intact; if not, then the chain is broken. Unfortunately, this detection does not extend to &&-chains within subshells even when the subshell itself is properly linked into the outer &&-chain. Address this shortcoming by feeding the body of the test to a lightweight "linter" which can peer inside subshells and identify broken &&-chains by pure textual inspection. Although the linter does not actually parse shell scripts, it has enough knowledge of shell syntax to reliably deal with formatting style variations (as evolved over the years) and to avoid being fooled by non-shell content (such as inside here-docs and multi-line strings). It recognizes modern subshell formatting: statement1 && ( statement2 && statement3 ) && statement4 as well as old-style: statement1 && (statement2 && statement3) && statement4 Heuristics are employed to properly identify the extent of a subshell formatted in the old-style since a number of legitimate constructs may superficially appear to close the subshell even though they don't. For example, it understands that neither "x=$(command)" nor "case $x in *)" end a subshell, despite the ")" at the end of line. Due to limitations of the tool used ('sed') and its inherent line-by-line processing, only subshells one level deep are handled, as well as one-liner subshells one level below that. Subshells deeper than that or multi-line subshells at level two are passed through as-is, thus &&-chains in their bodies are not checked. Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 't/test-lib.sh')
-rw-r--r--t/test-lib.sh3
1 files changed, 2 insertions, 1 deletions
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 2831570..78f7097 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -675,7 +675,8 @@ test_run_ () {
trace=
# 117 is magic because it is unlikely to match the exit
# code of other programs
- if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
+ if $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!') ||
+ test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
then
error "bug in the test script: broken &&-chain or run-away HERE-DOC: $1"
fi