diff options
author | Eric Sunshine <sunshine@sunshineco.com> | 2018-07-11 02:46:33 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2018-07-17 09:15:14 -0700 |
commit | 878f9883507492fe1734561ea8ddc3c4e9de3c1d (patch) | |
tree | 3d1b20bca3e348287f0c486e3816e090fe9bcd82 /t/test-lib.sh | |
parent | t5608: fix broken &&-chain (diff) | |
download | tgif-878f9883507492fe1734561ea8ddc3c4e9de3c1d.tar.xz |
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.sh | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/t/test-lib.sh b/t/test-lib.sh index 28315706be..78f7097746 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 |