git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 00/19] tests: fix broken &&-chains & abort loops on error
@ 2021-12-09  5:10 Eric Sunshine
  2021-12-09  5:10 ` [PATCH 01/19] t/lib-pager: use sane_unset() to avoid breaking &&-chain Eric Sunshine
                   ` (20 more replies)
  0 siblings, 21 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:10 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

A while back, Peff successfully nerd-sniped[1] me into tackling a
long-brewing idea I had about (possibly) improving `chainlint`
performance by linting all tests in all scripts with a single command
invocation instead of running `sed` 25300+ times (once for each test).

Beside the obvious improvement of checking all tests in all scripts at
once, the new linter is also a good deal smarter than chainlint.sed and
understands not just shell syntax but also some semantics of test
construction, unlike chainlint.sed which is merely heuristics-based.
For instance, the new linter recognizes cases when a broken &&-chain is
legitimate, such as when `$?` is handled explicitly or when a failure is
signaled directly with `false`, in which case the &&-chain leading up to
the `false` is immaterial, as well as other cases. Unlike chainlint.sed,
it recognizes that a semicolon after the last command in a compound
statement is harmless, thus won't interpret the semicolon as breaking
the &&-chain.

The new linter also provides considerably better coverage for broken
&&-chains. The &&-chain checker built into t/test-lib.sh, which causes
tests to magically exit with code 117 if the &&-chain is broken, only
works for top-level command invocations. The magic doesn't work within
`{...}` groups, `(...)` subshells, `$(...)` substitutions, or within
bodies of compound statements, such as `if`, `for`, `while`, `case`,
etc. chainlint.sed partly fills the gap by catching broken &&-chains in
`(...)` subshells one level deep, but bugs can still lurk behind broken
&&-chains in the other cases. The new linter catches broken &&-chains
within all those constructs to any depth.

Another important improvement is that the new linter understands that
shell loops do not terminate automatically when a command in the loop
body fails, and that the condition needs to be handled explicitly by the
test author by using `|| return 1` (or `|| exit 1` in a subshell) within
the loop body to flag the failure. Consequently, the new linter will
complain when a loop is lacking `|| return 1` (or `|| exit 1`). There
are a number of other improvements, as well, but the above are some of
the more important ones.

Although the new chainlint implementation has been complete for several
months, I'm still working out how to organize its patch series. In the
meantime, _this_ patch series fixes problems discovered by the new
linter due to its improved coverage and extra semantic knowledge about
Git tests. As much as possible, I resisted the temptation to make
ancillary cleanups (including indentation fixes) to tests even when such
cleanups would be obvious improvements. Avoiding such unrelated cleanups
should make the long patches in this series, which touch a lot of tests,
easier to review (--color-words helps a lot here).

This series merges cleanly with 'next' but conflicts with a couple topics
in 'seen':

* jh/builtin-fsmonitor-part2

  t/perf/p7519-fsmonitor.sh
    simple resolution: keep all changes from jh/builtin-fsmonitor-part2
    (it obviates the need for the fixes made by this series)

* ms/customizable-ident-expansion

  t/t0021-conversion.sh
    this is a messy conflict but resolution is simple enough: keep all
    the changes made by ms/customizable-ident-expansion and throw away
    the changes by this series; this will leave a few broken &&-chains
    in t0021-conversion.sh but there are a few other topics in 'seen'
    with such problems already, so it has company; anyhow, "What's
    Cooking" indicates that ms/customizable-ident-expansion is going to
    be discarded, so it may not be worth worrying about it

[1]: https://lore.kernel.org/git/YJzGcZpZ+E9R0gYd@coredump.intra.peff.net/

Eric Sunshine (19):
  t/lib-pager: use sane_unset() to avoid breaking &&-chain
  t1010: fix unnoticed failure on Windows
  t1020: avoid aborting entire test script when one test fails
  t4202: clarify intent by creating expected content less cleverly
  t5516: drop unnecessary subshell and command invocation
  t6300: make `%(raw:size) --shell` test more robust
  t9107: use shell parameter expansion to avoid breaking &&-chain
  tests: simplify construction of large blocks of text
  tests: use test_write_lines() to generate line-oriented output
  tests: fix broken &&-chains in compound statements
  tests: fix broken &&-chains in `$(...)` command substitutions
  tests: fix broken &&-chains in `{...}` groups
  tests: apply modern idiom for signaling test failure
  tests: apply modern idiom for exiting loop upon failure
  tests: simplify by dropping unnecessary `for` loops
  t0000-t3999: detect and signal failure within loop
  t4000-t4999: detect and signal failure within loop
  t5000-t5999: detect and signal failure within loop
  t6000-t9999: detect and signal failure within loop

 .../mw-to-git/t/t9365-continuing-queries.sh   |   2 +-
 contrib/subtree/t/t7900-subtree.sh            |   2 +-
 t/annotate-tests.sh                           |   2 +-
 t/lib-pager.sh                                |   2 +-
 t/perf/p0005-status.sh                        |  12 +-
 t/perf/p0006-read-tree-checkout.sh            |  20 +-
 t/perf/p0007-write-cache.sh                   |   4 +-
 t/perf/p0100-globbing.sh                      |   4 +-
 t/perf/p1400-update-ref.sh                    |   4 +-
 t/perf/p1451-fsck-skip-list.sh                |   2 +-
 t/perf/p3400-rebase.sh                        |   2 +-
 t/perf/p5302-pack-index.sh                    |   4 +-
 t/perf/p5303-many-packs.sh                    |  10 +-
 t/perf/p7519-fsmonitor.sh                     |   8 +-
 t/t0005-signals.sh                            |   2 +-
 t/t0008-ignores.sh                            |   2 +-
 t/t0011-hashmap.sh                            |   4 +-
 t/t0020-crlf.sh                               |  28 +-
 t/t0021-conversion.sh                         |  60 ++--
 t/t0026-eol-config.sh                         |   4 +-
 t/t0060-path-utils.sh                         |   4 +-
 t/t0069-oidtree.sh                            |  12 +-
 t/t0095-bloom.sh                              |   4 +-
 t/t0410-partial-clone.sh                      |   2 +-
 t/t1006-cat-file.sh                           |  12 +-
 t/t1010-mktree.sh                             |   4 +-
 t/t1020-subdirectory.sh                       |  10 +-
 t/t1050-large.sh                              |  34 +-
 t/t1091-sparse-checkout-builtin.sh            |   2 +-
 t/t1300-config.sh                             |   6 +-
 t/t1400-update-ref.sh                         |   4 +-
 t/t1403-show-ref.sh                           |  12 +-
 t/t1410-reflog.sh                             |   4 +-
 t/t1512-rev-parse-disambiguation.sh           |  12 +-
 t/t1700-split-index.sh                        |   4 +-
 t/t2004-checkout-cache-temp.sh                |   4 +-
 t/t2012-checkout-last.sh                      |   4 +-
 t/t2102-update-index-symlinks.sh              |   2 +-
 t/t2103-update-index-ignore-missing.sh        |   2 +-
 t/t2200-add-update.sh                         |  18 +-
 t/t2201-add-update-typechange.sh              |  10 +-
 t/t2203-add-intent.sh                         |   2 +-
 t/t3005-ls-files-relative.sh                  |  10 +-
 t/t3070-wildmatch.sh                          |   2 +-
 t/t3202-show-branch.sh                        |   8 +-
 t/t3303-notes-subtrees.sh                     |   6 +-
 t/t3305-notes-fanout.sh                       |   4 +-
 t/t3402-rebase-merge.sh                       |   8 +-
 t/t3404-rebase-interactive.sh                 |   4 +-
 t/t3417-rebase-whitespace-fix.sh              |   4 +-
 t/t3501-revert-cherry-pick.sh                 |   2 +-
 t/t3508-cherry-pick-many-commits.sh           |   2 +-
 t/t3600-rm.sh                                 |   7 +-
 t/t3700-add.sh                                |   8 +-
 t/t3920-crlf-messages.sh                      |   4 +-
 t/t4001-diff-rename.sh                        |   2 +-
 t/t4012-diff-binary.sh                        |   2 +-
 t/t4013-diff-various.sh                       |  22 +-
 t/t4014-format-patch.sh                       |  32 +-
 t/t4015-diff-whitespace.sh                    |   4 +-
 t/t4018-diff-funcname.sh                      |   2 +-
 t/t4019-diff-wserror.sh                       |   4 +-
 t/t4023-diff-rename-typechange.sh             |   6 +-
 t/t4024-diff-optimize-common.sh               |   2 +-
 t/t4025-hunk-header.sh                        |  10 +-
 t/t4038-diff-combined.sh                      |   2 +-
 t/t4046-diff-unmerged.sh                      |  10 +-
 t/t4049-diff-stat-count.sh                    |   2 +-
 t/t4052-stat-output.sh                        |   2 +-
 t/t4057-diff-combined-paths.sh                |  16 +-
 t/t4105-apply-fuzz.sh                         |  10 +-
 t/t4106-apply-stdin.sh                        |   5 +-
 t/t4116-apply-reverse.sh                      |   4 +-
 t/t4117-apply-reject.sh                       |  20 +-
 t/t4118-apply-empty-context.sh                |   6 +-
 t/t4123-apply-shrink.sh                       |   4 +-
 t/t4124-apply-ws-rule.sh                      |  58 ++--
 t/t4125-apply-ws-fuzz.sh                      |   5 +-
 t/t4126-apply-empty.sh                        |   5 +-
 t/t4127-apply-same-fn.sh                      |   5 +-
 t/t4138-apply-ws-expansion.sh                 |  36 +-
 t/t4150-am.sh                                 |   2 +-
 t/t4151-am-abort.sh                           |  10 +-
 t/t4202-log.sh                                |  42 +--
 t/t4205-log-pretty-formats.sh                 |   2 +-
 t/t4211-line-log.sh                           |   2 +-
 t/t4212-log-corrupt.sh                        |   8 +-
 t/t4216-log-bloom.sh                          |   4 +-
 t/t5000-tar-tree.sh                           |   4 +-
 t/t5003-archive-zip.sh                        |   2 +-
 t/t5004-archive-corner-cases.sh               |   6 +-
 t/t5100-mailinfo.sh                           |   2 +-
 t/t5300-pack-object.sh                        |  18 +-
 t/t5302-pack-index.sh                         |   2 +-
 t/t5306-pack-nobase.sh                        |   2 +-
 t/t5307-pack-missing-commit.sh                |   2 +-
 t/t5310-pack-bitmaps.sh                       |   2 +-
 t/t5316-pack-delta-depth.sh                   |   7 +-
 t/t5317-pack-objects-filter-objects.sh        |  30 +-
 t/t5318-commit-graph.sh                       |   6 +-
 t/t5319-multi-pack-index.sh                   |  10 +-
 t/t5322-pack-objects-sparse.sh                |   4 +-
 t/t5325-reverse-index.sh                      |   2 +-
 t/t5500-fetch-pack.sh                         |   8 +-
 t/t5502-quickfetch.sh                         |   2 +-
 t/t5505-remote.sh                             |   6 +-
 t/t5510-fetch.sh                              |  14 +-
 t/t5515-fetch-merge-logic.sh                  |  38 +--
 t/t5516-fetch-push.sh                         |   5 +-
 t/t5552-skipping-fetch-negotiator.sh          |  10 +-
 t/t5562-http-backend-content-length.sh        |   2 +-
 t/t5570-git-daemon.sh                         |   2 +-
 t/t5571-pre-push-hook.sh                      |   6 +-
 t/t5611-clone-config.sh                       |   2 +-
 t/t5616-partial-clone.sh                      |  30 +-
 t/t5702-protocol-v2.sh                        |   4 +-
 t/t6005-rev-list-count.sh                     |   8 +-
 t/t6009-rev-list-parent.sh                    |   6 +-
 t/t6019-rev-list-ancestry-path.sh             |  10 +-
 t/t6060-merge-index.sh                        |   4 +-
 t/t6101-rev-parse-parents.sh                  |   2 +-
 t/t6112-rev-list-filters-objects.sh           |  22 +-
 t/t6120-describe.sh                           |  13 +-
 t/t6132-pathspec-exclude.sh                   |   2 +-
 t/t6200-fmt-merge-msg.sh                      |   2 +-
 t/t6300-for-each-ref.sh                       |   7 +-
 t/t6406-merge-attr.sh                         |   8 +-
 t/t6407-merge-binary.sh                       |   4 +-
 t/t6409-merge-subtree.sh                      |   6 +-
 t/t6411-merge-filemode.sh                     |   8 +-
 t/t6412-merge-large-rename.sh                 |  10 +-
 t/t6416-recursive-corner-cases.sh             |  30 +-
 t/t6417-merge-ours-theirs.sh                  |   5 +-
 t/t6430-merge-recursive.sh                    |   2 +-
 t/t6600-test-reach.sh                         |   4 +-
 t/t7004-tag.sh                                |   9 +-
 t/t7010-setup.sh                              |   2 +-
 t/t7110-reset-merge.sh                        |   2 +-
 t/t7501-commit-basic-functionality.sh         |   5 +-
 t/t7505-prepare-commit-msg-hook.sh            |   2 +-
 t/t7513-interpret-trailers.sh                 |   2 +-
 t/t7519-status-fsmonitor.sh                   |   2 +-
 t/t7600-merge.sh                              |   2 +-
 t/t7602-merge-octopus-many.sh                 |   4 +-
 t/t7603-merge-reduce-heads.sh                 |   4 +-
 t/t7700-repack.sh                             |   2 +-
 t/t7810-grep.sh                               | 310 +++++++++---------
 t/t8002-blame.sh                              |   2 +-
 t/t8003-blame-corner-cases.sh                 |  10 +-
 t/t8014-blame-ignore-fuzzy.sh                 |   4 +-
 t/t9104-git-svn-follow-parent.sh              |   4 +-
 t/t9107-git-svn-migrate.sh                    |   8 +-
 t/t9130-git-svn-authors-file.sh               |   6 +-
 t/t9134-git-svn-ignore-paths.sh               |  16 +-
 t/t9138-git-svn-authors-prog.sh               |   2 +-
 t/t9146-git-svn-empty-dirs.sh                 |   4 +-
 t/t9147-git-svn-include-paths.sh              |  16 +-
 t/t9152-svn-empty-dirs-after-gc.sh            |   2 +-
 t/t9304-fast-import-marks.sh                  |   2 +-
 t/t9400-git-cvsserver-server.sh               |  11 +-
 t/t9800-git-p4-basic.sh                       |   2 +-
 t/t9818-git-p4-block.sh                       |   6 +-
 t/t9902-completion.sh                         |   4 +-
 163 files changed, 740 insertions(+), 847 deletions(-)

-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH 01/19] t/lib-pager: use sane_unset() to avoid breaking &&-chain
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
@ 2021-12-09  5:10 ` Eric Sunshine
  2021-12-09  5:10 ` [PATCH 02/19] t1010: fix unnoticed failure on Windows Eric Sunshine
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:10 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

This test intentionally breaks the &&-chain following `unset` since it
doesn't know if `unset` will succeed or fail and doesn't want a local
`unset` failure to abort the test overall. We can do better by using
sane_unset() which can be linked into the &&-chain as usual.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/lib-pager.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/lib-pager.sh b/t/lib-pager.sh
index 3aa7a3ffd8..e5eb28df4e 100644
--- a/t/lib-pager.sh
+++ b/t/lib-pager.sh
@@ -3,7 +3,7 @@
 test_expect_success 'determine default pager' '
 	test_might_fail git config --unset core.pager &&
 	less=$(
-		unset PAGER GIT_PAGER;
+		sane_unset PAGER GIT_PAGER &&
 		git var GIT_PAGER
 	) &&
 	test -n "$less"
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 02/19] t1010: fix unnoticed failure on Windows
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
  2021-12-09  5:10 ` [PATCH 01/19] t/lib-pager: use sane_unset() to avoid breaking &&-chain Eric Sunshine
@ 2021-12-09  5:10 ` Eric Sunshine
  2021-12-09 16:27   ` Elijah Newren
  2021-12-09  5:10 ` [PATCH 03/19] t1020: avoid aborting entire test script when one test fails Eric Sunshine
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:10 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

On Microsoft Windows, a directory name should never end with a period.
Quoting from Microsoft documentation[1]:

    Do not end a file or directory name with a space or a period.
    Although the underlying file system may support such names, the
    Windows shell and user interface does not.

Naming a directory with a trailing period is indeed perilous:

    % git init foo
    % cd foo
    % mkdir a.
    % git status
    warning: could not open directory 'a./': No such file or directory

The t1010 "setup" test:

    for d in a a. a0
    do
        mkdir "$d" && echo "$d/one" >"$d/one" &&
        git add "$d"
    done &&

runs afoul of this Windows limitation, as can be observed when running
the test verbosely:

    error: open("a./one"): No such file or directory
    error: unable to index file 'a./one'
    fatal: adding files failed

The reason this problem has gone unnoticed for so long is twofold.
First, the failed `git add` is swallowed silently because the loop is
not terminated explicitly by `|| return 1` to signal the failure.
Second, none of the tests in this script care about the actual directory
names or even the number of tree entries. They care only that the tree
synthesized in the index and created by `git write-tree` matches the
tree created by the output of `git ls-tree` fed into `git mktree`, and
the failure of `git add "a./one"` doesn't change that outcome.

Skipping these tests on Windows by, for instance, checking the
FUNNYNAMES predicate would avoid the problem, however, the funny-looking
name is not what is being tested here. Rather, the tests are about
checking that `git mktree` produces stable results for various input
conditions, such as when the input order is not consistent or when an
object is missing.

Therefore, resolve the problem simply by using a directory name which is
legal on Windows (i.e. "a-" rather than "a."). While at it, add the
missing `|| return 1` to the loop body in order to catch this sort of
problem in the future.

[1]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t1010-mktree.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 48bfad07ab..3c08194526 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -6,10 +6,10 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
-	for d in a a. a0
+	for d in a a- a0
 	do
 		mkdir "$d" && echo "$d/one" >"$d/one" &&
-		git add "$d"
+		git add "$d" || return 1
 	done &&
 	echo zero >one &&
 	git update-index --add --info-only one &&
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 03/19] t1020: avoid aborting entire test script when one test fails
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
  2021-12-09  5:10 ` [PATCH 01/19] t/lib-pager: use sane_unset() to avoid breaking &&-chain Eric Sunshine
  2021-12-09  5:10 ` [PATCH 02/19] t1010: fix unnoticed failure on Windows Eric Sunshine
@ 2021-12-09  5:10 ` Eric Sunshine
  2021-12-09  5:11 ` [PATCH 04/19] t4202: clarify intent by creating expected content less cleverly Eric Sunshine
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:10 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Although `exit 1` is the proper way to signal a test failure from within
a subshell, its use outside any subshell should be avoided since it
aborts the entire script rather than aborting only the failed test.
Instead, a simple `return 1` is the proper idiom for signaling failure
outside a subshell since it aborts only the test in question, not the
entire script.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t1020-subdirectory.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index c2df75e495..da19c06fb5 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -22,7 +22,7 @@ test_expect_success 'update-index and ls-files' '
 	git update-index --add one &&
 	case "$(git ls-files)" in
 	one) echo pass one ;;
-	*) echo bad one; exit 1 ;;
+	*) echo bad one; return 1 ;;
 	esac &&
 	(
 		cd dir &&
@@ -34,7 +34,7 @@ test_expect_success 'update-index and ls-files' '
 	) &&
 	case "$(git ls-files)" in
 	dir/two"$LF"one) echo pass both ;;
-	*) echo bad; exit 1 ;;
+	*) echo bad; return 1 ;;
 	esac
 '
 
@@ -57,7 +57,7 @@ test_expect_success 'diff-files' '
 	echo d >>dir/two &&
 	case "$(git diff-files --name-only)" in
 	dir/two"$LF"one) echo pass top ;;
-	*) echo bad top; exit 1 ;;
+	*) echo bad top; return 1 ;;
 	esac &&
 	# diff should not omit leading paths
 	(
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 04/19] t4202: clarify intent by creating expected content less cleverly
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (2 preceding siblings ...)
  2021-12-09  5:10 ` [PATCH 03/19] t1020: avoid aborting entire test script when one test fails Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:09   ` Jeff King
  2021-12-09  5:11 ` [PATCH 05/19] t5516: drop unnecessary subshell and command invocation Eric Sunshine
                   ` (16 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Several tests assign the output of `$(...)` command substitution to an
"expect" variable, taking advantage of the fact that `$(...)` folds out
the final line terminator while leaving internal line terminators
intact. They do this because the "actual" string with which "expect"
will be compared is shaped the same way. However, this intent (having
internal line terminators, but no final line terminator) is not
necessarily obvious at first glance and may confuse casual readers. The
intent can be made more obvious by using `printf` instead, with which
line termination is stated clearly:

    printf "sixth\nthird"

In fact, many other tests in this script already use `printf` for
precisely this purpose, thus it is an established pattern. Therefore,
convert these tests to employ `printf`, as well.

While at it, modernize the tests to use test_cmp() to compare the
expected and actual output rather than using the semi-deprecated
`verbose test "$x" = "$y"`.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t4202-log.sh | 42 +++++++++++++++++++++---------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 7884e3d46b..c2cfbc69f7 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -120,48 +120,48 @@ test_expect_success 'diff-filter=A' '
 
 test_expect_success 'diff-filter=M' '
 
-	actual=$(git log --pretty="format:%s" --diff-filter=M HEAD) &&
-	expect=$(echo second) &&
-	verbose test "$actual" = "$expect"
+	git log --pretty="format:%s" --diff-filter=M HEAD >actual &&
+	printf "second" >expect &&
+	test_cmp expect actual
 
 '
 
 test_expect_success 'diff-filter=D' '
 
-	actual=$(git log --no-renames --pretty="format:%s" --diff-filter=D HEAD) &&
-	expect=$(echo sixth ; echo third) &&
-	verbose test "$actual" = "$expect"
+	git log --no-renames --pretty="format:%s" --diff-filter=D HEAD >actual &&
+	printf "sixth\nthird" >expect &&
+	test_cmp expect actual
 
 '
 
 test_expect_success 'diff-filter=R' '
 
-	actual=$(git log -M --pretty="format:%s" --diff-filter=R HEAD) &&
-	expect=$(echo third) &&
-	verbose test "$actual" = "$expect"
+	git log -M --pretty="format:%s" --diff-filter=R HEAD >actual &&
+	printf "third" >expect &&
+	test_cmp expect actual
 
 '
 
 test_expect_success 'diff-filter=C' '
 
-	actual=$(git log -C -C --pretty="format:%s" --diff-filter=C HEAD) &&
-	expect=$(echo fourth) &&
-	verbose test "$actual" = "$expect"
+	git log -C -C --pretty="format:%s" --diff-filter=C HEAD >actual &&
+	printf "fourth" >expect &&
+	test_cmp expect actual
 
 '
 
 test_expect_success 'git log --follow' '
 
-	actual=$(git log --follow --pretty="format:%s" ichi) &&
-	expect=$(echo third ; echo second ; echo initial) &&
-	verbose test "$actual" = "$expect"
+	git log --follow --pretty="format:%s" ichi >actual &&
+	printf "third\nsecond\ninitial" >expect &&
+	test_cmp expect actual
 '
 
 test_expect_success 'git config log.follow works like --follow' '
 	test_config log.follow true &&
-	actual=$(git log --pretty="format:%s" ichi) &&
-	expect=$(echo third ; echo second ; echo initial) &&
-	verbose test "$actual" = "$expect"
+	git log --pretty="format:%s" ichi >actual &&
+	printf "third\nsecond\ninitial" >expect &&
+	test_cmp expect actual
 '
 
 test_expect_success 'git config log.follow does not die with multiple paths' '
@@ -176,9 +176,9 @@ test_expect_success 'git config log.follow does not die with no paths' '
 
 test_expect_success 'git config log.follow is overridden by --no-follow' '
 	test_config log.follow true &&
-	actual=$(git log --no-follow --pretty="format:%s" ichi) &&
-	expect="third" &&
-	verbose test "$actual" = "$expect"
+	git log --no-follow --pretty="format:%s" ichi >actual &&
+	printf "third" >expect &&
+	test_cmp expect actual
 '
 
 # Note that these commits are intentionally listed out of order.
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 05/19] t5516: drop unnecessary subshell and command invocation
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (3 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 04/19] t4202: clarify intent by creating expected content less cleverly Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:10   ` Jeff King
  2021-12-09  5:11 ` [PATCH 06/19] t6300: make `%(raw:size) --shell` test more robust Eric Sunshine
                   ` (15 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

To create its "expect" file, this test pipes into `sort` the output of
`git for-each-ref` and a copy of that same output but with a minor
textual transformation applied. To do so, it employs a subshell and
commands `cat` and `sed` even though the same result can be accomplished
by `sed` alone (without a subshell).

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t5516-fetch-push.sh | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 8212ca56dc..d5e19b54af 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1316,10 +1316,7 @@ test_expect_success 'fetch follows tags by default' '
 		git pull ../testrepo main &&
 		git tag -m "annotated" tag &&
 		git for-each-ref >tmp1 &&
-		(
-			cat tmp1
-			sed -n "s|refs/heads/main$|refs/remotes/origin/main|p" tmp1
-		) |
+		sed -n "p; s|refs/heads/main$|refs/remotes/origin/main|p" tmp1 |
 		sort -k 3 >../expect
 	) &&
 	git init dst &&
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 06/19] t6300: make `%(raw:size) --shell` test more robust
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (4 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 05/19] t5516: drop unnecessary subshell and command invocation Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:14   ` Jeff King
  2021-12-09  5:11 ` [PATCH 07/19] t9107: use shell parameter expansion to avoid breaking &&-chain Eric Sunshine
                   ` (14 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

This test populates its `expect` file solely by appending content but
fails to ensure that the file starts out empty. The test succeeds only
because no earlier test populated a file of the exact same name, however
this is an accident waiting to happen. Make the test more robust by
ensuring that it contains exactly the intended content.

While at it, simplify the implementation via a straightforward `sed`
application and by avoiding dropping out of the single-quote context
within the test body (thus eliminating a hard-to-digest combination of
apostrophes and backslashes).

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---

Notes:
    An alternative simple fix would be to capture the output of the
    `while` loop itself rather than the output of `echo`:
    
        git for-each-ref ... | while read line
        do
            echo ...
        done >expect &&
    
    however, I prefer the conciseness of the `sed` approach,
    
    This patch makes no attempt to address `git` being upstream in a
    pipe. There are enough other such instances in this script that
    fixing them warrants a separate patch (if someone wants to tackle
    it).

 t/t6300-for-each-ref.sh | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 9f2c706c12..aae57908f8 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -955,10 +955,7 @@ test_expect_success '%(raw) with --shell and --sort=raw must fail' '
 '
 
 test_expect_success '%(raw:size) with --shell' '
-	git for-each-ref --format="%(raw:size)" | while read line
-	do
-		echo "'\''$line'\''" >>expect
-	done &&
+	git for-each-ref --format="%(raw:size)" | sed "s/^/$SQ/;s/$/$SQ/" >expect &&
 	git for-each-ref --format="%(raw:size)" --shell >actual &&
 	test_cmp expect actual
 '
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 07/19] t9107: use shell parameter expansion to avoid breaking &&-chain
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (5 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 06/19] t6300: make `%(raw:size) --shell` test more robust Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09  5:11 ` [PATCH 08/19] tests: simplify construction of large blocks of text Eric Sunshine
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

This test intentionally breaks the &&-chain when using `expr` to parse
"[<path>]:<ref>" since the pattern matching operation will return 1
(failure) when <path> is empty even though an empty <path> is legitimate
in this test and should not cause the test to fail. However, it is
possible to parse the input without breaking the &&-chain by using shell
parameter expansion (i.e. `${i%%...}`). Other ways to avoid the problem
would be `{ expr $i : ... ||:; }` or test_might_fail(), however,
parameter expansion seems simplest.

IMPLEMENTATION NOTE

The rewritten `if` expression:

    if test "$ref" = "${ref#refs/remotes/}"`; then continue; fi

is perhaps a bit subtle. At first glance, it looks like it will
`continue` the loop if $ref starts with "refs/remotes/", but in fact
it's the opposite: the loop will `continue` if $ref does not start with
"refs/remotes/".

In the original, `expr` would only match if the ref started with
"refs/remotes/", and $ref would end up empty if it didn't, so `test -z`
would `continue` the loop if the ref did not start with "refs/remotes/".

With parameter expansion, ${ref#refs/remotes/} attempts to strip
"refs/remotes/" from $ref. If it fails, meaning that $ref does not start
with "refs/remotes/", then the expansion will just be $ref unchanged,
and it will `continue` the loop. On the other hand, if stripping
succeeds, meaning that $ref begins with "refs/remotes/", then the
expansion will be the value of $ref with "refs/remotes/" removed, hence
`continue` will not be taken.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t9107-git-svn-migrate.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index ceaa5bad10..aa908bbc2f 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -98,10 +98,10 @@ test_expect_success 'migrate --minimize on old inited layout' '
 	rm -rf "$GIT_DIR"/svn &&
 	for i in $(cat fetch.out)
 	do
-		path=$(expr $i : "\([^:]*\):.*$")
-		ref=$(expr $i : "[^:]*:\(refs/remotes/.*\)$")
-		if test -z "$ref"; then continue; fi
-		if test -n "$path"; then path="/$path"; fi
+		path=${i%%:*} &&
+		ref=${i#*:} &&
+		if test "$ref" = "${ref#refs/remotes/}"; then continue; fi &&
+		if test -n "$path"; then path="/$path"; fi &&
 		mkdir -p "$GIT_DIR"/svn/$ref/info/ &&
 		echo "$svnrepo"$path >"$GIT_DIR"/svn/$ref/info/url ||
 		return 1
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 08/19] tests: simplify construction of large blocks of text
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (6 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 07/19] t9107: use shell parameter expansion to avoid breaking &&-chain Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09  5:11 ` [PATCH 09/19] tests: use test_write_lines() to generate line-oriented output Eric Sunshine
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Take advantage of here-docs to create large blocks of text rather than
using a series of `echo` statements. Not only are here-docs a natural
fit for such a task, but there is less opportunity for a broken
&&-chain.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t0021-conversion.sh        |  44 ++---
 t/t4106-apply-stdin.sh       |   5 +-
 t/t5510-fetch.sh             |  10 +-
 t/t5515-fetch-merge-logic.sh |  22 +--
 t/t6406-merge-attr.sh        |   8 +-
 t/t6411-merge-filemode.sh    |   8 +-
 t/t7810-grep.sh              | 310 +++++++++++++++++------------------
 7 files changed, 205 insertions(+), 202 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 33dfc9cd56..1a1a69ad92 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -118,17 +118,17 @@ test_expect_success check '
 # If an expanded ident ever gets into the repository, we want to make sure that
 # it is collapsed before being expanded again on checkout
 test_expect_success expanded_in_repo '
-	{
-		echo "File with expanded keywords"
-		echo "\$Id\$"
-		echo "\$Id:\$"
-		echo "\$Id: 0000000000000000000000000000000000000000 \$"
-		echo "\$Id: NoSpaceAtEnd\$"
-		echo "\$Id:NoSpaceAtFront \$"
-		echo "\$Id:NoSpaceAtEitherEnd\$"
-		echo "\$Id: NoTerminatingSymbol"
-		echo "\$Id: Foreign Commit With Spaces \$"
-	} >expanded-keywords.0 &&
+	cat >expanded-keywords.0 <<-\EOF &&
+	File with expanded keywords
+	$Id$
+	$Id:$
+	$Id: 0000000000000000000000000000000000000000 $
+	$Id: NoSpaceAtEnd$
+	$Id:NoSpaceAtFront $
+	$Id:NoSpaceAtEitherEnd$
+	$Id: NoTerminatingSymbol
+	$Id: Foreign Commit With Spaces $
+	EOF
 
 	{
 		cat expanded-keywords.0 &&
@@ -139,17 +139,17 @@ test_expect_success expanded_in_repo '
 	git commit -m "File with keywords expanded" &&
 	id=$(git rev-parse --verify :expanded-keywords) &&
 
-	{
-		echo "File with expanded keywords"
-		echo "\$Id: $id \$"
-		echo "\$Id: $id \$"
-		echo "\$Id: $id \$"
-		echo "\$Id: $id \$"
-		echo "\$Id: $id \$"
-		echo "\$Id: $id \$"
-		echo "\$Id: NoTerminatingSymbol"
-		echo "\$Id: Foreign Commit With Spaces \$"
-	} >expected-output.0 &&
+	cat >expected-output.0 <<-EOF &&
+	File with expanded keywords
+	\$Id: $id \$
+	\$Id: $id \$
+	\$Id: $id \$
+	\$Id: $id \$
+	\$Id: $id \$
+	\$Id: $id \$
+	\$Id: NoTerminatingSymbol
+	\$Id: Foreign Commit With Spaces \$
+	EOF
 	{
 		cat expected-output.0 &&
 		printf "\$Id: NoTerminatingSymbolAtEOF"
diff --git a/t/t4106-apply-stdin.sh b/t/t4106-apply-stdin.sh
index 72467a1e8e..1e70810b9c 100755
--- a/t/t4106-apply-stdin.sh
+++ b/t/t4106-apply-stdin.sh
@@ -18,7 +18,10 @@ test_expect_success 'git apply --numstat - < patch' '
 '
 
 test_expect_success 'git apply --numstat - < patch patch' '
-	for i in 1 2; do echo "1	1	text"; done >expect &&
+	cat >expect <<-\EOF &&
+	1	1	text
+	1	1	text
+	EOF
 	git apply --numstat - < patch patch >actual &&
 	test_cmp expect actual
 '
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index a0faf0dd94..1892d6615a 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -40,11 +40,11 @@ test_expect_success "clone and setup child repos" '
 		git config branch.main.remote two &&
 		git config branch.main.merge refs/heads/one &&
 		mkdir -p .git/remotes &&
-		{
-			echo "URL: ../two/.git/"
-			echo "Pull: refs/heads/main:refs/heads/two"
-			echo "Pull: refs/heads/one:refs/heads/one"
-		} >.git/remotes/two
+		cat >.git/remotes/two <<-\EOF
+		URL: ../two/.git/
+		Pull: refs/heads/main:refs/heads/two
+		Pull: refs/heads/one:refs/heads/one
+		EOF
 	) &&
 	git clone . bundle &&
 	git clone . seven
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index 50f14101c5..9d440e2821 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -105,19 +105,19 @@ test_expect_success setup '
 	remotes="$remotes config-glob" &&
 
 	mkdir -p .git/remotes &&
-	{
-		echo "URL: ../.git/"
-		echo "Pull: refs/heads/main:remotes/rem/main"
-		echo "Pull: refs/heads/one:remotes/rem/one"
-		echo "Pull: two:remotes/rem/two"
-		echo "Pull: refs/heads/three:remotes/rem/three"
-	} >.git/remotes/remote-explicit &&
+	cat >.git/remotes/remote-explicit <<-\EOF &&
+	URL: ../.git/
+	Pull: refs/heads/main:remotes/rem/main
+	Pull: refs/heads/one:remotes/rem/one
+	Pull: two:remotes/rem/two
+	Pull: refs/heads/three:remotes/rem/three
+	EOF
 	remotes="$remotes remote-explicit" &&
 
-	{
-		echo "URL: ../.git/"
-		echo "Pull: refs/heads/*:refs/remotes/rem/*"
-	} >.git/remotes/remote-glob &&
+	cat >.git/remotes/remote-glob <<-\EOF &&
+	URL: ../.git/
+	Pull: refs/heads/*:refs/remotes/rem/*
+	EOF
 	remotes="$remotes remote-glob" &&
 
 	mkdir -p .git/branches &&
diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh
index 8494645837..57e6af5eaa 100755
--- a/t/t6406-merge-attr.sh
+++ b/t/t6406-merge-attr.sh
@@ -62,10 +62,10 @@ test_expect_success setup '
 
 test_expect_success merge '
 
-	{
-		echo "binary -merge"
-		echo "union merge=union"
-	} >.gitattributes &&
+	cat >.gitattributes <<-\EOF &&
+	binary -merge
+	union merge=union
+	EOF
 
 	if git merge main
 	then
diff --git a/t/t6411-merge-filemode.sh b/t/t6411-merge-filemode.sh
index f54c915d6a..6ae2489286 100755
--- a/t/t6411-merge-filemode.sh
+++ b/t/t6411-merge-filemode.sh
@@ -51,10 +51,10 @@ test_expect_success 'set up mode change in both branches' '
 	: >file2 &&
 	git add file2 &&
 	git commit -m b2 &&
-	{
-		echo "100755 $H 2	file2"
-		echo "100644 $H 3	file2"
-	} >expect
+	cat >expect <<-EOF
+	100755 $H 2	file2
+	100644 $H 3	file2
+	EOF
 '
 
 do_both_modes () {
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 6b6423a07c..424c31c328 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -31,28 +31,28 @@ int main(int argc, const char **argv)
 EOF
 
 test_expect_success setup '
-	{
-		echo foo mmap bar
-		echo foo_mmap bar
-		echo foo_mmap bar mmap
-		echo foo mmap bar_mmap
-		echo foo_mmap bar mmap baz
-	} >file &&
-	{
-		echo Hello world
-		echo HeLLo world
-		echo Hello_world
-		echo HeLLo_world
-	} >hello_world &&
-	{
-		echo "a+b*c"
-		echo "a+bc"
-		echo "abc"
-	} >ab &&
-	{
-		echo d &&
-		echo 0
-	} >d0 &&
+	cat >file <<-\EOF &&
+	foo mmap bar
+	foo_mmap bar
+	foo_mmap bar mmap
+	foo mmap bar_mmap
+	foo_mmap bar mmap baz
+	EOF
+	cat >hello_world <<-\EOF &&
+	Hello world
+	HeLLo world
+	Hello_world
+	HeLLo_world
+	EOF
+	cat >ab <<-\EOF &&
+	a+b*c
+	a+bc
+	abc
+	EOF
+	cat >d0 <<-\EOF &&
+	d
+	0
+	EOF
 	echo vvv >v &&
 	echo ww w >w &&
 	echo x x xx x >x &&
@@ -63,13 +63,13 @@ test_expect_success setup '
 	echo vvv >t/v &&
 	mkdir t/a &&
 	echo vvv >t/a/v &&
-	{
-		echo "line without leading space1"
-		echo " line with leading space1"
-		echo " line with leading space2"
-		echo " line with leading space3"
-		echo "line without leading space2"
-	} >space &&
+	qz_to_tab_space >space <<-\EOF &&
+	line without leading space1
+	Zline with leading space1
+	Zline with leading space2
+	Zline with leading space3
+	line without leading space2
+	EOF
 	cat >hello.ps1 <<-\EOF &&
 	# No-op.
 	function dummy() {}
@@ -106,129 +106,129 @@ do
 	esac
 
 	test_expect_success "grep -w $L" '
-		{
-			echo ${HC}file:1:foo mmap bar
-			echo ${HC}file:3:foo_mmap bar mmap
-			echo ${HC}file:4:foo mmap bar_mmap
-			echo ${HC}file:5:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:1:foo mmap bar
+		${HC}file:3:foo_mmap bar mmap
+		${HC}file:4:foo mmap bar_mmap
+		${HC}file:5:foo_mmap bar mmap baz
+		EOF
 		git -c grep.linenumber=false grep -n -w -e mmap $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L (with --column)" '
-		{
-			echo ${HC}file:5:foo mmap bar
-			echo ${HC}file:14:foo_mmap bar mmap
-			echo ${HC}file:5:foo mmap bar_mmap
-			echo ${HC}file:14:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:5:foo mmap bar
+		${HC}file:14:foo_mmap bar mmap
+		${HC}file:5:foo mmap bar_mmap
+		${HC}file:14:foo_mmap bar mmap baz
+		EOF
 		git grep --column -w -e mmap $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L (with --column, extended OR)" '
-		{
-			echo ${HC}file:14:foo_mmap bar mmap
-			echo ${HC}file:19:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:14:foo_mmap bar mmap
+		${HC}file:19:foo_mmap bar mmap baz
+		EOF
 		git grep --column -w -e mmap$ --or -e baz $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L (with --column, --invert-match)" '
-		{
-			echo ${HC}file:1:foo mmap bar
-			echo ${HC}file:1:foo_mmap bar
-			echo ${HC}file:1:foo_mmap bar mmap
-			echo ${HC}file:1:foo mmap bar_mmap
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:1:foo mmap bar
+		${HC}file:1:foo_mmap bar
+		${HC}file:1:foo_mmap bar mmap
+		${HC}file:1:foo mmap bar_mmap
+		EOF
 		git grep --column --invert-match -w -e baz $H -- file >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep $L (with --column, --invert-match, extended OR)" '
-		{
-			echo ${HC}hello_world:6:HeLLo_world
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}hello_world:6:HeLLo_world
+		EOF
 		git grep --column --invert-match -e ll --or --not -e _ $H -- hello_world \
 			>actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep $L (with --column, --invert-match, extended AND)" '
-		{
-			echo ${HC}hello_world:3:Hello world
-			echo ${HC}hello_world:3:Hello_world
-			echo ${HC}hello_world:6:HeLLo_world
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}hello_world:3:Hello world
+		${HC}hello_world:3:Hello_world
+		${HC}hello_world:6:HeLLo_world
+		EOF
 		git grep --column --invert-match --not -e _ --and --not -e ll $H -- hello_world \
 			>actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep $L (with --column, double-negation)" '
-		{
-			echo ${HC}file:1:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:1:foo_mmap bar mmap baz
+		EOF
 		git grep --column --not \( --not -e foo --or --not -e baz \) $H -- file \
 			>actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L (with --column, -C)" '
-		{
-			echo ${HC}file:5:foo mmap bar
-			echo ${HC}file-foo_mmap bar
-			echo ${HC}file:14:foo_mmap bar mmap
-			echo ${HC}file:5:foo mmap bar_mmap
-			echo ${HC}file:14:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:5:foo mmap bar
+		${HC}file-foo_mmap bar
+		${HC}file:14:foo_mmap bar mmap
+		${HC}file:5:foo mmap bar_mmap
+		${HC}file:14:foo_mmap bar mmap baz
+		EOF
 		git grep --column -w -C1 -e mmap $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L (with --line-number, --column)" '
-		{
-			echo ${HC}file:1:5:foo mmap bar
-			echo ${HC}file:3:14:foo_mmap bar mmap
-			echo ${HC}file:4:5:foo mmap bar_mmap
-			echo ${HC}file:5:14:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:1:5:foo mmap bar
+		${HC}file:3:14:foo_mmap bar mmap
+		${HC}file:4:5:foo mmap bar_mmap
+		${HC}file:5:14:foo_mmap bar mmap baz
+		EOF
 		git grep -n --column -w -e mmap $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L (with non-extended patterns, --column)" '
-		{
-			echo ${HC}file:5:foo mmap bar
-			echo ${HC}file:10:foo_mmap bar
-			echo ${HC}file:10:foo_mmap bar mmap
-			echo ${HC}file:5:foo mmap bar_mmap
-			echo ${HC}file:10:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:5:foo mmap bar
+		${HC}file:10:foo_mmap bar
+		${HC}file:10:foo_mmap bar mmap
+		${HC}file:5:foo mmap bar_mmap
+		${HC}file:10:foo_mmap bar mmap baz
+		EOF
 		git grep --column -w -e bar -e mmap $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L" '
-		{
-			echo ${HC}file:1:foo mmap bar
-			echo ${HC}file:3:foo_mmap bar mmap
-			echo ${HC}file:4:foo mmap bar_mmap
-			echo ${HC}file:5:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:1:foo mmap bar
+		${HC}file:3:foo_mmap bar mmap
+		${HC}file:4:foo mmap bar_mmap
+		${HC}file:5:foo_mmap bar mmap baz
+		EOF
 		git -c grep.linenumber=true grep -w -e mmap $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L" '
-		{
-			echo ${HC}file:foo mmap bar
-			echo ${HC}file:foo_mmap bar mmap
-			echo ${HC}file:foo mmap bar_mmap
-			echo ${HC}file:foo_mmap bar mmap baz
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:foo mmap bar
+		${HC}file:foo_mmap bar mmap
+		${HC}file:foo mmap bar_mmap
+		${HC}file:foo_mmap bar mmap baz
+		EOF
 		git -c grep.linenumber=true grep --no-line-number -w -e mmap $H >actual &&
 		test_cmp expected actual
 	'
@@ -239,17 +239,17 @@ do
 	'
 
 	test_expect_success "grep -w $L (x)" '
-		{
-			echo ${HC}x:1:x x xx x
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}x:1:x x xx x
+		EOF
 		git grep -n -w -e "x xx* x" $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep -w $L (y-1)" '
-		{
-			echo ${HC}y:1:y yy
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}y:1:y yy
+		EOF
 		git grep -n -w -e "^y" $H >actual &&
 		test_cmp expected actual
 	'
@@ -277,16 +277,16 @@ do
 	'
 
 	test_expect_success "grep $L (with --column, --only-matching)" '
-		{
-			echo ${HC}file:1:5:mmap
-			echo ${HC}file:2:5:mmap
-			echo ${HC}file:3:5:mmap
-			echo ${HC}file:3:13:mmap
-			echo ${HC}file:4:5:mmap
-			echo ${HC}file:4:13:mmap
-			echo ${HC}file:5:5:mmap
-			echo ${HC}file:5:13:mmap
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}file:1:5:mmap
+		${HC}file:2:5:mmap
+		${HC}file:3:5:mmap
+		${HC}file:3:13:mmap
+		${HC}file:4:5:mmap
+		${HC}file:4:13:mmap
+		${HC}file:5:5:mmap
+		${HC}file:5:13:mmap
+		EOF
 		git grep --column -n -o -e mmap $H >actual &&
 		test_cmp expected actual
 	'
@@ -320,11 +320,11 @@ do
 	'
 
 	test_expect_success "grep --max-depth -1 $L" '
-		{
-			echo ${HC}t/a/v:1:vvv
-			echo ${HC}t/v:1:vvv
-			echo ${HC}v:1:vvv
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}t/a/v:1:vvv
+		${HC}t/v:1:vvv
+		${HC}v:1:vvv
+		EOF
 		git grep --max-depth -1 -n -e vvv $H >actual &&
 		test_cmp expected actual &&
 		git grep --recursive -n -e vvv $H >actual &&
@@ -332,9 +332,9 @@ do
 	'
 
 	test_expect_success "grep --max-depth 0 $L" '
-		{
-			echo ${HC}v:1:vvv
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}v:1:vvv
+		EOF
 		git grep --max-depth 0 -n -e vvv $H >actual &&
 		test_cmp expected actual &&
 		git grep --no-recursive -n -e vvv $H >actual &&
@@ -342,11 +342,11 @@ do
 	'
 
 	test_expect_success "grep --max-depth 0 -- '*' $L" '
-		{
-			echo ${HC}t/a/v:1:vvv
-			echo ${HC}t/v:1:vvv
-			echo ${HC}v:1:vvv
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}t/a/v:1:vvv
+		${HC}t/v:1:vvv
+		${HC}v:1:vvv
+		EOF
 		git grep --max-depth 0 -n -e vvv $H -- "*" >actual &&
 		test_cmp expected actual &&
 		git grep --no-recursive -n -e vvv $H -- "*" >actual &&
@@ -354,18 +354,18 @@ do
 	'
 
 	test_expect_success "grep --max-depth 1 $L" '
-		{
-			echo ${HC}t/v:1:vvv
-			echo ${HC}v:1:vvv
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}t/v:1:vvv
+		${HC}v:1:vvv
+		EOF
 		git grep --max-depth 1 -n -e vvv $H >actual &&
 		test_cmp expected actual
 	'
 
 	test_expect_success "grep --max-depth 0 -- t $L" '
-		{
-			echo ${HC}t/v:1:vvv
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}t/v:1:vvv
+		EOF
 		git grep --max-depth 0 -n -e vvv $H -- t >actual &&
 		test_cmp expected actual &&
 		git grep --no-recursive -n -e vvv $H -- t >actual &&
@@ -373,10 +373,10 @@ do
 	'
 
 	test_expect_success "grep --max-depth 0 -- . t $L" '
-		{
-			echo ${HC}t/v:1:vvv
-			echo ${HC}v:1:vvv
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}t/v:1:vvv
+		${HC}v:1:vvv
+		EOF
 		git grep --max-depth 0 -n -e vvv $H -- . t >actual &&
 		test_cmp expected actual &&
 		git grep --no-recursive -n -e vvv $H -- . t >actual &&
@@ -384,10 +384,10 @@ do
 	'
 
 	test_expect_success "grep --max-depth 0 -- t . $L" '
-		{
-			echo ${HC}t/v:1:vvv
-			echo ${HC}v:1:vvv
-		} >expected &&
+		cat >expected <<-EOF &&
+		${HC}t/v:1:vvv
+		${HC}v:1:vvv
+		EOF
 		git grep --max-depth 0 -n -e vvv $H -- t . >actual &&
 		test_cmp expected actual &&
 		git grep --no-recursive -n -e vvv $H -- t . >actual &&
@@ -1314,10 +1314,10 @@ test_expect_success PCRE 'grep -P pattern with grep.extendedRegexp=true' '
 '
 
 test_expect_success PCRE 'grep -P -v pattern' '
-	{
-		echo "ab:a+b*c"
-		echo "ab:a+bc"
-	} >expected &&
+	cat >expected <<-\EOF &&
+	ab:a+b*c
+	ab:a+bc
+	EOF
 	git grep -P -v "abc" ab >actual &&
 	test_cmp expected actual
 '
@@ -1331,10 +1331,10 @@ test_expect_success PCRE 'grep -P -i pattern' '
 '
 
 test_expect_success PCRE 'grep -P -w pattern' '
-	{
-		echo "hello_world:Hello world"
-		echo "hello_world:HeLLo world"
-	} >expected &&
+	cat >expected <<-\EOF &&
+	hello_world:Hello world
+	hello_world:HeLLo world
+	EOF
 	git grep -P -w "He((?i)ll)o" hello_world >actual &&
 	test_cmp expected actual
 '
@@ -1469,10 +1469,10 @@ test_expect_success 'grep -F pattern with grep.patternType=basic' '
 '
 
 test_expect_success 'grep -G pattern with grep.patternType=fixed' '
-	{
-		echo "ab:a+b*c"
-		echo "ab:a+bc"
-	} >expected &&
+	cat >expected <<-\EOF &&
+	ab:a+b*c
+	ab:a+bc
+	EOF
 	git \
 		-c grep.patterntype=fixed \
 		grep -G "a+b" ab >actual &&
@@ -1480,11 +1480,11 @@ test_expect_success 'grep -G pattern with grep.patternType=fixed' '
 '
 
 test_expect_success 'grep -E pattern with grep.patternType=fixed' '
-	{
-		echo "ab:a+b*c"
-		echo "ab:a+bc"
-		echo "ab:abc"
-	} >expected &&
+	cat >expected <<-\EOF &&
+	ab:a+b*c
+	ab:a+bc
+	ab:abc
+	EOF
 	git \
 		-c grep.patterntype=fixed \
 		grep -E "a+" ab >actual &&
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 09/19] tests: use test_write_lines() to generate line-oriented output
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (7 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 08/19] tests: simplify construction of large blocks of text Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:22   ` Jeff King
  2021-12-09  5:11 ` [PATCH 10/19] tests: fix broken &&-chains in compound statements Eric Sunshine
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Take advantage of test_write_lines() to generate line-oriented output
rather than using for-loops or a series of `echo` commands. Not only is
test_write_lines() a natural fit for such a task, but there is less
opportunity for a broken &&-chain.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t0020-crlf.sh                        | 28 ++++++-------
 t/t0026-eol-config.sh                  |  4 +-
 t/t1020-subdirectory.sh                |  4 +-
 t/t1512-rev-parse-disambiguation.sh    | 10 +----
 t/t2103-update-index-ignore-missing.sh |  2 +-
 t/t3417-rebase-whitespace-fix.sh       |  4 +-
 t/t4013-diff-various.sh                | 22 +++++-----
 t/t4014-format-patch.sh                | 26 ++++++------
 t/t4019-diff-wserror.sh                |  4 +-
 t/t4105-apply-fuzz.sh                  | 10 +----
 t/t4116-apply-reverse.sh               |  4 +-
 t/t4117-apply-reject.sh                | 20 ++-------
 t/t4118-apply-empty-context.sh         |  6 +--
 t/t4124-apply-ws-rule.sh               | 56 +++++++++++++-------------
 t/t4126-apply-empty.sh                 |  5 +--
 t/t4127-apply-same-fn.sh               |  5 +--
 t/t4151-am-abort.sh                    | 10 +----
 t/t5300-pack-object.sh                 | 12 +-----
 t/t5306-pack-nobase.sh                 |  2 +-
 t/t5611-clone-config.sh                |  2 +-
 t/t6019-rev-list-ancestry-path.sh      | 10 ++---
 t/t6060-merge-index.sh                 |  4 +-
 t/t6409-merge-subtree.sh               |  6 +--
 t/t6417-merge-ours-theirs.sh           |  5 +--
 t/t7501-commit-basic-functionality.sh  |  5 +--
 t/t8003-blame-corner-cases.sh          | 10 +----
 26 files changed, 106 insertions(+), 170 deletions(-)

diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index f25ae8b5e1..0bd6ff21c8 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -22,10 +22,10 @@ test_expect_success setup '
 
 	git config core.autocrlf false &&
 
-	for w in Hello world how are you; do echo $w; done >one &&
+	test_write_lines Hello world how are you >one &&
 	mkdir dir &&
-	for w in I am very very fine thank you; do echo $w; done >dir/two &&
-	for w in Oh here is NULQin text here; do echo $w; done | q_to_nul >three &&
+	test_write_lines I am very very fine thank you >dir/two &&
+	test_write_lines Oh here is NULQin text here | q_to_nul >three &&
 	git add . &&
 
 	git commit -m initial &&
@@ -35,7 +35,7 @@ test_expect_success setup '
 	two=$(git rev-parse HEAD:dir/two) &&
 	three=$(git rev-parse HEAD:three) &&
 
-	for w in Some extra lines here; do echo $w; done >>one &&
+	test_write_lines Some extra lines here >>one &&
 	git diff >patch.file &&
 	patched=$(git hash-object --stdin <one) &&
 	git read-tree --reset -u HEAD
@@ -46,7 +46,7 @@ test_expect_success 'safecrlf: autocrlf=input, all CRLF' '
 	git config core.autocrlf input &&
 	git config core.safecrlf true &&
 
-	for w in I am all CRLF; do echo $w; done | append_cr >allcrlf &&
+	test_write_lines I am all CRLF | append_cr >allcrlf &&
 	test_must_fail git add allcrlf
 '
 
@@ -55,7 +55,7 @@ test_expect_success 'safecrlf: autocrlf=input, mixed LF/CRLF' '
 	git config core.autocrlf input &&
 	git config core.safecrlf true &&
 
-	for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >mixed &&
+	test_write_lines Oh here is CRLFQ in text | q_to_cr >mixed &&
 	test_must_fail git add mixed
 '
 
@@ -64,7 +64,7 @@ test_expect_success 'safecrlf: autocrlf=true, all LF' '
 	git config core.autocrlf true &&
 	git config core.safecrlf true &&
 
-	for w in I am all LF; do echo $w; done >alllf &&
+	test_write_lines I am all LF >alllf &&
 	test_must_fail git add alllf
 '
 
@@ -73,7 +73,7 @@ test_expect_success 'safecrlf: autocrlf=true mixed LF/CRLF' '
 	git config core.autocrlf true &&
 	git config core.safecrlf true &&
 
-	for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >mixed &&
+	test_write_lines Oh here is CRLFQ in text | q_to_cr >mixed &&
 	test_must_fail git add mixed
 '
 
@@ -82,10 +82,10 @@ test_expect_success 'safecrlf: print warning only once' '
 	git config core.autocrlf input &&
 	git config core.safecrlf warn &&
 
-	for w in I am all LF; do echo $w; done >doublewarn &&
+	test_write_lines I am all LF >doublewarn &&
 	git add doublewarn &&
 	git commit -m "nowarn" &&
-	for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >doublewarn &&
+	test_write_lines Oh here is CRLFQ in text | q_to_cr >doublewarn &&
 	git add doublewarn 2>err &&
 	grep "CRLF will be replaced by LF" err >err.warnings &&
 	test_line_count = 1 err.warnings
@@ -103,7 +103,7 @@ test_expect_success 'safecrlf: no warning with safecrlf=false' '
 	git config core.autocrlf input &&
 	git config core.safecrlf false &&
 
-	for w in I am all CRLF; do echo $w; done | append_cr >allcrlf &&
+	test_write_lines I am all CRLF | append_cr >allcrlf &&
 	git add allcrlf 2>err &&
 	test_must_be_empty err
 '
@@ -351,9 +351,9 @@ test_expect_success 'setting up for new autocrlf tests' '
 	git config core.autocrlf false &&
 	git config core.safecrlf false &&
 	rm -rf .????* * &&
-	for w in I am all LF; do echo $w; done >alllf &&
-	for w in Oh here is CRLFQ in text; do echo $w; done | q_to_cr >mixed &&
-	for w in I am all CRLF; do echo $w; done | append_cr >allcrlf &&
+	test_write_lines I am all LF >alllf &&
+	test_write_lines Oh here is CRLFQ in text | q_to_cr >mixed &&
+	test_write_lines I am all CRLF | append_cr >allcrlf &&
 	git add -A . &&
 	git commit -m "alllf, allcrlf and mixed only" &&
 	git tag -a -m "message" autocrlf-checkpoint
diff --git a/t/t0026-eol-config.sh b/t/t0026-eol-config.sh
index cdcafcdff7..f426a185bb 100755
--- a/t/t0026-eol-config.sh
+++ b/t/t0026-eol-config.sh
@@ -15,8 +15,8 @@ test_expect_success setup '
 
 	echo "one text" > .gitattributes &&
 
-	for w in Hello world how are you; do echo $w; done >one &&
-	for w in I am very very fine thank you; do echo $w; done >two &&
+	test_write_lines Hello world how are you >one &&
+	test_write_lines I am very very fine thank you >two &&
 	git add . &&
 
 	git commit -m initial &&
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index da19c06fb5..9fdbb2af80 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -11,9 +11,9 @@ test_description='Try various core-level commands in subdirectory.
 
 test_expect_success setup '
 	long="a b c d e f g h i j k l m n o p q r s t u v w x y z" &&
-	for c in $long; do echo $c; done >one &&
+	test_write_lines $long >one &&
 	mkdir dir &&
-	for c in x y z $long a b c; do echo $c; done >dir/two &&
+	test_write_lines x y z $long a b c >dir/two &&
 	cp one original.one &&
 	cp dir/two original.two
 '
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index 7891a6becf..15188a408b 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -34,10 +34,7 @@ fi
 test_expect_success 'blob and tree' '
 	test_tick &&
 	(
-		for i in 0 1 2 3 4 5 6 7 8 9
-		do
-			echo $i
-		done &&
+		test_write_lines 0 1 2 3 4 5 6 7 8 9 &&
 		echo &&
 		echo b1rwzyc3
 	) >a0blgqsjc &&
@@ -204,10 +201,7 @@ test_expect_success 'more history' '
 	git checkout v1.0.0^0 &&
 	git mv a0blgqsjc f5518nwu &&
 
-	for i in h62xsjeu j08bekfvt kg7xflhm
-	do
-		echo $i
-	done >>f5518nwu &&
+	test_write_lines h62xsjeu j08bekfvt kg7xflhm >>f5518nwu &&
 	git add f5518nwu &&
 
 	test_tick &&
diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh
index 0114f05228..6938ecca86 100755
--- a/t/t2103-update-index-ignore-missing.sh
+++ b/t/t2103-update-index-ignore-missing.sh
@@ -23,7 +23,7 @@ test_expect_success basics '
 	test_cmp expect actual &&
 
 	git update-index --add one two three &&
-	for i in one three two; do echo $i; done >expect &&
+	test_write_lines one three two >expect &&
 	git ls-files >actual &&
 	test_cmp expect actual &&
 
diff --git a/t/t3417-rebase-whitespace-fix.sh b/t/t3417-rebase-whitespace-fix.sh
index 946e92f8da..96f2cf22fa 100755
--- a/t/t3417-rebase-whitespace-fix.sh
+++ b/t/t3417-rebase-whitespace-fix.sh
@@ -115,9 +115,7 @@ test_expect_success 'at beginning of file' '
 	git config core.whitespace "blank-at-eol" &&
 	cp beginning file &&
 	git commit -m beginning file &&
-	for i in 1 2 3 4 5; do
-		echo $i
-	done >> file &&
+	test_write_lines 1 2 3 4 5 >>file &&
 	git commit -m more file &&
 	git rebase --whitespace=fix HEAD^^ &&
 	test_cmp expect-beginning file
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 28683d059d..750aee17ea 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -19,8 +19,8 @@ test_expect_success setup '
 
 	mkdir dir &&
 	mkdir dir2 &&
-	for i in 1 2 3; do echo $i; done >file0 &&
-	for i in A B; do echo $i; done >dir/sub &&
+	test_write_lines 1 2 3 >file0 &&
+	test_write_lines A B >dir/sub &&
 	cat file0 >file2 &&
 	git add file0 file2 dir/sub &&
 	git commit -m Initial &&
@@ -32,8 +32,8 @@ test_expect_success setup '
 	GIT_COMMITTER_DATE="2006-06-26 00:01:00 +0000" &&
 	export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
 
-	for i in 4 5 6; do echo $i; done >>file0 &&
-	for i in C D; do echo $i; done >>dir/sub &&
+	test_write_lines 4 5 6 >>file0 &&
+	test_write_lines C D >>dir/sub &&
 	rm -f file2 &&
 	git update-index --remove file0 file2 dir/sub &&
 	git commit -m "Second${LF}${LF}This is the second commit." &&
@@ -42,9 +42,9 @@ test_expect_success setup '
 	GIT_COMMITTER_DATE="2006-06-26 00:02:00 +0000" &&
 	export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
 
-	for i in A B C; do echo $i; done >file1 &&
+	test_write_lines A B C >file1 &&
 	git add file1 &&
-	for i in E F; do echo $i; done >>dir/sub &&
+	test_write_lines E F >>dir/sub &&
 	git update-index dir/sub &&
 	git commit -m Third &&
 
@@ -53,8 +53,8 @@ test_expect_success setup '
 	export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
 
 	git checkout side &&
-	for i in A B C; do echo $i; done >>file0 &&
-	for i in 1 2; do echo $i; done >>dir/sub &&
+	test_write_lines A B C >>file0 &&
+	test_write_lines 1 2 >>dir/sub &&
 	cat dir/sub >file3 &&
 	git add file3 &&
 	git update-index file0 dir/sub &&
@@ -71,8 +71,8 @@ test_expect_success setup '
 	GIT_COMMITTER_DATE="2006-06-26 00:05:00 +0000" &&
 	export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
 
-	for i in A B C; do echo $i; done >>file0 &&
-	for i in 1 2; do echo $i; done >>dir/sub &&
+	test_write_lines A B C >>file0 &&
+	test_write_lines 1 2 >>dir/sub &&
 	git update-index file0 dir/sub &&
 
 	mkdir dir3 &&
@@ -86,7 +86,7 @@ test_expect_success setup '
 	GIT_COMMITTER_DATE="2006-06-26 00:06:00 +0000" &&
 	export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
 	git checkout -b rearrange initial &&
-	for i in B A; do echo $i; done >dir/sub &&
+	test_write_lines B A >dir/sub &&
 	git add dir/sub &&
 	git commit -m "Rearranged lines in dir/sub" &&
 	git checkout master &&
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 712d4b5ddf..eefe815fca 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -12,25 +12,25 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
 test_expect_success setup '
-	for i in 1 2 3 4 5 6 7 8 9 10; do echo "$i"; done >file &&
+	test_write_lines 1 2 3 4 5 6 7 8 9 10 >file &&
 	cat file >elif &&
 	git add file elif &&
 	test_tick &&
 	git commit -m Initial &&
 	git checkout -b side &&
 
-	for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
+	test_write_lines 1 2 5 6 A B C 7 8 9 10 >file &&
 	test_chmod +x elif &&
 	test_tick &&
 	git commit -m "Side changes #1" &&
 
-	for i in D E F; do echo "$i"; done >>file &&
+	test_write_lines D E F >>file &&
 	git update-index file &&
 	test_tick &&
 	git commit -m "Side changes #2" &&
 	git tag C2 &&
 
-	for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file &&
+	test_write_lines 5 6 1 2 3 A 4 B C 7 8 9 10 D E F >file &&
 	git update-index file &&
 	test_tick &&
 	git commit -m "Side changes #3 with \\n backslash-n in it." &&
@@ -43,18 +43,18 @@ test_expect_success setup '
 
 	git checkout side &&
 	git checkout -b patchid &&
-	for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file2 &&
-	for i in 1 2 3 A 4 B C 7 8 9 10 D E F 5 6; do echo "$i"; done >file3 &&
-	for i in 8 9 10; do echo "$i"; done >file &&
+	test_write_lines 5 6 1 2 3 A 4 B C 7 8 9 10 D E F >file2 &&
+	test_write_lines 1 2 3 A 4 B C 7 8 9 10 D E F 5 6 >file3 &&
+	test_write_lines 8 9 10 >file &&
 	git add file file2 file3 &&
 	test_tick &&
 	git commit -m "patchid 1" &&
-	for i in 4 A B 7 8 9 10; do echo "$i"; done >file2 &&
-	for i in 8 9 10 5 6; do echo "$i"; done >file3 &&
+	test_write_lines 4 A B 7 8 9 10 >file2 &&
+	test_write_lines 8 9 10 5 6 >file3 &&
 	git add file2 file3 &&
 	test_tick &&
 	git commit -m "patchid 2" &&
-	for i in 10 5 6; do echo "$i"; done >file &&
+	test_write_lines 10 5 6 >file &&
 	git add file &&
 	test_tick &&
 	git commit -m "patchid 3" &&
@@ -653,7 +653,7 @@ test_expect_success 'excessive subject' '
 	git checkout side &&
 	before=$(git hash-object file) &&
 	before=$(git rev-parse --short $before) &&
-	for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
+	test_write_lines 5 6 1 2 3 A 4 B C 7 8 9 10 D E F >>file &&
 	after=$(git hash-object file) &&
 	after=$(git rev-parse --short $after) &&
 	git update-index file &&
@@ -1086,7 +1086,7 @@ test_expect_success TTY 'format-patch --stdout paginates' '
 test_expect_success 'format-patch handles multi-line subjects' '
 	rm -rf patches/ &&
 	echo content >>file &&
-	for i in one two three; do echo $i; done >msg &&
+	test_write_lines one two three >msg &&
 	git add file &&
 	git commit -F msg &&
 	git format-patch -o patches -1 &&
@@ -1098,7 +1098,7 @@ test_expect_success 'format-patch handles multi-line subjects' '
 test_expect_success 'format-patch handles multi-line encoded subjects' '
 	rm -rf patches/ &&
 	echo content >>file &&
-	for i in en två tre; do echo $i; done >msg &&
+	test_write_lines en två tre >msg &&
 	git add file &&
 	git commit -F msg &&
 	git format-patch -o patches -1 &&
diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh
index c68729ac09..d2b3109c2d 100755
--- a/t/t4019-diff-wserror.sh
+++ b/t/t4019-diff-wserror.sh
@@ -287,9 +287,9 @@ test_expect_success 'do not color trailing cr in context' '
 '
 
 test_expect_success 'color new trailing blank lines' '
-	{ echo a; echo b; echo; echo; } >x &&
+	test_write_lines a b "" "" >x &&
 	git add x &&
-	{ echo a; echo; echo; echo; echo c; echo; echo; echo; echo; } >x &&
+	test_write_lines a "" "" "" c "" "" "" "" >x &&
 	git diff --color x >output &&
 	cnt=$($grep_a "${blue_grep}" output | wc -l) &&
 	test $cnt = 2
diff --git a/t/t4105-apply-fuzz.sh b/t/t4105-apply-fuzz.sh
index 3266e39400..b80ec20801 100755
--- a/t/t4105-apply-fuzz.sh
+++ b/t/t4105-apply-fuzz.sh
@@ -15,15 +15,9 @@ dotest () {
 
 test_expect_success setup '
 
-	for i in 1 2 3 4 5 6 7 8 9 10 11 12
-	do
-		echo $i
-	done >file &&
+	test_write_lines 1 2 3 4 5 6 7 8 9 10 11 12 >file &&
 	git update-index --add file &&
-	for i in 1 2 3 4 5 6 7 a b c d e 8 9 10 11 12
-	do
-		echo $i
-	done >file &&
+	test_write_lines 1 2 3 4 5 6 7 a b c d e 8 9 10 11 12 >file &&
 	cat file >expect &&
 	git diff >O0.diff &&
 
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
index b99e65c086..fa3fa44e51 100755
--- a/t/t4116-apply-reverse.sh
+++ b/t/t4116-apply-reverse.sh
@@ -11,14 +11,14 @@ test_description='git apply in reverse
 
 test_expect_success setup '
 
-	for i in a b c d e f g h i j k l m n; do echo $i; done >file1 &&
+	test_write_lines a b c d e f g h i j k l m n >file1 &&
 	perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 &&
 
 	git add file1 file2 &&
 	git commit -m initial &&
 	git tag initial &&
 
-	for i in a b c g h i J K L m o n p q; do echo $i; done >file1 &&
+	test_write_lines a b c g h i J K L m o n p q >file1 &&
 	perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 &&
 
 	git commit -a -m second &&
diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh
index 0ee93fe845..c86d05a96f 100755
--- a/t/t4117-apply-reject.sh
+++ b/t/t4117-apply-reject.sh
@@ -10,25 +10,16 @@ test_description='git apply with rejects
 . ./test-lib.sh
 
 test_expect_success setup '
-	for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
-	do
-		echo $i
-	done >file1 &&
+	test_write_lines 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 >file1 &&
 	cat file1 >saved.file1 &&
 	git update-index --add file1 &&
 	git commit -m initial &&
 
-	for i in 1 2 A B 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 D 21
-	do
-		echo $i
-	done >file1 &&
+	test_write_lines 1 2 A B 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 D 21 >file1 &&
 	git diff >patch.1 &&
 	cat file1 >clean &&
 
-	for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21
-	do
-		echo $i
-	done >expected &&
+	test_write_lines 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21 >expected &&
 
 	mv file1 file2 &&
 	git update-index --add --remove file1 file2 &&
@@ -38,10 +29,7 @@ test_expect_success setup '
 	mv saved.file1 file1 &&
 	git update-index --add --remove file1 file2 &&
 
-	for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 F 21
-	do
-		echo $i
-	done >file1 &&
+	test_write_lines 1 E 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 F 21 >file1 &&
 
 	cat file1 >saved.file1
 '
diff --git a/t/t4118-apply-empty-context.sh b/t/t4118-apply-empty-context.sh
index 65f2e4c3ef..1bce118600 100755
--- a/t/t4118-apply-empty-context.sh
+++ b/t/t4118-apply-empty-context.sh
@@ -10,11 +10,7 @@ test_description='git apply with new style GNU diff with empty context
 . ./test-lib.sh
 
 test_expect_success setup '
-	{
-		echo; echo;
-		echo A; echo B; echo C;
-		echo;
-	} >file1 &&
+	test_write_lines "" "" A B C "" >file1 &&
 	cat file1 >file1.orig &&
 	{
 		cat file1 &&
diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index 0ca29821ec..ebff6c6883 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -230,9 +230,9 @@ test_expect_success 'blank at EOF with --whitespace=fix (1)' '
 	test_might_fail git config --unset core.whitespace &&
 	rm -f .gitattributes &&
 
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	git add one &&
-	{ echo a; echo b; echo c; } >expect &&
+	test_write_lines a b c >expect &&
 	{ cat expect; echo; } >one &&
 	git diff -- one >patch &&
 
@@ -242,10 +242,10 @@ test_expect_success 'blank at EOF with --whitespace=fix (1)' '
 '
 
 test_expect_success 'blank at EOF with --whitespace=fix (2)' '
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	git add one &&
-	{ echo a; echo c; } >expect &&
-	{ cat expect; echo; echo; } >one &&
+	test_write_lines a b >expect &&
+	{ cat expect && test_write_lines "" ""; } >one &&
 	git diff -- one >patch &&
 
 	git checkout one &&
@@ -254,10 +254,10 @@ test_expect_success 'blank at EOF with --whitespace=fix (2)' '
 '
 
 test_expect_success 'blank at EOF with --whitespace=fix (3)' '
-	{ echo a; echo b; echo; } >one &&
+	test_write_lines a b "" >one &&
 	git add one &&
-	{ echo a; echo c; echo; } >expect &&
-	{ cat expect; echo; echo; } >one &&
+	test_write_lines a c "" >expect &&
+	{ cat expect && test_write_lines "" ""; } >one &&
 	git diff -- one >patch &&
 
 	git checkout one &&
@@ -266,9 +266,9 @@ test_expect_success 'blank at EOF with --whitespace=fix (3)' '
 '
 
 test_expect_success 'blank at end of hunk, not at EOF with --whitespace=fix' '
-	{ echo a; echo b; echo; echo; echo; echo; echo; echo d; } >one &&
+	test_write_lines a b "" "" "" "" "" d >one &&
 	git add one &&
-	{ echo a; echo c; echo; echo; echo; echo; echo; echo; echo d; } >expect &&
+	test_write_lines a b "" "" "" "" "" "" d >expect &&
 	cp expect one &&
 	git diff -- one >patch &&
 
@@ -278,7 +278,7 @@ test_expect_success 'blank at end of hunk, not at EOF with --whitespace=fix' '
 '
 
 test_expect_success 'blank at EOF with --whitespace=warn' '
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	git add one &&
 	echo >>one &&
 	cat one >expect &&
@@ -291,7 +291,7 @@ test_expect_success 'blank at EOF with --whitespace=warn' '
 '
 
 test_expect_success 'blank at EOF with --whitespace=error' '
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	git add one &&
 	cat one >expect &&
 	echo >>one &&
@@ -304,7 +304,7 @@ test_expect_success 'blank at EOF with --whitespace=error' '
 '
 
 test_expect_success 'blank but not empty at EOF' '
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	git add one &&
 	echo "   " >>one &&
 	cat one >expect &&
@@ -317,13 +317,13 @@ test_expect_success 'blank but not empty at EOF' '
 '
 
 test_expect_success 'applying beyond EOF requires one non-blank context line' '
-	{ echo; echo; echo; echo; } >one &&
+	test_write_lines "" "" "" "" >one &&
 	git add one &&
-	{ echo b; } >>one &&
+	echo b >>one &&
 	git diff -- one >patch &&
 
 	git checkout one &&
-	{ echo a; echo; } >one &&
+	test_write_lines a "" >one &&
 	cp one expect &&
 	test_must_fail git apply --whitespace=fix patch &&
 	test_cmp expect one &&
@@ -333,7 +333,7 @@ test_expect_success 'applying beyond EOF requires one non-blank context line' '
 
 test_expect_success 'tons of blanks at EOF should not apply' '
 	for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
-		echo; echo; echo; echo;
+		test_write_lines "" "" "" ""
 	done >one &&
 	git add one &&
 	echo a >>one &&
@@ -362,9 +362,9 @@ test_expect_success 'missing blank line at end with --whitespace=fix' '
 '
 
 test_expect_success 'two missing blank lines at end with --whitespace=fix' '
-	{ echo a; echo; echo b; echo c; } >one &&
+	test_write_lines a "" b c >one &&
 	cp one no-blank-lines &&
-	{ echo; echo; } >>one &&
+	test_write_lines "" "" >>one &&
 	git add one &&
 	echo d >>one &&
 	cp one expect &&
@@ -381,9 +381,9 @@ test_expect_success 'two missing blank lines at end with --whitespace=fix' '
 '
 
 test_expect_success 'missing blank line at end, insert before end, --whitespace=fix' '
-	{ echo a; echo; } >one &&
+	test_write_lines a "" >one &&
 	git add one &&
-	{ echo b; echo a; echo; } >one &&
+	test_write_lines b a "" >one &&
 	cp one expect &&
 	git diff -- one >patch &&
 	echo a >one &&
@@ -393,10 +393,10 @@ test_expect_success 'missing blank line at end, insert before end, --whitespace=
 '
 
 test_expect_success 'shrink file with tons of missing blanks at end of file' '
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	cp one no-blank-lines &&
 	for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
-		echo; echo; echo; echo;
+		test_write_lines "" "" "" ""
 	done >>one &&
 	git add one &&
 	echo a >one &&
@@ -412,9 +412,9 @@ test_expect_success 'shrink file with tons of missing blanks at end of file' '
 '
 
 test_expect_success 'missing blanks at EOF must only match blank lines' '
-	{ echo a; echo b; } >one &&
+	test_write_lines a b >one &&
 	git add one &&
-	{ echo c; echo d; } >>one &&
+	test_write_lines c d >>one &&
 	git diff -- one >patch &&
 
 	echo a >one &&
@@ -434,9 +434,9 @@ test_expect_success 'missing blank line should match context line with spaces' '
 	git add one &&
 	echo d >>one &&
 	git diff -- one >patch &&
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	cp one expect &&
-	{ echo; echo d; } >>expect &&
+	test_write_lines "" d >>expect &&
 	git add one &&
 
 	git apply --whitespace=fix patch &&
@@ -455,7 +455,7 @@ test_expect_success 'same, but with the --ignore-space-option' '
 	echo d >>one &&
 	cp one expect &&
 	git diff -- one >patch &&
-	{ echo a; echo b; echo c; } >one &&
+	test_write_lines a b c >one &&
 	git add one &&
 
 	git checkout-index -f one &&
diff --git a/t/t4126-apply-empty.sh b/t/t4126-apply-empty.sh
index ceb6a79fe0..7391a5a1d2 100755
--- a/t/t4126-apply-empty.sh
+++ b/t/t4126-apply-empty.sh
@@ -9,10 +9,7 @@ test_expect_success setup '
 	git add empty &&
 	test_tick &&
 	git commit -m initial &&
-	for i in a b c d e
-	do
-		echo $i
-	done >empty &&
+	test_write_lines a b c d e >empty &&
 	cat empty >expect &&
 	git diff |
 	sed -e "/^diff --git/d" \
diff --git a/t/t4127-apply-same-fn.sh b/t/t4127-apply-same-fn.sh
index 305b7e649e..079872c714 100755
--- a/t/t4127-apply-same-fn.sh
+++ b/t/t4127-apply-same-fn.sh
@@ -10,10 +10,7 @@ modify () {
 }
 
 test_expect_success setup '
-	for i in a b c d e f g h i j k l m
-	do
-		echo $i
-	done >same_fn &&
+	test_write_lines a b c d e f g h i j k l m >same_fn &&
 	cp same_fn other_fn &&
 	git add same_fn other_fn &&
 	git commit -m initial
diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh
index 2374151662..5ed7e22827 100755
--- a/t/t4151-am-abort.sh
+++ b/t/t4151-am-abort.sh
@@ -5,10 +5,7 @@ test_description='am --abort'
 . ./test-lib.sh
 
 test_expect_success setup '
-	for i in a b c d e f g
-	do
-		echo $i
-	done >file-1 &&
+	test_write_lines a b c d e f g >file-1 &&
 	cp file-1 file-2 &&
 	test_tick &&
 	git add file-1 file-2 &&
@@ -43,10 +40,7 @@ do
 
 		test_must_fail git am$with3 000[1245]-*.patch &&
 		git log --pretty=tformat:%s >actual &&
-		for i in 3 2 initial
-		do
-			echo $i
-		done >expect &&
+		test_write_lines 3 2 initial >expect &&
 		test_cmp expect actual
 	'
 
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index e13a884207..f9877d42d7 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -361,11 +361,7 @@ test_expect_success 'unpacking with --strict' '
 	ST=$(git write-tree) &&
 	git rev-list --objects "$LIST" "$LI" "$ST" >actual &&
 	PACK5=$( git pack-objects test-5 <actual ) &&
-	PACK6=$( (
-			echo "$LIST"
-			echo "$LI"
-			echo "$ST"
-		 ) | git pack-objects test-6 ) &&
+	PACK6=$( test_write_lines "$LIST" "$LI" "$ST" | git pack-objects test-6 ) &&
 	test_create_repo test-5 &&
 	(
 		cd test-5 &&
@@ -408,11 +404,7 @@ test_expect_success 'index-pack with --strict' '
 	ST=$(git write-tree) &&
 	git rev-list --objects "$LIST" "$LI" "$ST" >actual &&
 	PACK5=$( git pack-objects test-5 <actual ) &&
-	PACK6=$( (
-			echo "$LIST"
-			echo "$LI"
-			echo "$ST"
-		 ) | git pack-objects test-6 ) &&
+	PACK6=$( test_write_lines "$LIST" "$LI" "$ST" | git pack-objects test-6 ) &&
 	test_create_repo test-7 &&
 	(
 		cd test-7 &&
diff --git a/t/t5306-pack-nobase.sh b/t/t5306-pack-nobase.sh
index f4931c0c2a..51973f4a51 100755
--- a/t/t5306-pack-nobase.sh
+++ b/t/t5306-pack-nobase.sh
@@ -12,7 +12,7 @@ test_description='git-pack-object with missing base
 #
 test_expect_success \
     'setup base' \
-    'for a in a b c d e f g h i; do echo $a >>text; done &&
+    'test_write_lines a b c d e f g h i >text &&
      echo side >side &&
      git update-index --add text side &&
      A=$(echo A | git commit-tree $(git write-tree)) &&
diff --git a/t/t5611-clone-config.sh b/t/t5611-clone-config.sh
index f8625f9158..4b3877216e 100755
--- a/t/t5611-clone-config.sh
+++ b/t/t5611-clone-config.sh
@@ -17,7 +17,7 @@ test_expect_success 'clone -c sets config in cloned repo' '
 test_expect_success 'clone -c can set multi-keys' '
 	rm -rf child &&
 	git clone -c core.foo=bar -c core.foo=baz . child &&
-	{ echo bar; echo baz; } >expect &&
+	test_write_lines bar baz >expect &&
 	git --git-dir=child/.git config --get-all core.foo >actual &&
 	test_cmp expect actual
 '
diff --git a/t/t6019-rev-list-ancestry-path.sh b/t/t6019-rev-list-ancestry-path.sh
index 20adbece65..af57a04b7f 100755
--- a/t/t6019-rev-list-ancestry-path.sh
+++ b/t/t6019-rev-list-ancestry-path.sh
@@ -51,7 +51,7 @@ test_expect_success setup '
 '
 
 test_expect_success 'rev-list D..M' '
-	for c in E F G H I J K L M; do echo $c; done >expect &&
+	test_write_lines E F G H I J K L M >expect &&
 	git rev-list --format=%s D..M |
 	sed -e "/^commit /d" |
 	sort >actual &&
@@ -59,7 +59,7 @@ test_expect_success 'rev-list D..M' '
 '
 
 test_expect_success 'rev-list --ancestry-path D..M' '
-	for c in E F H I J L M; do echo $c; done >expect &&
+	test_write_lines E F H I J L M >expect &&
 	git rev-list --ancestry-path --format=%s D..M |
 	sed -e "/^commit /d" |
 	sort >actual &&
@@ -81,7 +81,7 @@ test_expect_success 'rev-list --ancestry-path D..M -- M.t' '
 '
 
 test_expect_success 'rev-list F...I' '
-	for c in F G H I; do echo $c; done >expect &&
+	test_write_lines F G H I >expect &&
 	git rev-list --format=%s F...I |
 	sed -e "/^commit /d" |
 	sort >actual &&
@@ -89,7 +89,7 @@ test_expect_success 'rev-list F...I' '
 '
 
 test_expect_success 'rev-list --ancestry-path F...I' '
-	for c in F H I; do echo $c; done >expect &&
+	test_write_lines F H I >expect &&
 	git rev-list --ancestry-path --format=%s F...I |
 	sed -e "/^commit /d" |
 	sort >actual &&
@@ -111,7 +111,7 @@ test_expect_success 'rev-list --ancestry-path G..M -- G.t' '
 '
 
 test_expect_success 'rev-list --ancestry-path --simplify-merges G^..M -- G.t' '
-	for c in G L; do echo $c; done >expect &&
+	test_write_lines G L >expect &&
 	git rev-list --ancestry-path --simplify-merges --format=%s G^..M -- G.t |
 	sed -e "/^commit /d" |
 	sort >actual &&
diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh
index ddf34f0115..ed449abe55 100755
--- a/t/t6060-merge-index.sh
+++ b/t/t6060-merge-index.sh
@@ -4,9 +4,7 @@ test_description='basic git merge-index / git-merge-one-file tests'
 . ./test-lib.sh
 
 test_expect_success 'setup diverging branches' '
-	for i in 1 2 3 4 5 6 7 8 9 10; do
-		echo $i
-	done >file &&
+	test_write_lines 1 2 3 4 5 6 7 8 9 10 >file &&
 	git add file &&
 	git commit -m base &&
 	git tag base &&
diff --git a/t/t6409-merge-subtree.sh b/t/t6409-merge-subtree.sh
index ba7890ec52..e9ba6f1690 100755
--- a/t/t6409-merge-subtree.sh
+++ b/t/t6409-merge-subtree.sh
@@ -10,7 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 test_expect_success setup '
 
 	s="1 2 3 4 5 6 7 8" &&
-	for i in $s; do echo $i; done >hello &&
+	test_write_lines $s >hello &&
 	git add hello &&
 	git commit -m initial &&
 	git checkout -b side &&
@@ -18,7 +18,7 @@ test_expect_success setup '
 	git add hello &&
 	git commit -m second &&
 	git checkout main &&
-	for i in mundo $s; do echo $i; done >hello &&
+	test_write_lines mundo $s >hello &&
 	git add hello &&
 	git commit -m main
 
@@ -27,7 +27,7 @@ test_expect_success setup '
 test_expect_success 'subtree available and works like recursive' '
 
 	git merge -s subtree side &&
-	for i in mundo $s world; do echo $i; done >expect &&
+	test_write_lines mundo $s world >expect &&
 	test_cmp expect hello
 
 '
diff --git a/t/t6417-merge-ours-theirs.sh b/t/t6417-merge-ours-theirs.sh
index ec065d6a65..62d1406119 100755
--- a/t/t6417-merge-ours-theirs.sh
+++ b/t/t6417-merge-ours-theirs.sh
@@ -7,10 +7,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . ./test-lib.sh
 
 test_expect_success setup '
-	for i in 1 2 3 4 5 6 7 8 9
-	do
-		echo "$i"
-	done >file &&
+	test_write_lines 1 2 3 4 5 6 7 8 9 >file &&
 	git add file &&
 	cp file elif &&
 	git commit -m initial &&
diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh
index 512ae2781f..fb5417d5e7 100755
--- a/t/t7501-commit-basic-functionality.sh
+++ b/t/t7501-commit-basic-functionality.sh
@@ -667,10 +667,7 @@ test_expect_success 'amend can copy notes' '
 
 test_expect_success 'commit a file whose name is a dash' '
 	git reset --hard &&
-	for i in 1 2 3 4 5
-	do
-		echo $i
-	done >./- &&
+	test_write_lines 1 2 3 4 5 >./- &&
 	git add ./- &&
 	test_tick &&
 	git commit -m "add dash" >output </dev/null &&
diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh
index da80f815ce..d751d48b7d 100755
--- a/t/t8003-blame-corner-cases.sh
+++ b/t/t8003-blame-corner-cases.sh
@@ -13,14 +13,8 @@ test_expect_success setup '
 	echo B B B B B >two &&
 	echo C C C C C >tres &&
 	echo ABC >mouse &&
-	for i in 1 2 3 4 5 6 7 8 9
-	do
-		echo $i
-	done >nine_lines &&
-	for i in 1 2 3 4 5 6 7 8 9 a
-	do
-		echo $i
-	done >ten_lines &&
+	test_write_lines 1 2 3 4 5 6 7 8 9 >nine_lines &&
+	test_write_lines 1 2 3 4 5 6 7 8 9 a >ten_lines &&
 	git add one two tres mouse nine_lines ten_lines &&
 	test_tick &&
 	GIT_AUTHOR_NAME=Initial git commit -m Initial &&
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 10/19] tests: fix broken &&-chains in compound statements
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (8 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 09/19] tests: use test_write_lines() to generate line-oriented output Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09  5:11 ` [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions Eric Sunshine
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

The top-level &&-chain checker built into t/test-lib.sh causes tests to
magically exit with code 117 if the &&-chain is broken. However, it has
the shortcoming that the magic does not work within `{...}` groups,
`(...)` subshells, `$(...)` substitutions, or within bodies of compound
statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
partly fills in the gap by catching broken &&-chains in `(...)`
subshells, but bugs can still lurk behind broken &&-chains in the other
cases.

Fix broken &&-chains in compound statements in order to reduce the
number of possible lurking bugs.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/perf/p0005-status.sh                 | 12 ++++++------
 t/perf/p0006-read-tree-checkout.sh     | 20 ++++++++++----------
 t/perf/p0007-write-cache.sh            |  4 ++--
 t/perf/p5302-pack-index.sh             |  2 +-
 t/perf/p5303-many-packs.sh             |  8 ++++----
 t/t1050-large.sh                       |  4 ++--
 t/t1300-config.sh                      |  2 +-
 t/t1700-split-index.sh                 |  4 ++--
 t/t2200-add-update.sh                  |  4 ++--
 t/t3070-wildmatch.sh                   |  2 +-
 t/t3700-add.sh                         |  4 ++--
 t/t4046-diff-unmerged.sh               |  2 +-
 t/t4123-apply-shrink.sh                |  4 ++--
 t/t4138-apply-ws-expansion.sh          | 20 ++++++++++----------
 t/t5302-pack-index.sh                  |  2 +-
 t/t5317-pack-objects-filter-objects.sh | 20 ++++++++++----------
 t/t5571-pre-push-hook.sh               |  2 +-
 t/t5616-partial-clone.sh               | 18 +++++++++---------
 t/t6005-rev-list-count.sh              |  8 ++++----
 t/t6009-rev-list-parent.sh             |  2 +-
 t/t6112-rev-list-filters-objects.sh    | 14 +++++++-------
 t/t6120-describe.sh                    |  7 +++++--
 t/t6407-merge-binary.sh                |  4 ++--
 t/t6412-merge-large-rename.sh          |  2 +-
 t/t7004-tag.sh                         |  7 +++++--
 t/t7519-status-fsmonitor.sh            |  2 +-
 t/t7602-merge-octopus-many.sh          |  2 +-
 t/t9130-git-svn-authors-file.sh        |  2 +-
 28 files changed, 95 insertions(+), 89 deletions(-)

diff --git a/t/perf/p0005-status.sh b/t/perf/p0005-status.sh
index 0b0aa9858f..ca58d6c9b5 100755
--- a/t/perf/p0005-status.sh
+++ b/t/perf/p0005-status.sh
@@ -24,17 +24,17 @@ test_perf_default_repo
 test_expect_success "setup repo" '
 	if git rev-parse --verify refs/heads/p0006-ballast^{commit}
 	then
-		echo Assuming synthetic repo from many-files.sh
-		git branch br_base            master
-		git branch br_ballast         p0006-ballast
-		git config --local core.sparsecheckout 1
+		echo Assuming synthetic repo from many-files.sh &&
+		git branch br_base            master &&
+		git branch br_ballast         p0006-ballast &&
+		git config --local core.sparsecheckout 1 &&
 		cat >.git/info/sparse-checkout <<-EOF
 		/*
 		!ballast/*
 		EOF
 	else
-		echo Assuming non-synthetic repo...
-		git branch br_base            $(git rev-list HEAD | tail -n 1)
+		echo Assuming non-synthetic repo... &&
+		git branch br_base            $(git rev-list HEAD | tail -n 1) &&
 		git branch br_ballast         HEAD
 	fi &&
 	git checkout -q br_ballast &&
diff --git a/t/perf/p0006-read-tree-checkout.sh b/t/perf/p0006-read-tree-checkout.sh
index 78cc23fe2f..900b385c4b 100755
--- a/t/perf/p0006-read-tree-checkout.sh
+++ b/t/perf/p0006-read-tree-checkout.sh
@@ -24,21 +24,21 @@ test_perf_default_repo
 test_expect_success "setup repo" '
 	if git rev-parse --verify refs/heads/p0006-ballast^{commit}
 	then
-		echo Assuming synthetic repo from many-files.sh
-		git branch br_base            master
-		git branch br_ballast         p0006-ballast^
-		git branch br_ballast_alias   p0006-ballast^
-		git branch br_ballast_plus_1  p0006-ballast
-		git config --local core.sparsecheckout 1
+		echo Assuming synthetic repo from many-files.sh &&
+		git branch br_base            master &&
+		git branch br_ballast         p0006-ballast^ &&
+		git branch br_ballast_alias   p0006-ballast^ &&
+		git branch br_ballast_plus_1  p0006-ballast &&
+		git config --local core.sparsecheckout 1 &&
 		cat >.git/info/sparse-checkout <<-EOF
 		/*
 		!ballast/*
 		EOF
 	else
-		echo Assuming non-synthetic repo...
-		git branch br_base            $(git rev-list HEAD | tail -n 1)
-		git branch br_ballast         HEAD^ || error "no ancestor commit from current head"
-		git branch br_ballast_alias   HEAD^
+		echo Assuming non-synthetic repo... &&
+		git branch br_base            $(git rev-list HEAD | tail -n 1) &&
+		git branch br_ballast         HEAD^ || error "no ancestor commit from current head" &&
+		git branch br_ballast_alias   HEAD^ &&
 		git branch br_ballast_plus_1  HEAD
 	fi &&
 	git checkout -q br_ballast &&
diff --git a/t/perf/p0007-write-cache.sh b/t/perf/p0007-write-cache.sh
index 09595264f0..25d8ff7443 100755
--- a/t/perf/p0007-write-cache.sh
+++ b/t/perf/p0007-write-cache.sh
@@ -9,8 +9,8 @@ test_perf_default_repo
 test_expect_success "setup repo" '
 	if git rev-parse --verify refs/heads/p0006-ballast^{commit}
 	then
-		echo Assuming synthetic repo from many-files.sh
-		git config --local core.sparsecheckout 1
+		echo Assuming synthetic repo from many-files.sh &&
+		git config --local core.sparsecheckout 1 &&
 		cat >.git/info/sparse-checkout <<-EOF
 		/*
 		!ballast/*
diff --git a/t/perf/p5302-pack-index.sh b/t/perf/p5302-pack-index.sh
index 228593d9ad..654cd9c86e 100755
--- a/t/perf/p5302-pack-index.sh
+++ b/t/perf/p5302-pack-index.sh
@@ -21,7 +21,7 @@ test_expect_success 'set up thread-counting tests' '
 	threads= &&
 	while test $t -gt 0
 	do
-		threads="$t $threads"
+		threads="$t $threads" &&
 		t=$((t / 2))
 	done
 '
diff --git a/t/perf/p5303-many-packs.sh b/t/perf/p5303-many-packs.sh
index 35c0cbdf49..58213fe171 100755
--- a/t/perf/p5303-many-packs.sh
+++ b/t/perf/p5303-many-packs.sh
@@ -126,10 +126,10 @@ done
 # Measure pack loading with 10,000 packs.
 test_expect_success 'generate lots of packs' '
 	for i in $(test_seq 10000); do
-		echo "blob"
-		echo "data <<EOF"
-		echo "blob $i"
-		echo "EOF"
+		echo "blob" &&
+		echo "data <<EOF" &&
+		echo "blob $i" &&
+		echo "EOF" &&
 		echo "checkpoint"
 	done |
 	git -c fastimport.unpackLimit=0 fast-import
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index 6bc1d76fb1..99ff2866b7 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -54,7 +54,7 @@ test_expect_success 'add a large file or two' '
 	bad= count=0 idx= &&
 	for p in .git/objects/pack/pack-*.pack
 	do
-		count=$(( $count + 1 ))
+		count=$(( $count + 1 )) &&
 		if test_path_is_file "$p" &&
 		   idx=${p%.pack}.idx && test_path_is_file "$idx"
 		then
@@ -78,7 +78,7 @@ test_expect_success 'add a large file or two' '
 	bad= count=0 &&
 	for p in .git/objects/pack/pack-*.pack
 	do
-		count=$(( $count + 1 ))
+		count=$(( $count + 1 )) &&
 		if test_path_is_file "$p" &&
 		   idx=${p%.pack}.idx && test_path_is_file "$idx"
 		then
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 9ff46f3b04..9571649c42 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -717,7 +717,7 @@ test_expect_success bool '
 	rm -f result &&
 	for i in 1 2 3 4
 	do
-	    git config --bool --get bool.true$i >>result
+	    git config --bool --get bool.true$i >>result &&
 	    git config --bool --get bool.false$i >>result
 	done &&
 	test_cmp expect result'
diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index decd2527ed..b4ab166369 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -48,10 +48,10 @@ test_expect_success 'enable split index' '
 	# NEEDSWORK: Stop hard-coding checksums.
 	if test "$indexversion" = "4"
 	then
-		own=$(test_oid own_v4)
+		own=$(test_oid own_v4) &&
 		base=$(test_oid base_v4)
 	else
-		own=$(test_oid own_v3)
+		own=$(test_oid own_v3) &&
 		base=$(test_oid base_v3)
 	fi &&
 
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 94c4cb0672..67b9cc752f 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -150,8 +150,8 @@ test_expect_success 'add -u resolves unmerged paths' '
 	{
 		for path in path1 path2
 		do
-			echo "100644 $one 1	$path"
-			echo "100644 $two 2	$path"
+			echo "100644 $one 1	$path" &&
+			echo "100644 $two 2	$path" &&
 			echo "100644 $three 3	$path"
 		done
 		echo "100644 $one 1	path3"
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 72d5b014d8..f9539968e4 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -193,7 +193,7 @@ match() {
 		file=$(cat .git/expected_test_file) &&
 		if should_create_test_file "$file"
 		then
-			dirs=${file%/*}
+			dirs=${file%/*} &&
 			if test "$file" != "$dirs"
 			then
 				mkdir -p -- "$dirs" &&
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 283a66955d..23c3c214c5 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -141,8 +141,8 @@ test_expect_success 'check correct prefix detection' '
 test_expect_success 'git add with filemode=0, symlinks=0, and unmerged entries' '
 	for s in 1 2 3
 	do
-		echo $s > stage$s
-		echo "100755 $(git hash-object -w stage$s) $s	file"
+		echo $s > stage$s &&
+		echo "100755 $(git hash-object -w stage$s) $s	file" &&
 		echo "120000 $(printf $s | git hash-object -w -t blob --stdin) $s	symlink"
 	done | git update-index --index-info &&
 	git config core.filemode 0 &&
diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh
index ff7cfd884a..8c3d48e257 100755
--- a/t/t4046-diff-unmerged.sh
+++ b/t/t4046-diff-unmerged.sh
@@ -18,7 +18,7 @@ test_expect_success setup '
 			for t in o x
 			do
 				path="$b$o$t" &&
-				case "$path" in ooo) continue ;; esac
+				case "$path" in ooo) continue ;; esac &&
 				paths="$paths$path " &&
 				p="	$path" &&
 				case "$b" in x) echo "$m1$p" ;; esac &&
diff --git a/t/t4123-apply-shrink.sh b/t/t4123-apply-shrink.sh
index 984157f03b..51e69cf79e 100755
--- a/t/t4123-apply-shrink.sh
+++ b/t/t4123-apply-shrink.sh
@@ -45,8 +45,8 @@ test_expect_success 'apply should fail gracefully' '
 		echo Oops, should not have succeeded
 		false
 	else
-		status=$?
-		echo "Status was $status"
+		status=$? &&
+		echo "Status was $status" &&
 		if test -f .git/index.lock
 		then
 			echo Oops, should not have crashed
diff --git a/t/t4138-apply-ws-expansion.sh b/t/t4138-apply-ws-expansion.sh
index b19faeb67a..4ba52bbb61 100755
--- a/t/t4138-apply-ws-expansion.sh
+++ b/t/t4138-apply-ws-expansion.sh
@@ -29,7 +29,7 @@ test_expect_success setup '
 	x=1 &&
 	while test $x -lt $n
 	do
-		printf "%63s%d\n" "" $x >>after
+		printf "%63s%d\n" "" $x >>after &&
 		x=$(( $x + 1 ))
 	done &&
 	printf "\t%s\n" d e f >>after &&
@@ -40,7 +40,7 @@ test_expect_success setup '
 	x=1 &&
 	while test $x -lt $n
 	do
-		printf "%63s%d\n" "" $x >>expect-2
+		printf "%63s%d\n" "" $x >>expect-2 &&
 		x=$(( $x + 1 ))
 	done &&
 	printf "%64s\n" d e f >>expect-2 &&
@@ -52,7 +52,7 @@ test_expect_success setup '
 	x=0 &&
 	while test $x -lt $n
 	do
-		printf "%63s%02d\n" "" $x >>after
+		printf "%63s%02d\n" "" $x >>after &&
 		x=$(( $x + 1 ))
 	done &&
 	printf "\t%s\n" d e f >>after &&
@@ -63,7 +63,7 @@ test_expect_success setup '
 	x=0 &&
 	while test $x -lt $n
 	do
-		printf "%63s%02d\n" "" $x >>expect-3
+		printf "%63s%02d\n" "" $x >>expect-3 &&
 		x=$(( $x + 1 ))
 	done &&
 	printf "%64s\n" d e f >>expect-3 &&
@@ -73,15 +73,15 @@ test_expect_success setup '
 	x=0 &&
 	while test $x -lt 50
 	do
-		printf "\t%02d\n" $x >>before
+		printf "\t%02d\n" $x >>before &&
 		x=$(( $x + 1 ))
 	done &&
 	cat before >after &&
 	printf "%64s\n" a b c >>after &&
 	while test $x -lt 100
 	do
-		printf "\t%02d\n" $x >>before
-		printf "\t%02d\n" $x >>after
+		printf "\t%02d\n" $x >>before &&
+		printf "\t%02d\n" $x >>after &&
 		x=$(( $x + 1 ))
 	done &&
 	test_expect_code 1 git diff --no-index before after >patch4.patch.raw &&
@@ -90,15 +90,15 @@ test_expect_success setup '
 	x=0 &&
 	while test $x -lt 50
 	do
-		printf "%63s%02d\n" "" $x >>test-4
+		printf "%63s%02d\n" "" $x >>test-4 &&
 		x=$(( $x + 1 ))
 	done &&
 	cat test-4 >expect-4 &&
 	printf "%64s\n" a b c >>expect-4 &&
 	while test $x -lt 100
 	do
-		printf "%63s%02d\n" "" $x >>test-4
-		printf "%63s%02d\n" "" $x >>expect-4
+		printf "%63s%02d\n" "" $x >>test-4 &&
+		printf "%63s%02d\n" "" $x >>expect-4 &&
 		x=$(( $x + 1 ))
 	done &&
 
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index 7c9d687367..8ee67df38f 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -14,7 +14,7 @@ test_expect_success 'setup' '
 	i=1 &&
 	while test $i -le 100
 	do
-		iii=$(printf "%03i" $i)
+		iii=$(printf "%03i" $i) &&
 		test-tool genrandom "bar" 200 > wide_delta_$iii &&
 		test-tool genrandom "baz $iii" 50 >> wide_delta_$iii &&
 		test-tool genrandom "foo"$i 100 > deep_delta_$iii &&
diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh
index 13ed3eb136..8fb6acae47 100755
--- a/t/t5317-pack-objects-filter-objects.sh
+++ b/t/t5317-pack-objects-filter-objects.sh
@@ -16,8 +16,8 @@ test_expect_success 'setup r1' '
 	git init r1 &&
 	for n in 1 2 3 4 5
 	do
-		echo "This is file: $n" > r1/file.$n
-		git -C r1 add file.$n
+		echo "This is file: $n" > r1/file.$n &&
+		git -C r1 add file.$n &&
 		git -C r1 commit -m "$n"
 	done
 '
@@ -116,8 +116,8 @@ test_expect_success 'setup r2' '
 	git init r2 &&
 	for n in 1000 10000
 	do
-		printf "%"$n"s" X > r2/large.$n
-		git -C r2 add large.$n
+		printf "%"$n"s" X > r2/large.$n &&
+		git -C r2 add large.$n &&
 		git -C r2 commit -m "$n"
 	done
 '
@@ -278,9 +278,9 @@ test_expect_success 'setup r3' '
 	mkdir r3/dir1 &&
 	for n in sparse1 sparse2
 	do
-		echo "This is file: $n" > r3/$n
-		git -C r3 add $n
-		echo "This is file: dir1/$n" > r3/dir1/$n
+		echo "This is file: $n" > r3/$n &&
+		git -C r3 add $n &&
+		echo "This is file: dir1/$n" > r3/dir1/$n &&
 		git -C r3 add dir1/$n
 	done &&
 	git -C r3 commit -m "sparse" &&
@@ -331,9 +331,9 @@ test_expect_success 'setup r4' '
 	mkdir r4/dir1 &&
 	for n in sparse1 sparse2
 	do
-		echo "This is file: $n" > r4/$n
-		git -C r4 add $n
-		echo "This is file: dir1/$n" > r4/dir1/$n
+		echo "This is file: $n" > r4/$n &&
+		git -C r4 add $n &&
+		echo "This is file: dir1/$n" > r4/dir1/$n &&
 		git -C r4 add dir1/$n
 	done &&
 	echo dir1/ >r4/pattern &&
diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh
index ad8d5804f7..b043a279f1 100755
--- a/t/t5571-pre-push-hook.sh
+++ b/t/t5571-pre-push-hook.sh
@@ -117,7 +117,7 @@ test_expect_success 'set up many-ref tests' '
 		nr=1000
 		while test $nr -lt 2000
 		do
-			nr=$(( $nr + 1 ))
+			nr=$(( $nr + 1 )) &&
 			echo "create refs/heads/b/$nr $COMMIT3"
 		done
 	} | git update-ref --stdin
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index cf3e82bdf5..23c156e399 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -16,9 +16,9 @@ test_expect_success 'setup normal src repo' '
 	git init src &&
 	for n in 1 2 3 4
 	do
-		echo "This is file: $n" > src/file.$n.txt
-		git -C src add file.$n.txt
-		git -C src commit -m "file $n"
+		echo "This is file: $n" > src/file.$n.txt &&
+		git -C src add file.$n.txt &&
+		git -C src commit -m "file $n" &&
 		git -C src ls-files -s file.$n.txt >>temp
 	done &&
 	awk -f print_2.awk <temp | sort >expect_1.oids &&
@@ -72,8 +72,8 @@ test_expect_success 'push new commits to server' '
 	git -C src remote add srv "file://$(pwd)/srv.bare" &&
 	for x in a b c d e
 	do
-		echo "Mod file.1.txt $x" >>src/file.1.txt
-		git -C src add file.1.txt
+		echo "Mod file.1.txt $x" >>src/file.1.txt &&
+		git -C src add file.1.txt &&
 		git -C src commit -m "mod $x"
 	done &&
 	git -C src blame main -- file.1.txt >expect.blame &&
@@ -114,8 +114,8 @@ test_expect_success 'verify blame causes dynamic object fetch' '
 test_expect_success 'push new commits to server for file.2.txt' '
 	for x in a b c d e f
 	do
-		echo "Mod file.2.txt $x" >>src/file.2.txt
-		git -C src add file.2.txt
+		echo "Mod file.2.txt $x" >>src/file.2.txt &&
+		git -C src add file.2.txt &&
 		git -C src commit -m "mod $x"
 	done &&
 	git -C src push -u srv main
@@ -135,8 +135,8 @@ test_expect_success 'override inherited filter-spec using --no-filter' '
 test_expect_success 'push new commits to server for file.3.txt' '
 	for x in a b c d e f
 	do
-		echo "Mod file.3.txt $x" >>src/file.3.txt
-		git -C src add file.3.txt
+		echo "Mod file.3.txt $x" >>src/file.3.txt &&
+		git -C src add file.3.txt &&
 		git -C src commit -m "mod $x"
 	done &&
 	git -C src push -u srv main
diff --git a/t/t6005-rev-list-count.sh b/t/t6005-rev-list-count.sh
index 0b64822bf6..32b152095a 100755
--- a/t/t6005-rev-list-count.sh
+++ b/t/t6005-rev-list-count.sh
@@ -5,10 +5,10 @@ test_description='git rev-list --max-count and --skip test'
 . ./test-lib.sh
 
 test_expect_success 'setup' '
-    for n in 1 2 3 4 5 ; do \
-        echo $n > a ; \
-        git add a ; \
-        git commit -m "$n" ; \
+    for n in 1 2 3 4 5 ; do
+        echo $n > a &&
+        git add a &&
+        git commit -m "$n"
     done
 '
 
diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh
index 63fa7c8313..dc8160aa45 100755
--- a/t/t6009-rev-list-parent.sh
+++ b/t/t6009-rev-list-parent.sh
@@ -142,7 +142,7 @@ test_expect_success 'ancestors with the same commit time' '
 
 	test_tick_keep=$test_tick &&
 	for i in 1 2 3 4 5 6 7 8; do
-		test_tick=$test_tick_keep
+		test_tick=$test_tick_keep &&
 		test_commit t$i
 	done &&
 	git rev-list t1^! --not t$i >result &&
diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh
index 4ade105db3..9848425192 100755
--- a/t/t6112-rev-list-filters-objects.sh
+++ b/t/t6112-rev-list-filters-objects.sh
@@ -16,8 +16,8 @@ test_expect_success 'setup r1' '
 	git init r1 &&
 	for n in 1 2 3 4 5
 	do
-		echo "This is file: $n" > r1/file.$n
-		git -C r1 add file.$n
+		echo "This is file: $n" > r1/file.$n &&
+		git -C r1 add file.$n &&
 		git -C r1 commit -m "$n"
 	done
 '
@@ -73,8 +73,8 @@ test_expect_success 'setup r2' '
 	git init r2 &&
 	for n in 1000 10000
 	do
-		printf "%"$n"s" X > r2/large.$n
-		git -C r2 add large.$n
+		printf "%"$n"s" X > r2/large.$n &&
+		git -C r2 add large.$n &&
 		git -C r2 commit -m "$n"
 	done
 '
@@ -245,9 +245,9 @@ test_expect_success 'setup r3' '
 	mkdir r3/dir1 &&
 	for n in sparse1 sparse2
 	do
-		echo "This is file: $n" > r3/$n
-		git -C r3 add $n
-		echo "This is file: dir1/$n" > r3/dir1/$n
+		echo "This is file: $n" > r3/$n &&
+		git -C r3 add $n &&
+		echo "This is file: dir1/$n" > r3/dir1/$n &&
 		git -C r3 add dir1/$n
 	done &&
 	git -C r3 commit -m "sparse" &&
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index bae2419150..9b2cc066f7 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -390,8 +390,11 @@ test_expect_success ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
 committer A U Thor <author@example.com> $((1000000000 + $i * 100)) +0200
 data <<EOF
 commit #$i
-EOF"
-		test $i = 1 && echo "from refs/heads/main^0"
+EOF" &&
+		if test $i = 1
+		then
+			echo "from refs/heads/main^0"
+		fi &&
 		i=$(($i + 1))
 	done | git fast-import &&
 	git checkout main &&
diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh
index d4273f2575..4c4f690588 100755
--- a/t/t6407-merge-binary.sh
+++ b/t/t6407-merge-binary.sh
@@ -47,7 +47,7 @@ test_expect_success resolve '
 		echo Oops, should not have succeeded
 		false
 	else
-		git ls-files -s >current
+		git ls-files -s >current &&
 		test_cmp expect current
 	fi
 '
@@ -62,7 +62,7 @@ test_expect_success recursive '
 		echo Oops, should not have succeeded
 		false
 	else
-		git ls-files -s >current
+		git ls-files -s >current &&
 		test_cmp expect current
 	fi
 '
diff --git a/t/t6412-merge-large-rename.sh b/t/t6412-merge-large-rename.sh
index c50d315722..ed40801380 100755
--- a/t/t6412-merge-large-rename.sh
+++ b/t/t6412-merge-large-rename.sh
@@ -47,7 +47,7 @@ test_rename() {
 	git commit -a -m change=$n &&
 	git checkout -b test$n HEAD^ &&
 	for i in $(count $n); do
-		git rm $i
+		git rm $i &&
 		make_text $i initial changed >$i.moved
 	done &&
 	git add . &&
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 082be85dff..660cde5a63 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1976,8 +1976,11 @@ test_expect_success ULIMIT_STACK_SIZE '--contains and --no-contains work in a de
 committer A U Thor <author@example.com> $((1000000000 + $i * 100)) +0200
 data <<EOF
 commit #$i
-EOF"
-		test $i = 1 && echo "from refs/heads/main^0"
+EOF" &&
+		if test $i = 1
+		then
+			echo "from refs/heads/main^0"
+		fi &&
 		i=$(($i + 1))
 	done | git fast-import &&
 	git checkout main &&
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index f488d930df..1b4160dc53 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -248,7 +248,7 @@ do
 		git config core.preloadIndex $preload_val &&
 		if test $preload_val = true
 		then
-			GIT_TEST_PRELOAD_INDEX=$preload_val; export GIT_TEST_PRELOAD_INDEX
+			GIT_TEST_PRELOAD_INDEX=$preload_val && export GIT_TEST_PRELOAD_INDEX
 		else
 			sane_unset GIT_TEST_PRELOAD_INDEX
 		fi
diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index a9c816b47f..ddf64dc5f7 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -29,7 +29,7 @@ test_expect_success 'merge c1 with c2, c3, c4, ... c29' '
 	refs="" &&
 	while test $i -le 30
 	do
-		refs="$refs c$i"
+		refs="$refs c$i" &&
 		i=$(expr $i + 1)
 	done &&
 	git merge $refs &&
diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh
index cb764bcadc..b4081fefba 100755
--- a/t/t9130-git-svn-authors-file.sh
+++ b/t/t9130-git-svn-authors-file.sh
@@ -59,7 +59,7 @@ test_expect_success 'authors-file against globs' '
 	git svn clone --authors-file=svn-authors -s "$svnrepo"/aa aa-work &&
 	for i in bb ee cc
 	do
-		branch="aa/branches/$i"
+		branch="aa/branches/$i" &&
 		svn_cmd mkdir -m "$branch" --username $i "$svnrepo/$branch"
 	done
 	'
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (9 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 10/19] tests: fix broken &&-chains in compound statements Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09 16:44   ` Elijah Newren
  2021-12-09  5:11 ` [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups Eric Sunshine
                   ` (9 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

The top-level &&-chain checker built into t/test-lib.sh causes tests to
magically exit with code 117 if the &&-chain is broken. However, it has
the shortcoming that the magic does not work within `{...}` groups,
`(...)` subshells, `$(...)` substitutions, or within bodies of compound
statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
partly fills in the gap by catching broken &&-chains in `(...)`
subshells, but bugs can still lurk behind broken &&-chains in the other
cases.

Fix broken &&-chains in `$(...)` command substitutions in order to
reduce the number of possible lurking bugs.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 contrib/subtree/t/t7900-subtree.sh |  2 +-
 t/t0005-signals.sh                 |  2 +-
 t/t0060-path-utils.sh              |  4 ++--
 t/t1006-cat-file.sh                | 10 +++++-----
 t/t3600-rm.sh                      |  2 +-
 t/t7010-setup.sh                   |  2 +-
 6 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 4153b65321..1c1f76f04a 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -1445,7 +1445,7 @@ test_expect_success 'subtree descendant check' '
 	) &&
 	test_create_commit "$test_count" folder_subtree/0 &&
 	test_create_commit "$test_count" folder_subtree/b &&
-	cherry=$(cd "$test_count"; git rev-parse HEAD) &&
+	cherry=$(cd "$test_count" && git rev-parse HEAD) &&
 	(
 		cd "$test_count" &&
 		git checkout branch
diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh
index a5ec6a0315..eba75a2490 100755
--- a/t/t0005-signals.sh
+++ b/t/t0005-signals.sh
@@ -48,7 +48,7 @@ test_expect_success !MINGW 'a constipated git dies with SIGPIPE' '
 '
 
 test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' '
-	OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) &&
+	OUT=$( ((trap "" PIPE && large_git; echo $? 1>&3) | :) 3>&1 ) &&
 	test_match_signal 13 "$OUT"
 '
 
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 34d1061f32..71a5d370cc 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -216,7 +216,7 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
 	mkdir second &&
 	ln -s ../first second/other &&
 	mkdir third &&
-	dir="$(cd .git; pwd -P)" &&
+	dir="$(cd .git && pwd -P)" &&
 	dir2=third/../second/other/.git &&
 	test "$dir" = "$(test-tool path-utils real_path $dir2)" &&
 	file="$dir"/index &&
@@ -224,7 +224,7 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
 	basename=blub &&
 	test "$dir/$basename" = "$(cd .git && test-tool path-utils real_path "$basename")" &&
 	ln -s ../first/file .git/syml &&
-	sym="$(cd first; pwd -P)"/file &&
+	sym="$(cd first && pwd -P)"/file &&
 	test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")"
 '
 
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 658628375c..67a3f64c2d 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -211,14 +211,14 @@ done
 test_expect_success "--batch-check for a non-existent named object" '
     test "foobar42 missing
 foobar84 missing" = \
-    "$( ( echo foobar42; echo_without_newline foobar84; ) | git cat-file --batch-check)"
+    "$( ( echo foobar42 && echo_without_newline foobar84 ) | git cat-file --batch-check)"
 '
 
 test_expect_success "--batch-check for a non-existent hash" '
     test "0000000000000000000000000000000000000042 missing
 0000000000000000000000000000000000000084 missing" = \
-    "$( ( echo 0000000000000000000000000000000000000042;
-	 echo_without_newline 0000000000000000000000000000000000000084; ) |
+    "$( ( echo 0000000000000000000000000000000000000042 &&
+	 echo_without_newline 0000000000000000000000000000000000000084 ) |
        git cat-file --batch-check)"
 '
 
@@ -226,8 +226,8 @@ test_expect_success "--batch for an existent and a non-existent hash" '
     test "$tag_sha1 tag $tag_size
 $tag_content
 0000000000000000000000000000000000000000 missing" = \
-    "$( ( echo $tag_sha1;
-	 echo_without_newline 0000000000000000000000000000000000000000; ) |
+    "$( ( echo $tag_sha1 &&
+	 echo_without_newline 0000000000000000000000000000000000000000 ) |
        git cat-file --batch)"
 '
 
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index bb9ef35dac..ed3952eb98 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -265,7 +265,7 @@ test_expect_success 'choking "git rm" should not let it die with cruft (induce S
 
 test_expect_success !MINGW 'choking "git rm" should not let it die with cruft (induce and check SIGPIPE)' '
 	choke_git_rm_setup &&
-	OUT=$( ((trap "" PIPE; git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&
+	OUT=$( ((trap "" PIPE && git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&
 	test_match_signal 13 "$OUT" &&
 	test_path_is_missing .git/index.lock
 '
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index 0335a9a158..520f96d09f 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -137,7 +137,7 @@ test_expect_success 'setup deeper work tree' '
 
 test_expect_success 'add a directory outside the work tree' '(
 	cd tester &&
-	d1="$(cd .. ; pwd)" &&
+	d1="$(cd .. && pwd)" &&
 	test_must_fail git add "$d1"
 )'
 
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (10 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:29   ` Jeff King
  2021-12-10  9:38   ` Fabian Stelzer
  2021-12-09  5:11 ` [PATCH 13/19] tests: apply modern idiom for signaling test failure Eric Sunshine
                   ` (8 subsequent siblings)
  20 siblings, 2 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

The top-level &&-chain checker built into t/test-lib.sh causes tests to
magically exit with code 117 if the &&-chain is broken. However, it has
the shortcoming that the magic does not work within `{...}` groups,
`(...)` subshells, `$(...)` substitutions, or within bodies of compound
statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
partly fills in the gap by catching broken &&-chains in `(...)`
subshells, but bugs can still lurk behind broken &&-chains in the other
cases.

Fix broken &&-chains in `{...}` groups in order to reduce the number of
possible lurking bugs.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t0021-conversion.sh                  |  8 ++++----
 t/t0069-oidtree.sh                     | 12 ++++++------
 t/t1006-cat-file.sh                    |  2 +-
 t/t1300-config.sh                      |  2 +-
 t/t1403-show-ref.sh                    |  8 ++++----
 t/t2200-add-update.sh                  | 12 ++++++------
 t/t2201-add-update-typechange.sh       | 10 +++++-----
 t/t4023-diff-rename-typechange.sh      |  6 +++---
 t/t4124-apply-ws-rule.sh               |  2 +-
 t/t4150-am.sh                          |  2 +-
 t/t4212-log-corrupt.sh                 |  8 ++++----
 t/t5316-pack-delta-depth.sh            |  7 +++++--
 t/t5510-fetch.sh                       |  2 +-
 t/t5515-fetch-merge-logic.sh           | 12 ++++++------
 t/t5562-http-backend-content-length.sh |  2 +-
 t/t5570-git-daemon.sh                  |  2 +-
 t/t5571-pre-push-hook.sh               |  2 +-
 t/t7513-interpret-trailers.sh          |  2 +-
 t/t8002-blame.sh                       |  2 +-
 19 files changed, 53 insertions(+), 50 deletions(-)

diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 1a1a69ad92..bb3de2701a 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -76,13 +76,13 @@ test_expect_success setup '
 	git config filter.rot13.clean ./rot13.sh &&
 
 	{
-	    echo "*.t filter=rot13"
+	    echo "*.t filter=rot13" &&
 	    echo "*.i ident"
 	} >.gitattributes &&
 
 	{
-	    echo a b c d e f g h i j k l m
-	    echo n o p q r s t u v w x y z
+	    echo a b c d e f g h i j k l m &&
+	    echo n o p q r s t u v w x y z &&
 	    echo '\''$Id$'\''
 	} >test &&
 	cat test >test.t &&
@@ -159,7 +159,7 @@ test_expect_success expanded_in_repo '
 		printf "\$Id: NoTerminatingSymbolAtEOF"
 	} >expected-output-crlf &&
 	{
-		echo "expanded-keywords ident"
+		echo "expanded-keywords ident" &&
 		echo "expanded-keywords-crlf ident text eol=crlf"
 	} >>.gitattributes &&
 
diff --git a/t/t0069-oidtree.sh b/t/t0069-oidtree.sh
index 74cc59bf8a..889db50818 100755
--- a/t/t0069-oidtree.sh
+++ b/t/t0069-oidtree.sh
@@ -28,7 +28,7 @@ test_expect_success 'oidtree insert and contains' '
 	EOF
 	{
 		echoid insert 444 1 2 3 4 5 a b c d e &&
-		echoid contains 44 441 440 444 4440 4444
+		echoid contains 44 441 440 444 4440 4444 &&
 		echo clear
 	} | test-tool oidtree >actual &&
 	test_cmp expect actual
@@ -37,11 +37,11 @@ test_expect_success 'oidtree insert and contains' '
 test_expect_success 'oidtree each' '
 	echoid "" 123 321 321 >expect &&
 	{
-		echoid insert f 9 8 123 321 a b c d e
-		echo each 12300
-		echo each 3211
-		echo each 3210
-		echo each 32100
+		echoid insert f 9 8 123 321 a b c d e &&
+		echo each 12300 &&
+		echo each 3211 &&
+		echo each 3210 &&
+		echo each 32100 &&
 		echo clear
 	} | test-tool oidtree >actual &&
 	test_cmp expect actual
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 67a3f64c2d..f6f00c7039 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -283,7 +283,7 @@ test_expect_success "--batch-check with multiple sha1s gives correct format" '
 
 test_expect_success 'setup blobs which are likely to delta' '
 	test-tool genrandom foo 10240 >foo &&
-	{ cat foo; echo plus; } >foo-plus &&
+	{ cat foo && echo plus; } >foo-plus &&
 	git add foo foo-plus &&
 	git commit -m foo &&
 	cat >blobs <<-\EOF
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 9571649c42..516dd8bfa8 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -901,7 +901,7 @@ test_expect_success 'get --expiry-date' '
 	EOF
 	: "work around heredoc parsing bug fixed in dash 0.5.7 (in ec2c84d)" &&
 	{
-		echo "$rel_out $(git config --expiry-date date.valid1)"
+		echo "$rel_out $(git config --expiry-date date.valid1)" &&
 		git config --expiry-date date.valid2 &&
 		git config --expiry-date date.valid3 &&
 		git config --expiry-date date.valid4 &&
diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
index 17d3cc1405..bbc01aae34 100755
--- a/t/t1403-show-ref.sh
+++ b/t/t1403-show-ref.sh
@@ -78,7 +78,7 @@ test_expect_success 'show-ref --verify -q' '
 test_expect_success 'show-ref -d' '
 	{
 		echo $(git rev-parse refs/tags/A) refs/tags/A &&
-		echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}"
+		echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}" &&
 		echo $(git rev-parse refs/tags/C) refs/tags/C
 	} >expect &&
 	git show-ref -d A C >actual &&
@@ -148,7 +148,7 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' '
 
 	{
 		echo $(git rev-parse HEAD) HEAD &&
-		echo $(git rev-parse refs/heads/B) refs/heads/B
+		echo $(git rev-parse refs/heads/B) refs/heads/B &&
 		echo $(git rev-parse refs/tags/B) refs/tags/B
 	} >expect &&
 	git show-ref --head B >actual &&
@@ -156,8 +156,8 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' '
 
 	{
 		echo $(git rev-parse HEAD) HEAD &&
-		echo $(git rev-parse refs/heads/B) refs/heads/B
-		echo $(git rev-parse refs/tags/B) refs/tags/B
+		echo $(git rev-parse refs/heads/B) refs/heads/B &&
+		echo $(git rev-parse refs/tags/B) refs/tags/B &&
 		echo $(git rev-parse refs/tags/B^0) "refs/tags/B^{}"
 	} >expect &&
 	git show-ref --head -d B >actual &&
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 67b9cc752f..d2ef0041f9 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -153,10 +153,10 @@ test_expect_success 'add -u resolves unmerged paths' '
 			echo "100644 $one 1	$path" &&
 			echo "100644 $two 2	$path" &&
 			echo "100644 $three 3	$path"
-		done
-		echo "100644 $one 1	path3"
-		echo "100644 $one 1	path4"
-		echo "100644 $one 3	path5"
+		done &&
+		echo "100644 $one 1	path3" &&
+		echo "100644 $one 1	path4" &&
+		echo "100644 $one 3	path5" &&
 		echo "100644 $one 3	path6"
 	} |
 	git update-index --index-info &&
@@ -173,8 +173,8 @@ test_expect_success 'add -u resolves unmerged paths' '
 	git add -u &&
 	git ls-files -s path1 path2 path3 path4 path5 path6 >actual &&
 	{
-		echo "100644 $three 0	path1"
-		echo "100644 $two 0	path3"
+		echo "100644 $three 0	path1" &&
+		echo "100644 $two 0	path3" &&
 		echo "100644 $two 0	path5"
 	} >expect &&
 	test_cmp expect actual
diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh
index a4eec0a346..687be974d4 100755
--- a/t/t2201-add-update-typechange.sh
+++ b/t/t2201-add-update-typechange.sh
@@ -97,17 +97,17 @@ test_expect_success modify '
 		"
 	} >expect &&
 	{
-		cat expect
-		echo ":100644 160000 $_empty $ZERO_OID T	yonk"
+		cat expect &&
+		echo ":100644 160000 $_empty $ZERO_OID T	yonk" &&
 		echo ":100644 000000 $_empty $ZERO_OID D	zifmia"
 	} >expect-files &&
 	{
-		cat expect
+		cat expect &&
 		echo ":000000 160000 $ZERO_OID $ZERO_OID A	yonk"
 	} >expect-index &&
 	{
-		echo "100644 $_empty 0	nitfol"
-		echo "160000 $yomin 0	yomin"
+		echo "100644 $_empty 0	nitfol" &&
+		echo "160000 $yomin 0	yomin" &&
 		echo "160000 $yonk 0	yonk"
 	} >expect-final
 '
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 47d6f35dcc..7cb9909293 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -55,7 +55,7 @@ test_expect_success 'cross renames to be detected for regular files' '
 
 	git diff-tree five six -r --name-status -B -M | sort >actual &&
 	{
-		echo "R100	foo	bar"
+		echo "R100	foo	bar" &&
 		echo "R100	bar	foo"
 	} | sort >expect &&
 	test_cmp expect actual
@@ -66,7 +66,7 @@ test_expect_success 'cross renames to be detected for typechange' '
 
 	git diff-tree one two -r --name-status -B -M | sort >actual &&
 	{
-		echo "R100	foo	bar"
+		echo "R100	foo	bar" &&
 		echo "R100	bar	foo"
 	} | sort >expect &&
 	test_cmp expect actual
@@ -78,7 +78,7 @@ test_expect_success 'moves and renames' '
 	git diff-tree three four -r --name-status -B -M | sort >actual &&
 	{
 		# see -B -M (#6) in t4008
-		echo "C100	foo	bar"
+		echo "C100	foo	bar" &&
 		echo "T100	foo"
 	} | sort >expect &&
 	test_cmp expect actual
diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index ebff6c6883..ec5c10d2a0 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -233,7 +233,7 @@ test_expect_success 'blank at EOF with --whitespace=fix (1)' '
 	test_write_lines a b c >one &&
 	git add one &&
 	test_write_lines a b c >expect &&
-	{ cat expect; echo; } >one &&
+	{ cat expect && echo; } >one &&
 	git diff -- one >patch &&
 
 	git checkout one &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 2aaaa0d7de..103cd39148 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -116,7 +116,7 @@ test_expect_success setup '
 		git format-patch --stdout first | sed -e "1d"
 	} | append_cr >patch1-crlf.eml &&
 	{
-		printf "%255s\\n" ""
+		printf "%255s\\n" "" &&
 		echo "X-Fake-Field: Line One" &&
 		echo "X-Fake-Field: Line Two" &&
 		echo "X-Fake-Field: Line Three" &&
diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh
index 03b952c90d..0244888a5a 100755
--- a/t/t4212-log-corrupt.sh
+++ b/t/t4212-log-corrupt.sh
@@ -20,10 +20,10 @@ test_expect_success 'fsck notices broken commit' '
 
 test_expect_success 'git log with broken author email' '
 	{
-		echo commit $(cat broken_email.hash)
-		echo "Author: A U Thor <author@example.com>"
-		echo "Date:   Thu Apr 7 15:13:13 2005 -0700"
-		echo
+		echo commit $(cat broken_email.hash) &&
+		echo "Author: A U Thor <author@example.com>" &&
+		echo "Date:   Thu Apr 7 15:13:13 2005 -0700" &&
+		echo &&
 		echo "    foo"
 	} >expect.out &&
 
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
index 759169d074..df524f7b6d 100755
--- a/t/t5316-pack-delta-depth.sh
+++ b/t/t5316-pack-delta-depth.sh
@@ -57,8 +57,11 @@ test_expect_success 'create series of packs' '
 		git commit -m $i &&
 		cur=$(git rev-parse HEAD^{tree}) &&
 		{
-			test -n "$prev" && echo "-$prev"
-			echo $cur
+			if test -n "$prev"
+			then
+				echo "-$prev"
+			fi &&
+			echo $cur &&
 			echo "$(git rev-parse :file) file"
 		} | git pack-objects --stdout >tmp &&
 		git index-pack --stdin --fix-thin <tmp || return 1
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 1892d6615a..01468ce6d8 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -71,7 +71,7 @@ test_expect_success "fetch test for-merge" '
 	main_in_two=$(cd ../two && git rev-parse main) &&
 	one_in_two=$(cd ../two && git rev-parse one) &&
 	{
-		echo "$one_in_two	"
+		echo "$one_in_two	" &&
 		echo "$main_in_two	not-for-merge"
 	} >expected &&
 	cut -f -2 .git/FETCH_HEAD >actual &&
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index 9d440e2821..c69cfd5c64 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -191,17 +191,17 @@ do
 		cp "$expect_r" expect_r &&
 		convert_expected expect_r sed_script &&
 		{
-			echo "# $cmd"
-			set x $cmd; shift
-			git symbolic-ref HEAD refs/heads/$1 ; shift
-			rm -f .git/FETCH_HEAD
+			echo "# $cmd" &&
+			set x $cmd && shift &&
+			git symbolic-ref HEAD refs/heads/$1 && shift &&
+			rm -f .git/FETCH_HEAD &&
 			git for-each-ref \
 				refs/heads refs/remotes/rem refs/tags |
 			while read val type refname
 			do
 				git update-ref -d "$refname" "$val"
-			done
-			git fetch "$@" >/dev/null
+			done &&
+			git fetch "$@" >/dev/null &&
 			cat .git/FETCH_HEAD
 		} >"$actual_f" &&
 		git show-ref >"$actual_r" &&
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index 05a58069b0..b68ec22d3f 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -63,7 +63,7 @@ test_expect_success 'setup' '
 	hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) &&
 	{
 		printf "%s %s refs/heads/newbranch\\0report-status object-format=%s\\n" \
-			"$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize_raw
+			"$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize_raw &&
 		printf 0000 &&
 		echo "$hash_next" | git pack-objects --stdout
 	} >push_body &&
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index b87ca06a58..1131503b76 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -194,7 +194,7 @@ test_expect_success 'hostname cannot break out of directory' '
 
 test_expect_success FAKENC 'hostname interpolation works after LF-stripping' '
 	{
-		printf "git-upload-pack /interp.git\n\0host=localhost" | packetize_raw
+		printf "git-upload-pack /interp.git\n\0host=localhost" | packetize_raw &&
 		printf "0000"
 	} >input &&
 	fake_nc "$GIT_DAEMON_HOST_PORT" <input >output &&
diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh
index b043a279f1..80e86d8284 100755
--- a/t/t5571-pre-push-hook.sh
+++ b/t/t5571-pre-push-hook.sh
@@ -114,7 +114,7 @@ test_expect_success 'push to URL' '
 
 test_expect_success 'set up many-ref tests' '
 	{
-		nr=1000
+		nr=1000 &&
 		while test $nr -lt 2000
 		do
 			nr=$(( $nr + 1 )) &&
diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
index 04885d0a5e..97f10905d2 100755
--- a/t/t7513-interpret-trailers.sh
+++ b/t/t7513-interpret-trailers.sh
@@ -156,7 +156,7 @@ test_expect_success 'with config option on the command line' '
 		Acked-by: Johan
 		Reviewed-by: Peff
 	EOF
-	{ echo; echo "Acked-by: Johan"; } |
+	{ echo && echo "Acked-by: Johan"; } |
 	git -c "trailer.Acked-by.ifexists=addifdifferent" interpret-trailers \
 		--trailer "Reviewed-by: Peff" --trailer "Acked-by: Johan" >actual &&
 	test_cmp expected actual
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index 5bb302b1ba..ee4fdd8f18 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -97,7 +97,7 @@ test_expect_success 'set up abbrev tests' '
 	test_commit abbrev &&
 	sha1=$(git rev-parse --verify HEAD) &&
 	check_abbrev () {
-		expect=$1; shift
+		expect=$1 && shift &&
 		echo $sha1 | cut -c 1-$expect >expect &&
 		git blame "$@" abbrev.t >actual &&
 		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 13/19] tests: apply modern idiom for signaling test failure
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (11 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:32   ` Jeff King
  2021-12-09  5:11 ` [PATCH 14/19] tests: apply modern idiom for exiting loop upon failure Eric Sunshine
                   ` (7 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Simplify the way these tests signal failure by employing the modern
idiom of making the `if` or `case` statement resolve to false when an
error is detected.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t2102-update-index-symlinks.sh | 2 +-
 t/t3402-rebase-merge.sh          | 8 ++++----
 t/t3700-add.sh                   | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/t/t2102-update-index-symlinks.sh b/t/t2102-update-index-symlinks.sh
index 22f2c730ae..9b11130ab9 100755
--- a/t/t2102-update-index-symlinks.sh
+++ b/t/t2102-update-index-symlinks.sh
@@ -25,7 +25,7 @@ test_expect_success \
 'the index entry must still be a symbolic link' '
 case "$(git ls-files --stage --cached symlink)" in
 120000" "*symlink) echo pass;;
-*) echo fail; git ls-files --stage --cached symlink; (exit 1);;
+*) echo fail; git ls-files --stage --cached symlink; false;;
 esac'
 
 test_done
diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
index cfde68f193..7e46f4ca85 100755
--- a/t/t3402-rebase-merge.sh
+++ b/t/t3402-rebase-merge.sh
@@ -68,7 +68,7 @@ test_expect_success 'merge and rebase should match' '
 	if test -s difference
 	then
 		cat difference
-		(exit 1)
+		false
 	else
 		echo happy
 	fi
@@ -102,7 +102,7 @@ test_expect_success 'merge and rebase should match' '
 	if test -s difference
 	then
 		cat difference
-		(exit 1)
+		false
 	else
 		echo happy
 	fi
@@ -117,7 +117,7 @@ test_expect_success 'picking rebase' '
 		echo happy
 	else
 		git show-branch
-		(exit 1)
+		false
 	fi &&
 	f=$(git diff-tree --name-only HEAD^ HEAD) &&
 	g=$(git diff-tree --name-only HEAD^^ HEAD^) &&
@@ -127,7 +127,7 @@ test_expect_success 'picking rebase' '
 	*)
 		echo "$f"
 		echo "$g"
-		(exit 1)
+		false
 	esac
 '
 
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 23c3c214c5..6902807ff8 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -177,7 +177,7 @@ test_expect_success 'git add --refresh' '
 	git read-tree HEAD &&
 	case "$(git diff-index HEAD -- foo)" in
 	:100644" "*"M	foo") echo pass;;
-	*) echo fail; (exit 1);;
+	*) echo fail; false;;
 	esac &&
 	git add --refresh -- foo &&
 	test -z "$(git diff-index HEAD -- foo)"
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 14/19] tests: apply modern idiom for exiting loop upon failure
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (12 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 13/19] tests: apply modern idiom for signaling test failure Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:36   ` Jeff King
  2021-12-09  5:11 ` [PATCH 15/19] tests: simplify by dropping unnecessary `for` loops Eric Sunshine
                   ` (6 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Rather than maintaining a flag indicating a failure within a loop and
aborting the test when the loop ends if the flag is set, modern practice
is to signal the failure immediately by exiting the loop early via
`return 1` (or `exit 1` if inside a subshell). Simplify these loops by
following the modern idiom.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t1050-large.sh                | 26 ++++++++------------------
 t/t5505-remote.sh               |  6 ++----
 t/t9400-git-cvsserver-server.sh |  5 ++---
 3 files changed, 12 insertions(+), 25 deletions(-)

diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index 99ff2866b7..0e4267c723 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -51,27 +51,21 @@ EOF
 test_expect_success 'add a large file or two' '
 	git add large1 huge large2 &&
 	# make sure we got a single packfile and no loose objects
-	bad= count=0 idx= &&
+	count=0 idx= &&
 	for p in .git/objects/pack/pack-*.pack
 	do
 		count=$(( $count + 1 )) &&
-		if test_path_is_file "$p" &&
-		   idx=${p%.pack}.idx && test_path_is_file "$idx"
-		then
-			continue
-		fi
-		bad=t
+		test_path_is_file "$p" &&
+		idx=${p%.pack}.idx &&
+		test_path_is_file "$idx" || return 1
 	done &&
-	test -z "$bad" &&
 	test $count = 1 &&
 	cnt=$(git show-index <"$idx" | wc -l) &&
 	test $cnt = 2 &&
 	for l in .git/objects/$OIDPATH_REGEX
 	do
-		test_path_is_file "$l" || continue
-		bad=t
+		test_path_is_missing "$l" || return 1
 	done &&
-	test -z "$bad" &&
 
 	# attempt to add another copy of the same
 	git add large3 &&
@@ -79,14 +73,10 @@ test_expect_success 'add a large file or two' '
 	for p in .git/objects/pack/pack-*.pack
 	do
 		count=$(( $count + 1 )) &&
-		if test_path_is_file "$p" &&
-		   idx=${p%.pack}.idx && test_path_is_file "$idx"
-		then
-			continue
-		fi
-		bad=t
+		test_path_is_file "$p" &&
+		idx=${p%.pack}.idx &&
+		test_path_is_file "$idx" || return 1
 	done &&
-	test -z "$bad" &&
 	test $count = 1
 '
 
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index e6e3c8f552..5ef8db481c 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1332,7 +1332,6 @@ test_expect_success 'unqualified <dst> refspec DWIM and advice' '
 	(
 		cd test &&
 		git tag -a -m "Some tag" some-tag main &&
-		exit_with=true &&
 		for type in commit tag tree blob
 		do
 			if test "$type" = "blob"
@@ -1348,9 +1347,8 @@ test_expect_success 'unqualified <dst> refspec DWIM and advice' '
 				push origin $oid:dst 2>err &&
 			test_i18ngrep "error: The destination you" err &&
 			test_i18ngrep ! "hint: Did you mean" err ||
-			exit_with=false
-		done &&
-		$exit_with
+			exit 1
+		done
 	)
 '
 
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 17f988edd2..a6a73effde 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -350,10 +350,9 @@ test_expect_success 'cvs update (subdirectories)' \
 	test_cmp "$dir/$filename" "../$dir/$filename"; then
         :
       else
-        echo >failure
+        exit 1
       fi
-    done) &&
-   test ! -f failure'
+    done)'
 
 cd "$WORKDIR"
 test_expect_success 'cvs update (delete file)' \
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 15/19] tests: simplify by dropping unnecessary `for` loops
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (13 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 14/19] tests: apply modern idiom for exiting loop upon failure Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09 16:50   ` Elijah Newren
  2021-12-09  5:11 ` [PATCH 16/19] t0000-t3999: detect and signal failure within loop Eric Sunshine
                   ` (5 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Rather than manually looping over a set of items and plugging those
items into a template string which is printed repeatedly, achieve the
same effect by taking advantage of `printf` which loops over its
arguments automatically.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t3005-ls-files-relative.sh      | 10 ++--------
 t/t3600-rm.sh                     |  5 +----
 t/t4025-hunk-header.sh            | 10 ++--------
 t/t4125-apply-ws-fuzz.sh          |  5 +----
 t/t6416-recursive-corner-cases.sh | 30 ++++++------------------------
 t/t7110-reset-merge.sh            |  2 +-
 t/t9400-git-cvsserver-server.sh   |  2 +-
 7 files changed, 14 insertions(+), 50 deletions(-)

diff --git a/t/t3005-ls-files-relative.sh b/t/t3005-ls-files-relative.sh
index 6ba8b589cd..fbfa210a50 100755
--- a/t/t3005-ls-files-relative.sh
+++ b/t/t3005-ls-files-relative.sh
@@ -39,10 +39,7 @@ test_expect_success 'ls-files with mixed levels' '
 test_expect_success 'ls-files -c' '
 	(
 		cd top/sub &&
-		for f in ../y*
-		do
-			echo "error: pathspec $SQ$f$SQ did not match any file(s) known to git"
-		done >expect.err &&
+		printf "error: pathspec $SQ%s$SQ did not match any file(s) known to git\n" ../y* >expect.err &&
 		echo "Did you forget to ${SQ}git add${SQ}?" >>expect.err &&
 		ls ../x* >expect.out &&
 		test_must_fail git ls-files -c --error-unmatch ../[xy]* >actual.out 2>actual.err &&
@@ -54,10 +51,7 @@ test_expect_success 'ls-files -c' '
 test_expect_success 'ls-files -o' '
 	(
 		cd top/sub &&
-		for f in ../x*
-		do
-			echo "error: pathspec $SQ$f$SQ did not match any file(s) known to git"
-		done >expect.err &&
+		printf "error: pathspec $SQ%s$SQ did not match any file(s) known to git\n" ../x* >expect.err &&
 		echo "Did you forget to ${SQ}git add${SQ}?" >>expect.err &&
 		ls ../y* >expect.out &&
 		test_must_fail git ls-files -o --error-unmatch ../[xy]* >actual.out 2>actual.err &&
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index ed3952eb98..e74a318ac3 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -274,10 +274,7 @@ test_expect_success 'Resolving by removal is not a warning-worthy event' '
 	git reset -q --hard &&
 	test_when_finished "rm -f .git/index.lock msg && git reset -q --hard" &&
 	blob=$(echo blob | git hash-object -w --stdin) &&
-	for stage in 1 2 3
-	do
-		echo "100644 $blob $stage	blob"
-	done | git update-index --index-info &&
+	printf "100644 $blob %d\tblob\n" 1 2 3 | git update-index --index-info &&
 	git rm blob >msg 2>&1 &&
 	test_i18ngrep ! "needs merge" msg &&
 	test_must_fail git ls-files -s --error-unmatch blob
diff --git a/t/t4025-hunk-header.sh b/t/t4025-hunk-header.sh
index 6356961de4..5397cb7d42 100755
--- a/t/t4025-hunk-header.sh
+++ b/t/t4025-hunk-header.sh
@@ -14,15 +14,9 @@ test_expect_success setup '
 
 	(
 		echo "A $NS" &&
-		for c in B C D E F G H I J K
-		do
-			echo "  $c"
-		done &&
+		printf "  %s\n" B C D E F G H I J K &&
 		echo "L  $NS" &&
-		for c in M N O P Q R S T U V
-		do
-			echo "  $c"
-		done
+		printf "  %s\n" M N O P Q R S T U V
 	) >file &&
 	git add file &&
 
diff --git a/t/t4125-apply-ws-fuzz.sh b/t/t4125-apply-ws-fuzz.sh
index 9671de7999..090987c89b 100755
--- a/t/t4125-apply-ws-fuzz.sh
+++ b/t/t4125-apply-ws-fuzz.sh
@@ -10,10 +10,7 @@ test_expect_success setup '
 	git add file &&
 
 	# file-0 is full of whitespace breakages
-	for l in a bb c d eeee f ggg h
-	do
-		echo "$l "
-	done >file-0 &&
+	printf "%s \n" a bb c d eeee f ggg h >file-0 &&
 
 	# patch-0 creates a whitespace broken file
 	cat file-0 >file &&
diff --git a/t/t6416-recursive-corner-cases.sh b/t/t6416-recursive-corner-cases.sh
index 84f5082366..690c8482b1 100755
--- a/t/t6416-recursive-corner-cases.sh
+++ b/t/t6416-recursive-corner-cases.sh
@@ -24,14 +24,8 @@ test_expect_success 'setup basic criss-cross + rename with no modifications' '
 		cd basic-rename &&
 
 		ten="0 1 2 3 4 5 6 7 8 9" &&
-		for i in $ten
-		do
-			echo line $i in a sample file
-		done >one &&
-		for i in $ten
-		do
-			echo line $i in another sample file
-		done >two &&
+		printf "line %d in a sample file\n" $ten >one &&
+		printf "line %d in another sample file\n" $ten >two &&
 		git add one two &&
 		test_tick && git commit -m initial &&
 
@@ -96,14 +90,8 @@ test_expect_success 'setup criss-cross + rename merges with basic modification'
 		cd rename-modify &&
 
 		ten="0 1 2 3 4 5 6 7 8 9" &&
-		for i in $ten
-		do
-			echo line $i in a sample file
-		done >one &&
-		for i in $ten
-		do
-			echo line $i in another sample file
-		done >two &&
+		printf "line %d in a sample file\n" $ten >one &&
+		printf "line %d in another sample file\n" $ten >two &&
 		git add one two &&
 		test_tick && git commit -m initial &&
 
@@ -1588,10 +1576,7 @@ test_expect_success 'setup nested conflicts' '
 		cd nested_conflicts &&
 
 		# Create some related files now
-		for i in $(test_seq 1 10)
-		do
-			echo Random base content line $i
-		done >initial &&
+		printf "Random base content line %d\n" $(test_seq 1 10) >initial &&
 
 		cp initial b_L1 &&
 		cp initial b_R1 &&
@@ -1777,10 +1762,7 @@ test_expect_success 'setup virtual merge base with nested conflicts' '
 		cd virtual_merge_base_has_nested_conflicts &&
 
 		# Create some related files now
-		for i in $(test_seq 1 10)
-		do
-			echo Random base content line $i
-		done >content &&
+		printf "Random base content line %d\n" $(test_seq 1 10) >content &&
 
 		# Setup original commit
 		git add content &&
diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh
index a82a07a04a..3d62e10b53 100755
--- a/t/t7110-reset-merge.sh
+++ b/t/t7110-reset-merge.sh
@@ -8,7 +8,7 @@ test_description='Tests for "git reset" with "--merge" and "--keep" options'
 . ./test-lib.sh
 
 test_expect_success setup '
-    for i in 1 2 3; do echo line $i; done >file1 &&
+    printf "line %d\n" 1 2 3 >file1 &&
     cat file1 >file2 &&
     git add file1 file2 &&
     test_tick &&
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index a6a73effde..a60fe2e19f 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -591,7 +591,7 @@ test_expect_success 'cvs annotate' '
     cd cvswork &&
     GIT_CONFIG="$git_config" cvs annotate merge >../out &&
     sed -e "s/ .*//" ../out >../actual &&
-    for i in 3 1 1 1 1 1 1 1 2 4; do echo 1.$i; done >../expect &&
+    printf "1.%d\n" 3 1 1 1 1 1 1 1 2 4 >../expect &&
     test_cmp ../expect ../actual
 '
 
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 16/19] t0000-t3999: detect and signal failure within loop
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (14 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 15/19] tests: simplify by dropping unnecessary `for` loops Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09  5:11 ` [PATCH 17/19] t4000-t4999: " Eric Sunshine
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Failures within `for` and `while` loops can go unnoticed if not detected
and signaled manually since the loop itself does not abort when a
contained command fails, nor will a failure necessarily be detected when
the loop finishes since the loop returns the exit code of the last
command it ran on the final iteration, which may not be the command
which failed. Therefore, detect and signal failures manually within
loops using the idiom `|| return 1` (or `|| exit 1` within subshells).

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/perf/p0100-globbing.sh            | 4 ++--
 t/perf/p1400-update-ref.sh          | 4 ++--
 t/perf/p1451-fsck-skip-list.sh      | 2 +-
 t/perf/p3400-rebase.sh              | 2 +-
 t/perf/p5302-pack-index.sh          | 2 +-
 t/perf/p5303-many-packs.sh          | 2 +-
 t/perf/p7519-fsmonitor.sh           | 8 ++++----
 t/t0008-ignores.sh                  | 2 +-
 t/t0011-hashmap.sh                  | 4 ++--
 t/t0021-conversion.sh               | 8 ++++----
 t/t0095-bloom.sh                    | 4 ++--
 t/t0410-partial-clone.sh            | 2 +-
 t/t1050-large.sh                    | 4 ++--
 t/t1091-sparse-checkout-builtin.sh  | 2 +-
 t/t1300-config.sh                   | 2 +-
 t/t1400-update-ref.sh               | 4 ++--
 t/t1403-show-ref.sh                 | 4 ++--
 t/t1410-reflog.sh                   | 4 ++--
 t/t1512-rev-parse-disambiguation.sh | 2 +-
 t/t2004-checkout-cache-temp.sh      | 4 ++--
 t/t2012-checkout-last.sh            | 4 ++--
 t/t2200-add-update.sh               | 2 +-
 t/t2203-add-intent.sh               | 2 +-
 t/t3202-show-branch.sh              | 8 ++++----
 t/t3303-notes-subtrees.sh           | 6 +++---
 t/t3305-notes-fanout.sh             | 4 ++--
 t/t3404-rebase-interactive.sh       | 4 ++--
 t/t3501-revert-cherry-pick.sh       | 2 +-
 t/t3508-cherry-pick-many-commits.sh | 2 +-
 t/t3700-add.sh                      | 2 +-
 t/t3920-crlf-messages.sh            | 4 ++--
 31 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/t/perf/p0100-globbing.sh b/t/perf/p0100-globbing.sh
index dd18a9ce2b..439e9c8e3c 100755
--- a/t/perf/p0100-globbing.sh
+++ b/t/perf/p0100-globbing.sh
@@ -19,9 +19,9 @@ test_expect_success 'setup' '
 		printf "a" >>refname &&
 		for j in $(test_seq 1 $i)
 		do
-			printf "a*" >>refglob.$i
+			printf "a*" >>refglob.$i || return 1
 		done &&
-		echo b >>refglob.$i
+		echo b >>refglob.$i || return 1
 	done &&
 	test_commit test $(cat refname).t "" $(cat refname).t
 '
diff --git a/t/perf/p1400-update-ref.sh b/t/perf/p1400-update-ref.sh
index dda8a74866..a75969cbb1 100755
--- a/t/perf/p1400-update-ref.sh
+++ b/t/perf/p1400-update-ref.sh
@@ -13,7 +13,7 @@ test_expect_success "setup" '
 	do
 		printf "start\ncreate refs/heads/%d PRE\ncommit\n" $i &&
 		printf "start\nupdate refs/heads/%d POST PRE\ncommit\n" $i &&
-		printf "start\ndelete refs/heads/%d POST\ncommit\n" $i
+		printf "start\ndelete refs/heads/%d POST\ncommit\n" $i || return 1
 	done >instructions
 '
 
@@ -22,7 +22,7 @@ test_perf "update-ref" '
 	do
 		git update-ref refs/heads/branch PRE &&
 		git update-ref refs/heads/branch POST PRE &&
-		git update-ref -d refs/heads/branch
+		git update-ref -d refs/heads/branch || return 1
 	done
 '
 
diff --git a/t/perf/p1451-fsck-skip-list.sh b/t/perf/p1451-fsck-skip-list.sh
index c2b97d2487..f767d834f2 100755
--- a/t/perf/p1451-fsck-skip-list.sh
+++ b/t/perf/p1451-fsck-skip-list.sh
@@ -15,7 +15,7 @@ test_expect_success "setup $n bad commits" '
 		echo "committer C <c@example.com> 1234567890 +0000" &&
 		echo "data <<EOF" &&
 		echo "$i.Q." &&
-		echo "EOF"
+		echo "EOF" || return 1
 	done | q_to_nul | git fast-import
 '
 
diff --git a/t/perf/p3400-rebase.sh b/t/perf/p3400-rebase.sh
index 43d5a34e8c..e6b0277729 100755
--- a/t/perf/p3400-rebase.sh
+++ b/t/perf/p3400-rebase.sh
@@ -22,7 +22,7 @@ test_expect_success 'setup rebasing on top of a lot of changes' '
 		git add unrelated-file$i &&
 		test_tick &&
 		git commit -m commit$i-reverse unrelated-file$i ||
-		break
+		return 1
 	done &&
 	git checkout to-rebase &&
 	test_commit our-patch interesting-file
diff --git a/t/perf/p5302-pack-index.sh b/t/perf/p5302-pack-index.sh
index 654cd9c86e..c16f6a3ff6 100755
--- a/t/perf/p5302-pack-index.sh
+++ b/t/perf/p5302-pack-index.sh
@@ -22,7 +22,7 @@ test_expect_success 'set up thread-counting tests' '
 	while test $t -gt 0
 	do
 		threads="$t $threads" &&
-		t=$((t / 2))
+		t=$((t / 2)) || return 1
 	done
 '
 
diff --git a/t/perf/p5303-many-packs.sh b/t/perf/p5303-many-packs.sh
index 58213fe171..af173a7b73 100755
--- a/t/perf/p5303-many-packs.sh
+++ b/t/perf/p5303-many-packs.sh
@@ -130,7 +130,7 @@ test_expect_success 'generate lots of packs' '
 		echo "data <<EOF" &&
 		echo "blob $i" &&
 		echo "EOF" &&
-		echo "checkpoint"
+		echo "checkpoint" || return 1
 	done |
 	git -c fastimport.unpackLimit=0 fast-import
 '
diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh
index 5eb5044a10..c8be58f3c7 100755
--- a/t/perf/p7519-fsmonitor.sh
+++ b/t/perf/p7519-fsmonitor.sh
@@ -119,10 +119,10 @@ test_expect_success "one time repo setup" '
 	fi &&
 
 	mkdir 1_file 10_files 100_files 1000_files 10000_files &&
-	for i in $(test_seq 1 10); do touch 10_files/$i; done &&
-	for i in $(test_seq 1 100); do touch 100_files/$i; done &&
-	for i in $(test_seq 1 1000); do touch 1000_files/$i; done &&
-	for i in $(test_seq 1 10000); do touch 10000_files/$i; done &&
+	for i in $(test_seq 1 10); do touch 10_files/$i || return 1; done &&
+	for i in $(test_seq 1 100); do touch 100_files/$i || return 1; done &&
+	for i in $(test_seq 1 1000); do touch 1000_files/$i || return 1; done &&
+	for i in $(test_seq 1 10000); do touch 10000_files/$i || return 1; done &&
 	git add 1_file 10_files 100_files 1000_files 10000_files &&
 	git commit -qm "Add files" &&
 
diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 42d2314804..5575dade8e 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -200,7 +200,7 @@ test_expect_success 'setup' '
 	do
 		: >$dir/not-ignored &&
 		: >$dir/ignored-and-untracked &&
-		: >$dir/ignored-but-in-index
+		: >$dir/ignored-but-in-index || return 1
 	done &&
 	git add -f ignored-but-in-index a/ignored-but-in-index &&
 	cat <<-\EOF >a/.gitignore &&
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
index e094975b13..1cb6aa6824 100755
--- a/t/t0011-hashmap.sh
+++ b/t/t0011-hashmap.sh
@@ -220,7 +220,7 @@ test_expect_success 'grow / shrink' '
 	for n in $(test_seq 51)
 	do
 		echo put key$n value$n >> in &&
-		echo NULL >> expect
+		echo NULL >> expect || return 1
 	done &&
 	echo size >> in &&
 	echo 64 51 >> expect &&
@@ -231,7 +231,7 @@ test_expect_success 'grow / shrink' '
 	for n in $(test_seq 12)
 	do
 		echo remove key$n >> in &&
-		echo value$n >> expect
+		echo value$n >> expect || return 1
 	done &&
 	echo size >> in &&
 	echo 256 40 >> expect &&
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index bb3de2701a..bad37abad2 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -285,7 +285,7 @@ test_expect_success 'required filter with absent smudge field' '
 test_expect_success 'filtering large input to small output should use little memory' '
 	test_config filter.devnull.clean "cat >/dev/null" &&
 	test_config filter.devnull.required true &&
-	for i in $(test_seq 1 30); do printf "%1048576d" 1; done >30MB &&
+	for i in $(test_seq 1 30); do printf "%1048576d" 1 || return 1; done >30MB &&
 	echo "30MB filter=devnull" >.gitattributes &&
 	GIT_MMAP_LIMIT=1m GIT_ALLOC_LIMIT=1m git add 30MB
 '
@@ -303,7 +303,7 @@ test_expect_success 'filter that does not read is fine' '
 test_expect_success EXPENSIVE 'filter large file' '
 	test_config filter.largefile.smudge cat &&
 	test_config filter.largefile.clean cat &&
-	for i in $(test_seq 1 2048); do printf "%1048576d" 1; done >2GB &&
+	for i in $(test_seq 1 2048); do printf "%1048576d" 1 || return 1; done >2GB &&
 	echo "2GB filter=largefile" >.gitattributes &&
 	git add 2GB 2>err &&
 	test_must_be_empty err &&
@@ -643,7 +643,7 @@ test_expect_success PERL 'required process filter should process multiple packet
 		for FILE in "$TEST_ROOT"/*.file
 		do
 			cp "$FILE" . &&
-			rot13.sh <"$FILE" >"$FILE.rot13"
+			rot13.sh <"$FILE" >"$FILE.rot13" || return 1
 		done &&
 
 		echo "*.file filter=protocol" >.gitattributes &&
@@ -682,7 +682,7 @@ test_expect_success PERL 'required process filter should process multiple packet
 
 		for FILE in *.file
 		do
-			test_cmp_committed_rot13 "$TEST_ROOT/$FILE" $FILE
+			test_cmp_committed_rot13 "$TEST_ROOT/$FILE" $FILE || return 1
 		done
 	)
 '
diff --git a/t/t0095-bloom.sh b/t/t0095-bloom.sh
index 7e4ab1795f..5945973552 100755
--- a/t/t0095-bloom.sh
+++ b/t/t0095-bloom.sh
@@ -84,7 +84,7 @@ test_expect_success 'get bloom filter for commit with 10 changes' '
 	mkdir smallDir &&
 	for i in $(test_seq 0 9)
 	do
-		echo $i >smallDir/$i
+		echo $i >smallDir/$i || return 1
 	done &&
 	git add smallDir &&
 	git commit -m "commit with 10 changes" &&
@@ -102,7 +102,7 @@ test_expect_success EXPENSIVE 'get bloom filter for commit with 513 changes' '
 	mkdir bigDir &&
 	for i in $(test_seq 0 511)
 	do
-		echo $i >bigDir/$i
+		echo $i >bigDir/$i || return 1
 	done &&
 	git add bigDir &&
 	git commit -m "commit with 513 changes" &&
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index c76485b1b6..f17abd298c 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -469,7 +469,7 @@ test_expect_success 'rev-list dies for missing objects on cmd line' '
 		git -C repo rev-list --ignore-missing --objects \
 			--exclude-promisor-objects "$OBJ" &&
 		git -C repo rev-list --ignore-missing --objects-edge-aggressive \
-			--exclude-promisor-objects "$OBJ"
+			--exclude-promisor-objects "$OBJ" || return 1
 	done
 '
 
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index 0e4267c723..4f3aa17c99 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -105,7 +105,7 @@ test_expect_success 'packsize limit' '
 		count=0 &&
 		for pi in .git/objects/pack/pack-*.idx
 		do
-			test_path_is_file "$pi" && count=$(( $count + 1 ))
+			test_path_is_file "$pi" && count=$(( $count + 1 )) || return 1
 		done &&
 		test $count = 2 &&
 
@@ -118,7 +118,7 @@ test_expect_success 'packsize limit' '
 
 		for pi in .git/objects/pack/pack-*.idx
 		do
-			git show-index <"$pi"
+			git show-index <"$pi" || return 1
 		done |
 		sed -e "s/^[0-9]* \([0-9a-f]*\) .*/\1/" |
 		sort >actual &&
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 272ba1b566..5d53dbfbde 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -586,7 +586,7 @@ test_expect_success 'pattern-checks: contained glob characters' '
 		!/*/
 		something$c-else/
 		EOF
-		check_read_tree_errors repo "a" "disabling cone pattern matching"
+		check_read_tree_errors repo "a" "disabling cone pattern matching" || return 1
 	done
 '
 
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 516dd8bfa8..50ee5dc828 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -718,7 +718,7 @@ test_expect_success bool '
 	for i in 1 2 3 4
 	do
 	    git config --bool --get bool.true$i >>result &&
-	    git config --bool --get bool.false$i >>result
+	    git config --bool --get bool.false$i >>result || return 1
 	done &&
 	test_cmp expect result'
 
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 0d4f73acaa..bd58c6c897 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -1368,7 +1368,7 @@ test_expect_success ULIMIT_FILE_DESCRIPTORS 'large transaction creating branches
 (
 	for i in $(test_seq 33)
 	do
-		echo "create refs/heads/$i HEAD"
+		echo "create refs/heads/$i HEAD" || exit 1
 	done >large_input &&
 	run_with_limited_open_files git update-ref --stdin <large_input &&
 	git rev-parse --verify -q refs/heads/33
@@ -1379,7 +1379,7 @@ test_expect_success ULIMIT_FILE_DESCRIPTORS 'large transaction deleting branches
 (
 	for i in $(test_seq 33)
 	do
-		echo "delete refs/heads/$i HEAD"
+		echo "delete refs/heads/$i HEAD" || exit 1
 	done >large_input &&
 	run_with_limited_open_files git update-ref --stdin <large_input &&
 	test_must_fail git rev-parse --verify -q refs/heads/33
diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
index bbc01aae34..405da58b75 100755
--- a/t/t1403-show-ref.sh
+++ b/t/t1403-show-ref.sh
@@ -123,14 +123,14 @@ test_expect_success 'show-ref -d' '
 test_expect_success 'show-ref --heads, --tags, --head, pattern' '
 	for branch in B main side
 	do
-		echo $(git rev-parse refs/heads/$branch) refs/heads/$branch
+		echo $(git rev-parse refs/heads/$branch) refs/heads/$branch || return 1
 	done >expect.heads &&
 	git show-ref --heads >actual &&
 	test_cmp expect.heads actual &&
 
 	for tag in A B C
 	do
-		echo $(git rev-parse refs/tags/$tag) refs/tags/$tag
+		echo $(git rev-parse refs/tags/$tag) refs/tags/$tag || return 1
 	done >expect.tags &&
 	git show-ref --tags >actual &&
 	test_cmp expect.tags actual &&
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index d42f067ff8..d7ddf7612d 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -349,12 +349,12 @@ test_expect_success SHA1 'parsing reverse reflogs at BUFSIZ boundaries' '
 		printf "$zf%02d $zf%02d %s\t" $i $(($i+1)) "$ident" &&
 		if test $i = 75; then
 			for j in $(test_seq 1 89); do
-				printf X
+				printf X || return 1
 			done
 		else
 			printf X
 		fi &&
-		printf "\n"
+		printf "\n" || return 1
 	done >.git/logs/refs/heads/reflogskip &&
 	git rev-parse reflogskip@{73} >actual &&
 	echo ${zf}03 >expect &&
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index 15188a408b..b0119bf8bc 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -381,7 +381,7 @@ test_expect_success 'ambiguous commits are printed by type first, then hash orde
 	do
 		grep $type objects >$type.objects &&
 		sort $type.objects >$type.objects.sorted &&
-		test_cmp $type.objects.sorted $type.objects
+		test_cmp $type.objects.sorted $type.objects || return 1
 	done
 '
 
diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh
index 9bb503a975..b16d69ca4a 100755
--- a/t/t2004-checkout-cache-temp.sh
+++ b/t/t2004-checkout-cache-temp.sh
@@ -57,7 +57,7 @@ test_expect_success 'checkout all stage 0 to temporary files' '
 		test $(grep $f actual | cut "-d	" -f2) = $f &&
 		p=$(grep $f actual | cut "-d	" -f1) &&
 		test -f $p &&
-		test $(cat $p) = tree1$f
+		test $(cat $p) = tree1$f || return 1
 	done
 '
 
@@ -85,7 +85,7 @@ test_expect_success 'checkout all stage 2 to temporary files' '
 		test $(grep $f actual | cut "-d	" -f2) = $f &&
 		p=$(grep $f actual | cut "-d	" -f1) &&
 		test -f $p &&
-		test $(cat $p) = tree2$f
+		test $(cat $p) = tree2$f || return 1
 	done
 '
 
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index 0e7d47ab31..42601d5a31 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -49,14 +49,14 @@ test_expect_success '"checkout -" detaches again' '
 test_expect_success 'more switches' '
 	for i in 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
 	do
-		git checkout -b branch$i
+		git checkout -b branch$i || return 1
 	done
 '
 
 more_switches () {
 	for i in 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
 	do
-		git checkout branch$i
+		git checkout branch$i || return 1
 	done
 }
 
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index d2ef0041f9..6993fcbe7a 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -152,7 +152,7 @@ test_expect_success 'add -u resolves unmerged paths' '
 		do
 			echo "100644 $one 1	$path" &&
 			echo "100644 $two 2	$path" &&
-			echo "100644 $three 3	$path"
+			echo "100644 $three 3	$path" || return 1
 		done &&
 		echo "100644 $one 1	path3" &&
 		echo "100644 $one 1	path4" &&
diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh
index cf0175ad6e..db7ca55998 100755
--- a/t/t2203-add-intent.sh
+++ b/t/t2203-add-intent.sh
@@ -116,7 +116,7 @@ test_expect_success 'cache-tree does not ignore dir that has i-t-a entries' '
 		mkdir 2 &&
 		for f in 1 2/1 2/2 3
 		do
-			echo "$f" >"$f"
+			echo "$f" >"$f" || return 1
 		done &&
 		git add 1 2/2 3 &&
 		git add -N 2/1 &&
diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh
index ad9902a06b..1e54a33103 100755
--- a/t/t3202-show-branch.sh
+++ b/t/t3202-show-branch.sh
@@ -9,7 +9,7 @@ test_expect_success 'setup' '
 	for i in $(test_seq 1 10)
 	do
 		git checkout -b branch$i initial &&
-		test_commit --no-tag branch$i
+		test_commit --no-tag branch$i || return 1
 	done &&
 	git for-each-ref \
 		--sort=version:refname \
@@ -49,7 +49,7 @@ test_expect_success 'show-branch with more than 8 branches' '
 test_expect_success 'show-branch with showbranch.default' '
 	for branch in $(cat branches.sorted)
 	do
-		test_config showbranch.default $branch --add
+		test_config showbranch.default $branch --add || return 1
 	done &&
 	git show-branch >actual &&
 	test_cmp expect actual
@@ -124,7 +124,7 @@ test_expect_success 'show branch --merge-base with one argument' '
 	do
 		git rev-parse $branch >expect &&
 		git show-branch --merge-base $branch >actual &&
-		test_cmp expect actual
+		test_cmp expect actual || return 1
 	done
 '
 
@@ -133,7 +133,7 @@ test_expect_success 'show branch --merge-base with two arguments' '
 	do
 		git rev-parse initial >expect &&
 		git show-branch --merge-base initial $branch >actual &&
-		test_cmp expect actual
+		test_cmp expect actual || return 1
 	done
 '
 
diff --git a/t/t3303-notes-subtrees.sh b/t/t3303-notes-subtrees.sh
index d47ce00f69..7ce056e617 100755
--- a/t/t3303-notes-subtrees.sh
+++ b/t/t3303-notes-subtrees.sh
@@ -30,7 +30,7 @@ verify_notes () {
 	while [ $i -gt 0 ]; do
 		echo "    commit #$i" &&
 		echo "    note for commit #$i" &&
-		i=$(($i-1));
+		i=$(($i-1)) || return 1
 	done > expect &&
 	test_cmp expect output
 }
@@ -42,7 +42,7 @@ test_expect_success "setup: create $number_of_commits commits" '
 		while [ $nr -lt $number_of_commits ]; do
 			nr=$(($nr+1)) &&
 			test_tick &&
-			cat <<INPUT_END
+			cat <<INPUT_END || return 1
 commit refs/heads/main
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 data <<COMMIT
@@ -178,7 +178,7 @@ verify_concatenated_notes () {
 		echo "    first note for commit #$i" &&
 		echo "    " &&
 		echo "    second note for commit #$i" &&
-		i=$(($i-1));
+		i=$(($i-1)) || return 1
 	done > expect &&
 	test_cmp expect output
 }
diff --git a/t/t3305-notes-fanout.sh b/t/t3305-notes-fanout.sh
index 94c1b02251..836b6f22bf 100755
--- a/t/t3305-notes-fanout.sh
+++ b/t/t3305-notes-fanout.sh
@@ -57,7 +57,7 @@ test_expect_success 'many notes created correctly with git-notes' '
 	do
 		echo "    commit #$i" &&
 		echo "    note #$i" &&
-		i=$(($i - 1));
+		i=$(($i - 1)) || return 1
 	done > expect &&
 	test_cmp expect output
 '
@@ -106,7 +106,7 @@ test_expect_success 'most notes deleted correctly with git-notes' '
 	do
 		echo "    commit #$i" &&
 		echo "    note #$i" &&
-		i=$(($i - 1));
+		i=$(($i - 1)) || return 1
 	done > expect &&
 	test_cmp expect output
 '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 12eb226957..f6a9890d66 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -826,7 +826,7 @@ test_expect_success 'always cherry-pick with --no-ff' '
 	do
 		test ! $(git rev-parse HEAD~$p) = $(git rev-parse original-no-ff-branch~$p) &&
 		git diff HEAD~$p original-no-ff-branch~$p > out &&
-		test_must_be_empty out
+		test_must_be_empty out || return 1
 	done &&
 	test_cmp_rev HEAD~3 original-no-ff-branch~3 &&
 	git diff HEAD~3 original-no-ff-branch~3 > out &&
@@ -1341,7 +1341,7 @@ test_expect_success 'rebase --continue removes CHERRY_PICK_HEAD' '
 		test_seq 5 | sed "s/$double/&&/" >seq &&
 		git add seq &&
 		test_tick &&
-		git commit -m seq-$double
+		git commit -m seq-$double || return 1
 	done &&
 	git tag seq-onto &&
 	git reset --hard HEAD~2 &&
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 4b5b607673..8617efaaf1 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -19,7 +19,7 @@ test_expect_success setup '
 
 	for l in a b c d e f g h i j k l m n o
 	do
-		echo $l$l$l$l$l$l$l$l$l
+		echo $l$l$l$l$l$l$l$l$l || return 1
 	done >oops &&
 
 	test_tick &&
diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh
index e8375d1c97..2d53ce754c 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -29,7 +29,7 @@ test_expect_success setup '
 		git add file1 &&
 		test_tick &&
 		git commit -m "$val" &&
-		git tag $val
+		git tag $val || return 1
 	done
 '
 
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 6902807ff8..b1f90ba325 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -143,7 +143,7 @@ test_expect_success 'git add with filemode=0, symlinks=0, and unmerged entries'
 	do
 		echo $s > stage$s &&
 		echo "100755 $(git hash-object -w stage$s) $s	file" &&
-		echo "120000 $(printf $s | git hash-object -w -t blob --stdin) $s	symlink"
+		echo "120000 $(printf $s | git hash-object -w -t blob --stdin) $s	symlink" || return 1
 	done | git update-index --index-info &&
 	git config core.filemode 0 &&
 	git config core.symlinks 0 &&
diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
index a8ad5462d9..0276edbe3d 100755
--- a/t/t3920-crlf-messages.sh
+++ b/t/t3920-crlf-messages.sh
@@ -70,7 +70,7 @@ test_crlf_subject_body_and_contents() {
 			for ref in ${LIB_CRLF_BRANCHES}
 			do
 				cat .crlf-${file}-\"\${ref}\".txt >>expect &&
-				printf \"\n\" >>expect
+				printf \"\n\" >>expect || return 1
 			done &&
 			git $command_and_args --format=\"%${atom}\" >actual &&
 			test_cmp expect actual
@@ -90,7 +90,7 @@ test_expect_success 'branch: --verbose works with messages using CRLF' '
 	do
 		printf "  " >>expect &&
 		cat .crlf-subject-${branch}.txt >>expect &&
-		printf "\n" >>expect
+		printf "\n" >>expect || return 1
 	done &&
 	git branch -v >tmp &&
 	# Remove first two columns, and the line for the currently checked out branch
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 17/19] t4000-t4999: detect and signal failure within loop
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (15 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 16/19] t0000-t3999: detect and signal failure within loop Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-10  9:53   ` Fabian Stelzer
  2021-12-09  5:11 ` [PATCH 18/19] t5000-t5999: " Eric Sunshine
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Failures within `for` and `while` loops can go unnoticed if not detected
and signaled manually since the loop itself does not abort when a
contained command fails, nor will a failure necessarily be detected when
the loop finishes since the loop returns the exit code of the last
command it ran on the final iteration, which may not be the command
which failed. Therefore, detect and signal failures manually within
loops using the idiom `|| return 1` (or `|| exit 1` within subshells).

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t4001-diff-rename.sh          |  2 +-
 t/t4012-diff-binary.sh          |  2 +-
 t/t4014-format-patch.sh         |  6 +++---
 t/t4015-diff-whitespace.sh      |  4 ++--
 t/t4018-diff-funcname.sh        |  2 +-
 t/t4024-diff-optimize-common.sh |  2 +-
 t/t4038-diff-combined.sh        |  2 +-
 t/t4046-diff-unmerged.sh        |  8 ++++----
 t/t4049-diff-stat-count.sh      |  2 +-
 t/t4052-stat-output.sh          |  2 +-
 t/t4057-diff-combined-paths.sh  | 16 ++++++++--------
 t/t4124-apply-ws-rule.sh        |  4 ++--
 t/t4138-apply-ws-expansion.sh   | 16 ++++++++--------
 t/t4205-log-pretty-formats.sh   |  2 +-
 t/t4211-line-log.sh             |  2 +-
 t/t4216-log-bloom.sh            |  4 ++--
 16 files changed, 38 insertions(+), 38 deletions(-)

diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index 68f2ebca58..3dc9047044 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -174,7 +174,7 @@ test_expect_success 'setup for many rename source candidates' '
 	do
 		for j in 0 1 2 3 4 5 6 7 8 9;
 		do
-			echo "$i$j" >"path$i$j"
+			echo "$i$j" >"path$i$j" || return 1
 		done
 	done &&
 	git add "path??" &&
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 33ff588ebc..b0f16ff5c0 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -122,7 +122,7 @@ test_expect_success 'diff --stat with binary files and big change count' '
 	i=0 &&
 	while test $i -lt 10000; do
 		echo $i &&
-		i=$(($i + 1))
+		i=$(($i + 1)) || return 1
 	done >textfile &&
 	git add textfile &&
 	git diff --cached --stat binfile textfile >output &&
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index eefe815fca..7dc5a5c736 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -325,7 +325,7 @@ test_expect_success 'filename length limit' '
 		max=$(
 			for patch in 000[1-9]-*.patch
 			do
-				echo "$patch" | wc -c
+				echo "$patch" | wc -c || exit 1
 			done |
 			sort -nr |
 			head -n 1
@@ -343,7 +343,7 @@ test_expect_success 'filename length limit from config' '
 		max=$(
 			for patch in 000[1-9]-*.patch
 			do
-				echo "$patch" | wc -c
+				echo "$patch" | wc -c || exit 1
 			done |
 			sort -nr |
 			head -n 1
@@ -361,7 +361,7 @@ test_expect_success 'filename limit applies only to basename' '
 		max=$(
 			for patch in patches/000[1-9]-*.patch
 			do
-				echo "${patch#patches/}" | wc -c
+				echo "${patch#patches/}" | wc -c || exit 1
 			done |
 			sort -nr |
 			head -n 1
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index 2c13b62d3c..ca5adabe14 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -843,7 +843,7 @@ test_expect_success 'whitespace changes with modification reported (diffstat)' '
 
 test_expect_success 'whitespace-only changes reported across renames (diffstat)' '
 	git reset --hard &&
-	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
+	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
 	git add x &&
 	git commit -m "base" &&
 	sed -e "5s/^/ /" x >z &&
@@ -859,7 +859,7 @@ test_expect_success 'whitespace-only changes reported across renames (diffstat)'
 
 test_expect_success 'whitespace-only changes reported across renames' '
 	git reset --hard HEAD~1 &&
-	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
+	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
 	git add x &&
 	hash_x=$(git hash-object x) &&
 	before=$(git rev-parse --short "$hash_x") &&
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 740696c8f7..42a2b9a13b 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -75,7 +75,7 @@ test_expect_success 'last regexp must not be negated' '
 test_expect_success 'setup hunk header tests' '
 	for i in $diffpatterns
 	do
-		echo "$i-* diff=$i"
+		echo "$i-* diff=$i" || return 1
 	done > .gitattributes &&
 
 	# add all test files to the index
diff --git a/t/t4024-diff-optimize-common.sh b/t/t4024-diff-optimize-common.sh
index 6b44ce1493..b98ac0a0c0 100755
--- a/t/t4024-diff-optimize-common.sh
+++ b/t/t4024-diff-optimize-common.sh
@@ -148,7 +148,7 @@ test_expect_success 'diff -U0' '
 
 	for n in $sample
 	do
-		git diff -U0 file-?$n
+		git diff -U0 file-?$n || return 1
 	done | zc >actual &&
 	test_cmp expect actual
 
diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh
index aeac203c42..9a292bac70 100755
--- a/t/t4038-diff-combined.sh
+++ b/t/t4038-diff-combined.sh
@@ -100,7 +100,7 @@ test_expect_success 'setup for --cc --raw' '
 	for i in $(test_seq 1 40)
 	do
 		blob=$(echo file$i | git hash-object --stdin -w) &&
-		trees="$trees$(echo "100644 blob $blob	file" | git mktree)$LF"
+		trees="$trees$(echo "100644 blob $blob	file" | git mktree)$LF" || return 1
 	done
 '
 
diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh
index 8c3d48e257..1828a72e0b 100755
--- a/t/t4046-diff-unmerged.sh
+++ b/t/t4046-diff-unmerged.sh
@@ -37,7 +37,7 @@ test_expect_success 'diff-files -0' '
 	for path in $paths
 	do
 		>"$path" &&
-		echo ":000000 100644 $ZERO_OID $ZERO_OID U	$path"
+		echo ":000000 100644 $ZERO_OID $ZERO_OID U	$path" || return 1
 	done >diff-files-0.expect &&
 	git diff-files -0 >diff-files-0.actual &&
 	test_cmp diff-files-0.expect diff-files-0.actual
@@ -50,7 +50,7 @@ test_expect_success 'diff-files -1' '
 		echo ":000000 100644 $ZERO_OID $ZERO_OID U	$path" &&
 		case "$path" in
 		x??) echo ":100644 100644 $blob1 $ZERO_OID M	$path"
-		esac
+		esac || return 1
 	done >diff-files-1.expect &&
 	git diff-files -1 >diff-files-1.actual &&
 	test_cmp diff-files-1.expect diff-files-1.actual
@@ -63,7 +63,7 @@ test_expect_success 'diff-files -2' '
 		echo ":000000 100644 $ZERO_OID $ZERO_OID U	$path" &&
 		case "$path" in
 		?x?) echo ":100644 100644 $blob2 $ZERO_OID M	$path"
-		esac
+		esac || return 1
 	done >diff-files-2.expect &&
 	git diff-files -2 >diff-files-2.actual &&
 	test_cmp diff-files-2.expect diff-files-2.actual &&
@@ -78,7 +78,7 @@ test_expect_success 'diff-files -3' '
 		echo ":000000 100644 $ZERO_OID $ZERO_OID U	$path" &&
 		case "$path" in
 		??x) echo ":100644 100644 $blob3 $ZERO_OID M	$path"
-		esac
+		esac || return 1
 	done >diff-files-3.expect &&
 	git diff-files -3 >diff-files-3.actual &&
 	test_cmp diff-files-3.expect diff-files-3.actual
diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh
index 53061b104e..e74baa0635 100755
--- a/t/t4049-diff-stat-count.sh
+++ b/t/t4049-diff-stat-count.sh
@@ -51,7 +51,7 @@ test_expect_success 'exclude unmerged entries from total file count' '
 	git rm -f d &&
 	for stage in 1 2 3
 	do
-		sed -e "s/ 0	a/ $stage	d/" x
+		sed -e "s/ 0	a/ $stage	d/" x || return 1
 	done |
 	git update-index --index-info &&
 	echo d >d &&
diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh
index 9eba436211..b5c281edaa 100755
--- a/t/t4052-stat-output.sh
+++ b/t/t4052-stat-output.sh
@@ -101,7 +101,7 @@ test_expect_success 'preparation for big change tests' '
 	i=0 &&
 	while test $i -lt 1000
 	do
-		echo $i && i=$(($i + 1))
+		echo $i && i=$(($i + 1)) || return 1
 	done >abcd &&
 	git commit -m message abcd
 '
diff --git a/t/t4057-diff-combined-paths.sh b/t/t4057-diff-combined-paths.sh
index 7e5b74f72e..04b8a1542a 100755
--- a/t/t4057-diff-combined-paths.sh
+++ b/t/t4057-diff-combined-paths.sh
@@ -18,13 +18,13 @@ test_expect_success 'trivial merge - combine-diff empty' '
 	for i in $(test_seq 1 9)
 	do
 		echo $i >$i.txt &&
-		git add $i.txt
+		git add $i.txt || return 1
 	done &&
 	git commit -m "init" &&
 	git checkout -b side &&
 	for i in $(test_seq 2 9)
 	do
-		echo $i/2 >>$i.txt
+		echo $i/2 >>$i.txt || return 1
 	done &&
 	git commit -a -m "side 2-9" &&
 	git checkout main &&
@@ -40,14 +40,14 @@ test_expect_success 'only one truly conflicting path' '
 	git checkout side &&
 	for i in $(test_seq 2 9)
 	do
-		echo $i/3 >>$i.txt
+		echo $i/3 >>$i.txt || return 1
 	done &&
 	echo "4side" >>4.txt &&
 	git commit -a -m "side 2-9 +4" &&
 	git checkout main &&
 	for i in $(test_seq 1 9)
 	do
-		echo $i/3 >>$i.txt
+		echo $i/3 >>$i.txt || return 1
 	done &&
 	echo "4main" >>4.txt &&
 	git commit -a -m "main 1-9 +4" &&
@@ -69,13 +69,13 @@ test_expect_success 'merge introduces new file' '
 	git checkout side &&
 	for i in $(test_seq 5 9)
 	do
-		echo $i/4 >>$i.txt
+		echo $i/4 >>$i.txt || return 1
 	done &&
 	git commit -a -m "side 5-9" &&
 	git checkout main &&
 	for i in $(test_seq 1 3)
 	do
-		echo $i/4 >>$i.txt
+		echo $i/4 >>$i.txt || return 1
 	done &&
 	git commit -a -m "main 1-3 +4hello" &&
 	git merge side &&
@@ -90,13 +90,13 @@ test_expect_success 'merge removed a file' '
 	git checkout side &&
 	for i in $(test_seq 5 9)
 	do
-		echo $i/5 >>$i.txt
+		echo $i/5 >>$i.txt || return 1
 	done &&
 	git commit -a -m "side 5-9" &&
 	git checkout main &&
 	for i in $(test_seq 1 3)
 	do
-		echo $i/4 >>$i.txt
+		echo $i/4 >>$i.txt || return 1
 	done &&
 	git commit -a -m "main 1-3" &&
 	git merge side &&
diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index ec5c10d2a0..485c7d2d12 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -333,7 +333,7 @@ test_expect_success 'applying beyond EOF requires one non-blank context line' '
 
 test_expect_success 'tons of blanks at EOF should not apply' '
 	for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
-		test_write_lines "" "" "" ""
+		test_write_lines "" "" "" "" || return 1
 	done >one &&
 	git add one &&
 	echo a >>one &&
@@ -396,7 +396,7 @@ test_expect_success 'shrink file with tons of missing blanks at end of file' '
 	test_write_lines a b c >one &&
 	cp one no-blank-lines &&
 	for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
-		test_write_lines "" "" "" ""
+		test_write_lines "" "" "" "" || return 1
 	done >>one &&
 	git add one &&
 	echo a >one &&
diff --git a/t/t4138-apply-ws-expansion.sh b/t/t4138-apply-ws-expansion.sh
index 4ba52bbb61..8bbf8260fa 100755
--- a/t/t4138-apply-ws-expansion.sh
+++ b/t/t4138-apply-ws-expansion.sh
@@ -30,7 +30,7 @@ test_expect_success setup '
 	while test $x -lt $n
 	do
 		printf "%63s%d\n" "" $x >>after &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 	printf "\t%s\n" d e f >>after &&
 	test_expect_code 1 git diff --no-index before after >patch2.patch.raw &&
@@ -41,7 +41,7 @@ test_expect_success setup '
 	while test $x -lt $n
 	do
 		printf "%63s%d\n" "" $x >>expect-2 &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 	printf "%64s\n" d e f >>expect-2 &&
 
@@ -53,7 +53,7 @@ test_expect_success setup '
 	while test $x -lt $n
 	do
 		printf "%63s%02d\n" "" $x >>after &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 	printf "\t%s\n" d e f >>after &&
 	test_expect_code 1 git diff --no-index before after >patch3.patch.raw &&
@@ -64,7 +64,7 @@ test_expect_success setup '
 	while test $x -lt $n
 	do
 		printf "%63s%02d\n" "" $x >>expect-3 &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 	printf "%64s\n" d e f >>expect-3 &&
 
@@ -74,7 +74,7 @@ test_expect_success setup '
 	while test $x -lt 50
 	do
 		printf "\t%02d\n" $x >>before &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 	cat before >after &&
 	printf "%64s\n" a b c >>after &&
@@ -82,7 +82,7 @@ test_expect_success setup '
 	do
 		printf "\t%02d\n" $x >>before &&
 		printf "\t%02d\n" $x >>after &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 	test_expect_code 1 git diff --no-index before after >patch4.patch.raw &&
 	sed -e "s/before/test-4/" -e "s/after/test-4/" patch4.patch.raw >patch4.patch &&
@@ -91,7 +91,7 @@ test_expect_success setup '
 	while test $x -lt 50
 	do
 		printf "%63s%02d\n" "" $x >>test-4 &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 	cat test-4 >expect-4 &&
 	printf "%64s\n" a b c >>expect-4 &&
@@ -99,7 +99,7 @@ test_expect_success setup '
 	do
 		printf "%63s%02d\n" "" $x >>test-4 &&
 		printf "%63s%02d\n" "" $x >>expect-4 &&
-		x=$(( $x + 1 ))
+		x=$(( $x + 1 )) || return 1
 	done &&
 
 	git config core.whitespace tab-in-indent,tabwidth=63 &&
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 5865daa8f8..f4ce7c59a4 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -976,7 +976,7 @@ test_expect_success '%(describe) vs git describe' '
 		else
 			: >expect-contains-bad
 		fi &&
-		echo "$hash $desc"
+		echo "$hash $desc" || return 1
 	done >expect &&
 	test_path_exists expect-contains-good &&
 	test_path_exists expect-contains-bad &&
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index 560127cc07..ac9e4d0928 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -137,7 +137,7 @@ test_expect_success 'range_set_union' '
 	test_seq 1000 > c.c &&
 	git add c.c &&
 	git commit -m "modify many lines" &&
-	git log $(for x in $(test_seq 200); do echo -L $((2*x)),+1:c.c; done)
+	git log $(for x in $(test_seq 200); do echo -L $((2*x)),+1:c.c || return 1; done)
 '
 
 test_expect_success '-s shows only line-log commits' '
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index 50f206db55..41355f038b 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -376,7 +376,7 @@ test_expect_success 'Bloom generation backfills empty commits' '
 		cd empty &&
 		for i in $(test_seq 1 6)
 		do
-			git commit --allow-empty -m "$i"
+			git commit --allow-empty -m "$i" || return 1
 		done &&
 
 		# Generate Bloom filters for empty commits 1-6, two at a time.
@@ -389,7 +389,7 @@ test_expect_success 'Bloom generation backfills empty commits' '
 			test_filter_computed 2 trace.event &&
 			test_filter_not_computed 4 trace.event &&
 			test_filter_trunc_empty 2 trace.event &&
-			test_filter_trunc_large 0 trace.event
+			test_filter_trunc_large 0 trace.event || return 1
 		done &&
 
 		# Finally, make sure that once all commits have filters, that
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 18/19] t5000-t5999: detect and signal failure within loop
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (16 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 17/19] t4000-t4999: " Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09  5:11 ` [PATCH 19/19] t6000-t9999: " Eric Sunshine
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Failures within `for` and `while` loops can go unnoticed if not detected
and signaled manually since the loop itself does not abort when a
contained command fails, nor will a failure necessarily be detected when
the loop finishes since the loop returns the exit code of the last
command it ran on the final iteration, which may not be the command
which failed. Therefore, detect and signal failures manually within
loops using the idiom `|| return 1` (or `|| exit 1` within subshells).

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 t/t5000-tar-tree.sh                    |  4 ++--
 t/t5003-archive-zip.sh                 |  2 +-
 t/t5004-archive-corner-cases.sh        |  6 +++---
 t/t5100-mailinfo.sh                    |  2 +-
 t/t5300-pack-object.sh                 |  6 +++---
 t/t5307-pack-missing-commit.sh         |  2 +-
 t/t5310-pack-bitmaps.sh                |  2 +-
 t/t5317-pack-objects-filter-objects.sh | 10 +++++-----
 t/t5318-commit-graph.sh                |  6 +++---
 t/t5319-multi-pack-index.sh            | 10 +++++-----
 t/t5322-pack-objects-sparse.sh         |  4 ++--
 t/t5325-reverse-index.sh               |  2 +-
 t/t5500-fetch-pack.sh                  |  8 ++++----
 t/t5502-quickfetch.sh                  |  2 +-
 t/t5510-fetch.sh                       |  2 +-
 t/t5515-fetch-merge-logic.sh           |  4 ++--
 t/t5552-skipping-fetch-negotiator.sh   | 10 +++++-----
 t/t5571-pre-push-hook.sh               |  2 +-
 t/t5616-partial-clone.sh               | 12 ++++++------
 t/t5702-protocol-v2.sh                 |  4 ++--
 20 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 2c88d1c159..7f8d2ab0a7 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -77,7 +77,7 @@ check_tar() {
 					path=$(get_pax_header $header path) &&
 					if test -n "$path"
 					then
-						mv "$data" "$path"
+						mv "$data" "$path" || exit 1
 					fi
 				fi
 			done
@@ -133,7 +133,7 @@ test_expect_success 'populate workdir' '
 		for depth in 1 2 3 4 5
 		do
 			mkdir $p &&
-			cd $p
+			cd $p || exit 1
 		done &&
 		echo text >file_with_long_path
 	) &&
diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh
index 1e6d18b140..d726964307 100755
--- a/t/t5003-archive-zip.sh
+++ b/t/t5003-archive-zip.sh
@@ -106,7 +106,7 @@ test_expect_success \
      printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
      printf "A not substituted O" >a/substfile2 &&
      (p=long_path_to_a_file && cd a &&
-      for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
+      for depth in 1 2 3 4 5; do mkdir $p && cd $p || exit 1; done &&
       echo text >file_with_long_path)
 '
 
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 2d32d0ed12..ae508e2162 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -131,7 +131,7 @@ test_expect_success ZIPINFO 'zip archive with many entries' '
 	do
 		for b in 0 1 2 3 4 5 6 7 8 9 a b c d e f
 		do
-			: >00/$a$b
+			: >00/$a$b || return 1
 		done
 	done &&
 	git add 00 &&
@@ -143,7 +143,7 @@ test_expect_success ZIPINFO 'zip archive with many entries' '
 	do
 		for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f
 		do
-			echo "040000 tree $subtree	$c$d"
+			echo "040000 tree $subtree	$c$d" || return 1
 		done
 	done >tree &&
 	tree=$(git mktree <tree) &&
@@ -171,7 +171,7 @@ test_expect_success EXPENSIVE,UNZIP,UNZIP_ZIP64_SUPPORT \
 	# create tree containing 65500 entries of that blob
 	for i in $(test_seq 1 65500)
 	do
-		echo "100644 blob $blob	$i"
+		echo "100644 blob $blob	$i" || return 1
 	done >tree &&
 	tree=$(git mktree <tree) &&
 
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 141b29f031..cebad1048c 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -122,7 +122,7 @@ test_expect_success 'mailinfo unescapes with --mboxrd' '
 	do
 		git mailinfo mboxrd/msg mboxrd/patch \
 		  <mboxrd/$i >mboxrd/out &&
-		test_cmp "$DATA/${i}mboxrd" mboxrd/msg
+		test_cmp "$DATA/${i}mboxrd" mboxrd/msg || return 1
 	done &&
 	sp=" " &&
 	echo "From " >expect &&
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index f9877d42d7..2fd845187e 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -347,7 +347,7 @@ test_expect_success 'unpacking with --strict' '
 		for i in 0 1 2 3 4 5 6 7 8 9
 		do
 			o=$(echo $j$i | git hash-object -w --stdin) &&
-			echo "100644 $o	0 $j$i"
+			echo "100644 $o	0 $j$i" || return 1
 		done
 	done >LIST &&
 	rm -f .git/index &&
@@ -390,7 +390,7 @@ test_expect_success 'index-pack with --strict' '
 		for i in 0 1 2 3 4 5 6 7 8 9
 		do
 			o=$(echo $j$i | git hash-object -w --stdin) &&
-			echo "100644 $o	0 $j$i"
+			echo "100644 $o	0 $j$i" || return 1
 		done
 	done >LIST &&
 	rm -f .git/index &&
@@ -586,7 +586,7 @@ test_expect_success 'setup for --stdin-packs tests' '
 		for id in A B C
 		do
 			git pack-objects .git/objects/pack/pack-$id \
-				--incremental --revs <<-EOF
+				--incremental --revs <<-EOF || exit 1
 			refs/tags/$id
 			EOF
 		done &&
diff --git a/t/t5307-pack-missing-commit.sh b/t/t5307-pack-missing-commit.sh
index f4338abb78..fa4bc269fe 100755
--- a/t/t5307-pack-missing-commit.sh
+++ b/t/t5307-pack-missing-commit.sh
@@ -11,7 +11,7 @@ test_expect_success setup '
 		git add "file$i" &&
 		test_tick &&
 		git commit -m "$i" &&
-		git tag "tag$i"
+		git tag "tag$i" || return 1
 	done &&
 	obj=$(git rev-parse --verify tag3) &&
 	fanout=$(expr "$obj" : "\(..\)") &&
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index dcf03d324a..783cd96290 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -230,7 +230,7 @@ test_expect_success 'pack reuse respects --honor-pack-keep' '
 	test_when_finished "rm -f .git/objects/pack/*.keep" &&
 	for i in .git/objects/pack/*.pack
 	do
-		>${i%.pack}.keep
+		>${i%.pack}.keep || return 1
 	done &&
 	reusable_pack --honor-pack-keep >empty.pack &&
 	git index-pack empty.pack &&
diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh
index 8fb6acae47..33b740ce62 100755
--- a/t/t5317-pack-objects-filter-objects.sh
+++ b/t/t5317-pack-objects-filter-objects.sh
@@ -18,7 +18,7 @@ test_expect_success 'setup r1' '
 	do
 		echo "This is file: $n" > r1/file.$n &&
 		git -C r1 add file.$n &&
-		git -C r1 commit -m "$n"
+		git -C r1 commit -m "$n" || return 1
 	done
 '
 
@@ -118,7 +118,7 @@ test_expect_success 'setup r2' '
 	do
 		printf "%"$n"s" X > r2/large.$n &&
 		git -C r2 add large.$n &&
-		git -C r2 commit -m "$n"
+		git -C r2 commit -m "$n" || return 1
 	done
 '
 
@@ -281,7 +281,7 @@ test_expect_success 'setup r3' '
 		echo "This is file: $n" > r3/$n &&
 		git -C r3 add $n &&
 		echo "This is file: dir1/$n" > r3/dir1/$n &&
-		git -C r3 add dir1/$n
+		git -C r3 add dir1/$n || return 1
 	done &&
 	git -C r3 commit -m "sparse" &&
 	echo dir1/ >pattern1 &&
@@ -334,7 +334,7 @@ test_expect_success 'setup r4' '
 		echo "This is file: $n" > r4/$n &&
 		git -C r4 add $n &&
 		echo "This is file: dir1/$n" > r4/dir1/$n &&
-		git -C r4 add dir1/$n
+		git -C r4 add dir1/$n || return 1
 	done &&
 	echo dir1/ >r4/pattern &&
 	git -C r4 add pattern &&
@@ -409,7 +409,7 @@ test_expect_success 'setup r1 - delete loose blobs' '
 
 	for id in `cat expected | sed "s|..|&/|"`
 	do
-		rm r1/.git/objects/$id
+		rm r1/.git/objects/$id || return 1
 	done
 '
 
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index f516fda7cc..edb728f77c 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -64,7 +64,7 @@ test_expect_success 'create commits and repack' '
 	for i in $(test_seq 3)
 	do
 		test_commit $i &&
-		git branch commits/$i
+		git branch commits/$i || return 1
 	done &&
 	git repack
 '
@@ -147,13 +147,13 @@ test_expect_success 'Add more commits' '
 	for i in $(test_seq 4 5)
 	do
 		test_commit $i &&
-		git branch commits/$i
+		git branch commits/$i || return 1
 	done &&
 	git reset --hard commits/2 &&
 	for i in $(test_seq 6 7)
 	do
 		test_commit $i &&
-		git branch commits/$i
+		git branch commits/$i || return 1
 	done &&
 	git reset --hard commits/2 &&
 	git merge commits/4 &&
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 3f69e43178..86b0372dc8 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -93,7 +93,7 @@ test_expect_success 'create objects' '
 	test_commit initial &&
 	for i in $(test_seq 1 5)
 	do
-		generate_objects $i
+		generate_objects $i || return 1
 	done &&
 	commit_and_list_objects
 '
@@ -155,7 +155,7 @@ test_expect_success 'corrupt idx reports errors' '
 test_expect_success 'add more objects' '
 	for i in $(test_seq 6 10)
 	do
-		generate_objects $i
+		generate_objects $i || return 1
 	done &&
 	commit_and_list_objects
 '
@@ -203,7 +203,7 @@ test_expect_success 'add more packs' '
 	do
 		generate_objects $j &&
 		commit_and_list_objects &&
-		git pack-objects --index-version=2 $objdir/pack/test-pack <obj-list
+		git pack-objects --index-version=2 $objdir/pack/test-pack <obj-list || return 1
 	done
 '
 
@@ -594,7 +594,7 @@ test_expect_success 'force some 64-bit offsets with pack-objects' '
 	mkdir objects64/pack &&
 	for i in $(test_seq 1 11)
 	do
-		generate_objects 11
+		generate_objects 11 || return 1
 	done &&
 	commit_and_list_objects &&
 	pack64=$(git pack-objects --index-version=2,0x40 objects64/pack/test-64 <obj-list) &&
@@ -638,7 +638,7 @@ test_expect_success 'setup expire tests' '
 		git update-index --add large_file.txt &&
 		for i in $(test_seq 1 20)
 		do
-			test_commit $i
+			test_commit $i || exit 1
 		done &&
 		git branch A HEAD &&
 		git branch B HEAD~8 &&
diff --git a/t/t5322-pack-objects-sparse.sh b/t/t5322-pack-objects-sparse.sh
index 61cb907a90..d39958c066 100755
--- a/t/t5322-pack-objects-sparse.sh
+++ b/t/t5322-pack-objects-sparse.sh
@@ -14,7 +14,7 @@ test_expect_success 'setup repo' '
 		for j in $(test_seq 1 3)
 		do
 			mkdir f$i/f$j &&
-			echo $j >f$i/f$j/data.txt
+			echo $j >f$i/f$j/data.txt || return 1
 		done
 	done &&
 	git add . &&
@@ -23,7 +23,7 @@ test_expect_success 'setup repo' '
 	do
 		git checkout -b topic$i main &&
 		echo change-$i >f$i/f$i/data.txt &&
-		git commit -a -m "Changed f$i/f$i/data.txt"
+		git commit -a -m "Changed f$i/f$i/data.txt" || return 1
 	done &&
 	cat >packinput.txt <<-EOF &&
 	topic1
diff --git a/t/t5325-reverse-index.sh b/t/t5325-reverse-index.sh
index da453f68d6..d042d26f2b 100755
--- a/t/t5325-reverse-index.sh
+++ b/t/t5325-reverse-index.sh
@@ -46,7 +46,7 @@ test_expect_success 'index-pack with --[no-]rev-index' '
 		test_path_exists $rev &&
 
 		test_index_pack "$conf" --no-rev-index &&
-		test_path_is_missing $rev
+		test_path_is_missing $rev || return 1
 	done
 '
 
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 8a5d3492c7..f0dc4e6968 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -95,7 +95,7 @@ test_expect_success 'setup' '
 	while [ $cur -le 10 ]; do
 		add A$cur $(eval echo \$A$prev) &&
 		prev=$cur &&
-		cur=$(($cur+1))
+		cur=$(($cur+1)) || return 1
 	done &&
 	add B1 $A1 &&
 	git update-ref refs/heads/A "$ATIP" &&
@@ -112,7 +112,7 @@ test_expect_success 'post 1st pull setup' '
 	while [ $cur -le 65 ]; do
 		add B$cur $(eval echo \$B$prev) &&
 		prev=$cur &&
-		cur=$(($cur+1))
+		cur=$(($cur+1)) || return 1
 	done
 '
 
@@ -464,11 +464,11 @@ test_expect_success 'fetch creating new shallow root' '
 test_expect_success 'setup tests for the --stdin parameter' '
 	for head in C D E F
 	do
-		add $head
+		add $head || return 1
 	done &&
 	for head in A B C D E F
 	do
-		git tag $head $head
+		git tag $head $head || return 1
 	done &&
 	cat >input <<-\EOF &&
 	refs/heads/C
diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh
index 8c05c7715b..b160f8b7fb 100755
--- a/t/t5502-quickfetch.sh
+++ b/t/t5502-quickfetch.sh
@@ -130,7 +130,7 @@ test_expect_success 'quickfetch should handle ~1000 refs (on Windows)' '
 	for i in 0 1 2 3 4 5 6 7 8 9; do
 		for j in 0 1 2 3 4 5 6 7 8 9; do
 			for k in 0 1 2 3 4 5 6 7 8 9; do
-				echo "$branchprefix$i$j$k" >> .git/packed-refs
+				echo "$branchprefix$i$j$k" >> .git/packed-refs || return 1
 			done
 		done
 	done &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 01468ce6d8..ce18c20acd 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -550,7 +550,7 @@ test_expect_success 'bundle should record HEAD correctly' '
 	git bundle list-heads bundle5 >actual &&
 	for h in HEAD refs/heads/main
 	do
-		echo "$(git rev-parse --verify $h) $h"
+		echo "$(git rev-parse --verify $h) $h" || return 1
 	done >expect &&
 	test_cmp expect actual
 
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index c69cfd5c64..320d26796d 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -133,7 +133,7 @@ test_expect_success setup '
 		git config branch.br-$remote-merge.merge refs/heads/three &&
 		git config branch.br-$remote-octopus.remote $remote &&
 		git config branch.br-$remote-octopus.merge refs/heads/one &&
-		git config --add branch.br-$remote-octopus.merge two
+		git config --add branch.br-$remote-octopus.merge two || return 1
 	done &&
 	build_script sed_script
 '
@@ -199,7 +199,7 @@ do
 				refs/heads refs/remotes/rem refs/tags |
 			while read val type refname
 			do
-				git update-ref -d "$refname" "$val"
+				git update-ref -d "$refname" "$val" || return 1
 			done &&
 			git fetch "$@" >/dev/null &&
 			cat .git/FETCH_HEAD
diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh
index 7b9fb4ff02..165427d57e 100755
--- a/t/t5552-skipping-fetch-negotiator.sh
+++ b/t/t5552-skipping-fetch-negotiator.sh
@@ -48,7 +48,7 @@ test_expect_success 'commits with no parents are sent regardless of skip distanc
 	git init client &&
 	for i in $(test_seq 7)
 	do
-		test_commit -C client c$i
+		test_commit -C client c$i || return 1
 	done &&
 
 	# We send: "c7" (skip 1) "c5" (skip 2) "c2" (skip 4). After that, since
@@ -68,7 +68,7 @@ test_expect_success 'when two skips collide, favor the larger one' '
 	git init client &&
 	for i in $(test_seq 11)
 	do
-		test_commit -C client c$i
+		test_commit -C client c$i || return 1
 	done &&
 	git -C client checkout c5 &&
 	test_commit -C client c5side &&
@@ -155,14 +155,14 @@ test_expect_success 'do not send "have" with ancestors of commits that server AC
 	for i in $(test_seq 8)
 	do
 		git -C client checkout --orphan b$i &&
-		test_commit -C client b$i.c0
+		test_commit -C client b$i.c0 || return 1
 	done &&
 	for j in $(test_seq 19)
 	do
 		for i in $(test_seq 8)
 		do
 			git -C client checkout b$i &&
-			test_commit -C client b$i.c$j
+			test_commit -C client b$i.c$j || return 1
 		done
 	done &&
 
@@ -201,7 +201,7 @@ test_expect_success 'do not send "have" with ancestors of commits that server AC
 	# should still send the others (in this test, just check b2).
 	for i in $(test_seq 0 8)
 	do
-		have_not_sent b1.c$i
+		have_not_sent b1.c$i || return 1
 	done &&
 	have_sent b2.c1 b2.c0
 '
diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh
index 80e86d8284..660f876eec 100755
--- a/t/t5571-pre-push-hook.sh
+++ b/t/t5571-pre-push-hook.sh
@@ -118,7 +118,7 @@ test_expect_success 'set up many-ref tests' '
 		while test $nr -lt 2000
 		do
 			nr=$(( $nr + 1 )) &&
-			echo "create refs/heads/b/$nr $COMMIT3"
+			echo "create refs/heads/b/$nr $COMMIT3" || return 1
 		done
 	} | git update-ref --stdin
 '
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 23c156e399..34469b6ac1 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -19,7 +19,7 @@ test_expect_success 'setup normal src repo' '
 		echo "This is file: $n" > src/file.$n.txt &&
 		git -C src add file.$n.txt &&
 		git -C src commit -m "file $n" &&
-		git -C src ls-files -s file.$n.txt >>temp
+		git -C src ls-files -s file.$n.txt >>temp || return 1
 	done &&
 	awk -f print_2.awk <temp | sort >expect_1.oids &&
 	test_line_count = 4 expect_1.oids
@@ -74,7 +74,7 @@ test_expect_success 'push new commits to server' '
 	do
 		echo "Mod file.1.txt $x" >>src/file.1.txt &&
 		git -C src add file.1.txt &&
-		git -C src commit -m "mod $x"
+		git -C src commit -m "mod $x" || return 1
 	done &&
 	git -C src blame main -- file.1.txt >expect.blame &&
 	git -C src push -u srv main
@@ -116,7 +116,7 @@ test_expect_success 'push new commits to server for file.2.txt' '
 	do
 		echo "Mod file.2.txt $x" >>src/file.2.txt &&
 		git -C src add file.2.txt &&
-		git -C src commit -m "mod $x"
+		git -C src commit -m "mod $x" || return 1
 	done &&
 	git -C src push -u srv main
 '
@@ -137,7 +137,7 @@ test_expect_success 'push new commits to server for file.3.txt' '
 	do
 		echo "Mod file.3.txt $x" >>src/file.3.txt &&
 		git -C src add file.3.txt &&
-		git -C src commit -m "mod $x"
+		git -C src commit -m "mod $x" || return 1
 	done &&
 	git -C src push -u srv main
 '
@@ -385,7 +385,7 @@ setup_triangle () {
 	for i in $(test_seq 1 100)
 	do
 		echo "make the tree big" >server/file$i &&
-		git -C server add file$i
+		git -C server add file$i || return 1
 	done &&
 	git -C server commit -m "initial" &&
 	git clone --bare --filter=tree:0 "file://$(pwd)/server" client &&
@@ -669,7 +669,7 @@ test_expect_success 'tolerate server sending REF_DELTA against missing promisor
 	for i in $(test_seq 10)
 	do
 		echo "this is a line" >>"$SERVER/foo.txt" &&
-		echo "this is another line" >>"$SERVER/have.txt"
+		echo "this is another line" >>"$SERVER/have.txt" || return 1
 	done &&
 	git -C "$SERVER" add foo.txt have.txt &&
 	git -C "$SERVER" commit -m bar &&
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index d527cf6c49..ed8a071961 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -747,7 +747,7 @@ test_expect_success 'clone big repository with http:// using protocol v2' '
 		echo "data 0" &&
 		echo "M 644 inline bla.txt" &&
 		echo "data 4" &&
-		echo "bla"
+		echo "bla" || return 1
 	done | git -C "$HTTPD_DOCUMENT_ROOT_PATH/big" fast-import &&
 
 	GIT_TRACE_PACKET="$(pwd)/log" GIT_TRACE_CURL="$(pwd)/log" git \
@@ -942,7 +942,7 @@ test_expect_success 'part of packfile response provided as URI' '
 			then
 				>h2found
 			fi
-		fi
+		fi || return 1
 	done &&
 	test -f hfound &&
 	test -f h2found &&
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 19/19] t6000-t9999: detect and signal failure within loop
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (17 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 18/19] t5000-t5999: " Eric Sunshine
@ 2021-12-09  5:11 ` Eric Sunshine
  2021-12-09 17:02 ` [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Elijah Newren
  2021-12-11  9:58 ` [PATCH v1.1 2/19] t1010: fix unnoticed failure on Windows Eric Sunshine
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09  5:11 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Eric Sunshine

Failures within `for` and `while` loops can go unnoticed if not detected
and signaled manually since the loop itself does not abort when a
contained command fails, nor will a failure necessarily be detected when
the loop finishes since the loop returns the exit code of the last
command it ran on the final iteration, which may not be the command
which failed. Therefore, detect and signal failures manually within
loops using the idiom `|| return 1` (or `|| exit 1` within subshells).

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 contrib/mw-to-git/t/t9365-continuing-queries.sh |  2 +-
 t/annotate-tests.sh                             |  2 +-
 t/t6005-rev-list-count.sh                       |  2 +-
 t/t6009-rev-list-parent.sh                      |  4 ++--
 t/t6101-rev-parse-parents.sh                    |  2 +-
 t/t6112-rev-list-filters-objects.sh             |  8 ++++----
 t/t6120-describe.sh                             |  6 +++---
 t/t6132-pathspec-exclude.sh                     |  2 +-
 t/t6200-fmt-merge-msg.sh                        |  2 +-
 t/t6300-for-each-ref.sh                         |  2 +-
 t/t6412-merge-large-rename.sh                   |  8 ++++----
 t/t6430-merge-recursive.sh                      |  2 +-
 t/t6600-test-reach.sh                           |  4 ++--
 t/t7004-tag.sh                                  |  2 +-
 t/t7505-prepare-commit-msg-hook.sh              |  2 +-
 t/t7600-merge.sh                                |  2 +-
 t/t7602-merge-octopus-many.sh                   |  2 +-
 t/t7603-merge-reduce-heads.sh                   |  4 ++--
 t/t7700-repack.sh                               |  2 +-
 t/t8014-blame-ignore-fuzzy.sh                   |  4 ++--
 t/t9104-git-svn-follow-parent.sh                |  4 ++--
 t/t9130-git-svn-authors-file.sh                 |  4 ++--
 t/t9134-git-svn-ignore-paths.sh                 | 16 ++++++++--------
 t/t9138-git-svn-authors-prog.sh                 |  2 +-
 t/t9146-git-svn-empty-dirs.sh                   |  4 ++--
 t/t9147-git-svn-include-paths.sh                | 16 ++++++++--------
 t/t9152-svn-empty-dirs-after-gc.sh              |  2 +-
 t/t9304-fast-import-marks.sh                    |  2 +-
 t/t9400-git-cvsserver-server.sh                 |  4 ++--
 t/t9800-git-p4-basic.sh                         |  2 +-
 t/t9818-git-p4-block.sh                         |  6 +++---
 t/t9902-completion.sh                           |  4 ++--
 32 files changed, 65 insertions(+), 65 deletions(-)

diff --git a/contrib/mw-to-git/t/t9365-continuing-queries.sh b/contrib/mw-to-git/t/t9365-continuing-queries.sh
index 016454749f..d3e7312659 100755
--- a/contrib/mw-to-git/t/t9365-continuing-queries.sh
+++ b/contrib/mw-to-git/t/t9365-continuing-queries.sh
@@ -12,7 +12,7 @@ test_expect_success 'creating page w/ >500 revisions' '
 	for i in $(test_seq 501)
 	do
 		echo "creating revision $i" &&
-		wiki_editpage foo "revision $i<br/>" true
+		wiki_editpage foo "revision $i<br/>" true || return 1
 	done
 '
 
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index d3b299e75c..09e86f9ba0 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -161,7 +161,7 @@ test_expect_success 'blame huge graft' '
 			GIT_AUTHOR_NAME=$i$j GIT_AUTHOR_EMAIL=$i$j@test.git \
 			git commit -a -m "$i$j" &&
 			commit=$(git rev-parse --verify HEAD) &&
-			graft="$graft$commit "
+			graft="$graft$commit " || return 1
 		done
 	done &&
 	printf "%s " $graft >.git/info/grafts &&
diff --git a/t/t6005-rev-list-count.sh b/t/t6005-rev-list-count.sh
index 32b152095a..06d801032b 100755
--- a/t/t6005-rev-list-count.sh
+++ b/t/t6005-rev-list-count.sh
@@ -8,7 +8,7 @@ test_expect_success 'setup' '
     for n in 1 2 3 4 5 ; do
         echo $n > a &&
         git add a &&
-        git commit -m "$n"
+        git commit -m "$n" || return 1
     done
 '
 
diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh
index dc8160aa45..5a67bbc760 100755
--- a/t/t6009-rev-list-parent.sh
+++ b/t/t6009-rev-list-parent.sh
@@ -124,7 +124,7 @@ test_expect_success 'dodecapus' '
 		git checkout -b root$i five &&
 		test_commit $i &&
 		roots="$roots root$i" ||
-		return
+		return 1
 	done &&
 	git checkout main &&
 	test_tick &&
@@ -143,7 +143,7 @@ test_expect_success 'ancestors with the same commit time' '
 	test_tick_keep=$test_tick &&
 	for i in 1 2 3 4 5 6 7 8; do
 		test_tick=$test_tick_keep &&
-		test_commit t$i
+		test_commit t$i || return 1
 	done &&
 	git rev-list t1^! --not t$i >result &&
 	test_must_be_empty result
diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
index 78b5851780..c571fa5179 100755
--- a/t/t6101-rev-parse-parents.sh
+++ b/t/t6101-rev-parse-parents.sh
@@ -32,7 +32,7 @@ test_expect_success 'setup' '
 		test_tick &&
 		git commit --allow-empty -m "$i" &&
 		commit=$(git rev-parse --verify HEAD) &&
-		printf "$commit " >>.git/info/grafts
+		printf "$commit " >>.git/info/grafts || return 1
 	done
 '
 
diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh
index 9848425192..8d9d6604f0 100755
--- a/t/t6112-rev-list-filters-objects.sh
+++ b/t/t6112-rev-list-filters-objects.sh
@@ -18,7 +18,7 @@ test_expect_success 'setup r1' '
 	do
 		echo "This is file: $n" > r1/file.$n &&
 		git -C r1 add file.$n &&
-		git -C r1 commit -m "$n"
+		git -C r1 commit -m "$n" || return 1
 	done
 '
 
@@ -75,7 +75,7 @@ test_expect_success 'setup r2' '
 	do
 		printf "%"$n"s" X > r2/large.$n &&
 		git -C r2 add large.$n &&
-		git -C r2 commit -m "$n"
+		git -C r2 commit -m "$n" || return 1
 	done
 '
 
@@ -248,7 +248,7 @@ test_expect_success 'setup r3' '
 		echo "This is file: $n" > r3/$n &&
 		git -C r3 add $n &&
 		echo "This is file: dir1/$n" > r3/dir1/$n &&
-		git -C r3 add dir1/$n
+		git -C r3 add dir1/$n || return 1
 	done &&
 	git -C r3 commit -m "sparse" &&
 	echo dir1/ >pattern1 &&
@@ -672,7 +672,7 @@ test_expect_success 'rev-list W/ --missing=print' '
 
 	for id in `cat expected | sed "s|..|&/|"`
 	do
-		rm r1/.git/objects/$id
+		rm r1/.git/objects/$id || return 1
 	done &&
 
 	git -C r1 rev-list --quiet --missing=print --objects HEAD >revs &&
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 9b2cc066f7..d8af2bb9d2 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -262,7 +262,7 @@ test_expect_success 'name-rev --all' '
 	>expect.unsorted &&
 	for rev in $(git rev-list --all)
 	do
-		git name-rev $rev >>expect.unsorted
+		git name-rev $rev >>expect.unsorted || return 1
 	done &&
 	sort <expect.unsorted >expect &&
 	git name-rev --all >actual.unsorted &&
@@ -275,7 +275,7 @@ test_expect_success 'name-rev --stdin' '
 	for rev in $(git rev-list --all)
 	do
 		name=$(git name-rev --name-only $rev) &&
-		echo "$rev ($name)" >>expect.unsorted
+		echo "$rev ($name)" >>expect.unsorted || return 1
 	done &&
 	sort <expect.unsorted >expect &&
 	git rev-list --all | git name-rev --stdin >actual.unsorted &&
@@ -395,7 +395,7 @@ EOF" &&
 		then
 			echo "from refs/heads/main^0"
 		fi &&
-		i=$(($i + 1))
+		i=$(($i + 1)) || return 1
 	done | git fast-import &&
 	git checkout main &&
 	git tag far-far-away HEAD^ &&
diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh
index 30328b87f0..8ff1d76f79 100755
--- a/t/t6132-pathspec-exclude.sh
+++ b/t/t6132-pathspec-exclude.sh
@@ -11,7 +11,7 @@ test_expect_success 'setup' '
 		fi &&
 		: >$p &&
 		git add $p &&
-		git commit -m $p
+		git commit -m $p || return 1
 	done &&
 	git log --oneline --format=%s >actual &&
 	cat <<EOF >expect &&
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 06c5fb5615..5cf7b7673e 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -519,7 +519,7 @@ test_expect_success 'merge-msg lots of commits' '
 		while test $i -gt 9
 		do
 			echo "  $i" &&
-			i=$(($i-1))
+			i=$(($i-1)) || return 1
 		done &&
 		echo "  ..."
 	} >expected &&
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index aae57908f8..abc8e1495a 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -1338,7 +1338,7 @@ test_expect_success ':remotename and :remoteref' '
 			echo "${pair#*=}" >expect &&
 			git for-each-ref --format="${pair%=*}" \
 				refs/heads/main >actual &&
-			test_cmp expect actual
+			test_cmp expect actual || exit 1
 		done &&
 		git branch push-simple &&
 		git config branch.push-simple.pushRemote from &&
diff --git a/t/t6412-merge-large-rename.sh b/t/t6412-merge-large-rename.sh
index ed40801380..ca018d11f5 100755
--- a/t/t6412-merge-large-rename.sh
+++ b/t/t6412-merge-large-rename.sh
@@ -37,18 +37,18 @@ test_rename() {
 	test_might_fail git branch -D test$n &&
 	git reset --hard initial &&
 	for i in $(count $n); do
-		make_text $i initial initial >$i
+		make_text $i initial initial >$i || return 1
 	done &&
 	git add . &&
 	git commit -m add=$n &&
 	for i in $(count $n); do
-		make_text $i changed initial >$i
+		make_text $i changed initial >$i || return 1
 	done &&
 	git commit -a -m change=$n &&
 	git checkout -b test$n HEAD^ &&
 	for i in $(count $n); do
 		git rm $i &&
-		make_text $i initial changed >$i.moved
+		make_text $i initial changed >$i.moved || return 1
 	done &&
 	git add . &&
 	git commit -m change+rename=$n &&
@@ -79,7 +79,7 @@ test_expect_success 'setup large simple rename' '
 
 	git reset --hard initial &&
 	for i in $(count 200); do
-		make_text foo bar baz >$i
+		make_text foo bar baz >$i || return 1
 	done &&
 	git add . &&
 	git commit -m create-files &&
diff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh
index a0efe7cb6d..07067bb347 100755
--- a/t/t6430-merge-recursive.sh
+++ b/t/t6430-merge-recursive.sh
@@ -706,7 +706,7 @@ test_expect_success 'merge-recursive remembers the names of all base trees' '
 	# more trees than static slots used by oid_to_hex()
 	for commit in $c0 $c2 $c4 $c5 $c6 $c7
 	do
-		git rev-parse "$commit^{tree}"
+		git rev-parse "$commit^{tree}" || return 1
 	done >trees &&
 
 	# ignore the return code; it only fails because the input is weird...
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index 3d7a62ddab..338a9c46a2 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -32,7 +32,7 @@ test_expect_success 'setup' '
 	do
 		test_commit "1-$i" &&
 		git branch -f commit-1-$i &&
-		git tag -a -m "1-$i" tag-1-$i commit-1-$i
+		git tag -a -m "1-$i" tag-1-$i commit-1-$i || return 1
 	done &&
 	for j in $(test_seq 1 9)
 	do
@@ -46,7 +46,7 @@ test_expect_success 'setup' '
 		do
 			git merge commit-$j-$i -m "$x-$i" &&
 			git branch -f commit-$x-$i &&
-			git tag -a -m "$x-$i" tag-$x-$i commit-$x-$i
+			git tag -a -m "$x-$i" tag-$x-$i commit-$x-$i || return 1
 		done
 	done &&
 	git commit-graph write --reachable &&
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 660cde5a63..25a26563dd 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1981,7 +1981,7 @@ EOF" &&
 		then
 			echo "from refs/heads/main^0"
 		fi &&
-		i=$(($i + 1))
+		i=$(($i + 1)) || return 1
 	done | git fast-import &&
 	git checkout main &&
 	git tag far-far-away HEAD^ &&
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index 2a07c70867..e39c809ca4 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -16,7 +16,7 @@ test_expect_success 'set up commits for rebasing' '
 	test_commit rebase-b b bb &&
 	for i in $(test_seq 1 13)
 	do
-		test_commit rebase-$i c $i
+		test_commit rebase-$i c $i || return 1
 	done &&
 	git checkout main &&
 
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index c773e30b3f..f0f6fda150 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -967,7 +967,7 @@ test_expect_success 'set up mod-256 conflict scenario' '
 	# 256 near-identical stanzas...
 	for i in $(test_seq 1 256); do
 		for j in 1 2 3 4 5; do
-			echo $i-$j
+			echo $i-$j || return 1
 		done
 	done >file &&
 	git add file &&
diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index ddf64dc5f7..ff085b086c 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -30,7 +30,7 @@ test_expect_success 'merge c1 with c2, c3, c4, ... c29' '
 	while test $i -le 30
 	do
 		refs="$refs c$i" &&
-		i=$(expr $i + 1)
+		i=$(expr $i + 1) || return 1
 	done &&
 	git merge $refs &&
 	test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" &&
diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh
index 27cd94ad6f..4887ca705b 100755
--- a/t/t7603-merge-reduce-heads.sh
+++ b/t/t7603-merge-reduce-heads.sh
@@ -95,7 +95,7 @@ test_expect_success 'setup' '
 		echo $i > $i.c &&
 		git add $i.c &&
 		git commit -m $i &&
-		git tag $i
+		git tag $i || return 1
 	done &&
 	git reset --hard A &&
 	for i in F G H I
@@ -103,7 +103,7 @@ test_expect_success 'setup' '
 		echo $i > $i.c &&
 		git add $i.c &&
 		git commit -m $i &&
-		git tag $i
+		git tag $i || return 1
 	done
 '
 
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 0260ad6f0e..4693f8dc2b 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -117,7 +117,7 @@ test_expect_success 'packed obs in alternate ODB kept pack are repacked' '
 			rm alt_objects/pack/$base_name.keep
 		else
 			touch alt_objects/pack/$base_name.keep
-		fi
+		fi || return 1
 	done &&
 	git repack -a -d &&
 	test_no_missing_in_packs
diff --git a/t/t8014-blame-ignore-fuzzy.sh b/t/t8014-blame-ignore-fuzzy.sh
index e68e6115a6..0bd0341301 100755
--- a/t/t8014-blame-ignore-fuzzy.sh
+++ b/t/t8014-blame-ignore-fuzzy.sh
@@ -310,7 +310,7 @@ test_expect_success setup '
 			echo "$line" >>"$i" &&
 			git add "$i" &&
 			test_tick &&
-			GIT_AUTHOR_NAME="$line_count" git commit -m "$line_count"
+			GIT_AUTHOR_NAME="$line_count" git commit -m "$line_count" || return 1
 		done <"a$i"
 	done &&
 
@@ -318,7 +318,7 @@ test_expect_success setup '
 	do
 		# Overwrite the files with the final content.
 		cp b$i $i &&
-		git add $i
+		git add $i || return 1
 	done &&
 	test_tick &&
 
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 67eed2fefc..c7d8e0bf00 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -117,7 +117,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' '
 	mkdir -p import/trunk/subversion/bindings/swig/perl/t &&
 	for i in a b c ; do \
 	  echo $i > import/trunk/subversion/bindings/swig/perl/$i.pm &&
-	  echo _$i > import/trunk/subversion/bindings/swig/perl/t/$i.t; \
+	  echo _$i > import/trunk/subversion/bindings/swig/perl/t/$i.t || return 1
 	done &&
 	  echo "bad delete test" > \
 	   import/trunk/subversion/bindings/swig/perl/t/larger-parent &&
@@ -134,7 +134,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' '
 		svn mv t native/t &&
 		for i in a b c
 		do
-			svn mv $i.pm native/$i.pm
+			svn mv $i.pm native/$i.pm || return 1
 		done &&
 		echo z >>native/t/c.t &&
 		poke native/t/c.t &&
diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh
index b4081fefba..90325db909 100755
--- a/t/t9130-git-svn-authors-file.sh
+++ b/t/t9130-git-svn-authors-file.sh
@@ -15,7 +15,7 @@ EOF
 test_expect_success 'setup svnrepo' '
 	for i in aa bb cc dd
 	do
-		svn_cmd mkdir -m $i --username $i "$svnrepo"/$i
+		svn_cmd mkdir -m $i --username $i "$svnrepo"/$i || return 1
 	done
 	'
 
@@ -60,7 +60,7 @@ test_expect_success 'authors-file against globs' '
 	for i in bb ee cc
 	do
 		branch="aa/branches/$i" &&
-		svn_cmd mkdir -m "$branch" --username $i "$svnrepo/$branch"
+		svn_cmd mkdir -m "$branch" --username $i "$svnrepo/$branch" || return 1
 	done
 	'
 
diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh
index fff49c4100..4a77eb9f60 100755
--- a/t/t9134-git-svn-ignore-paths.sh
+++ b/t/t9134-git-svn-ignore-paths.sh
@@ -27,7 +27,7 @@ test_expect_success 'setup test repository' '
 test_expect_success 'clone an SVN repository with ignored www directory' '
 	git svn clone --ignore-paths="^www" "$svnrepo" g &&
 	echo test_qqq > expect &&
-	for i in g/*/*.txt; do cat $i >> expect2; done &&
+	for i in g/*/*.txt; do cat $i >> expect2 || return 1; done &&
 	test_cmp expect expect2
 '
 
@@ -36,7 +36,7 @@ test_expect_success 'init+fetch an SVN repository with ignored www directory' '
 	( cd c && git svn fetch --ignore-paths="^www" ) &&
 	rm expect2 &&
 	echo test_qqq > expect &&
-	for i in c/*/*.txt; do cat $i >> expect2; done &&
+	for i in c/*/*.txt; do cat $i >> expect2 || return 1; done &&
 	test_cmp expect expect2
 '
 
@@ -62,7 +62,7 @@ test_expect_success 'update git svn-cloned repo (config ignore)' '
 		cd g &&
 		git svn rebase &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -73,7 +73,7 @@ test_expect_success 'update git svn-cloned repo (option ignore)' '
 		cd c &&
 		git svn rebase --ignore-paths="^www" &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -94,7 +94,7 @@ test_expect_success 'update git svn-cloned repo (config ignore)' '
 		cd g &&
 		git svn rebase &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -105,7 +105,7 @@ test_expect_success 'update git svn-cloned repo (option ignore)' '
 		cd c &&
 		git svn rebase --ignore-paths="^www" &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -127,7 +127,7 @@ test_expect_success 'update git svn-cloned repo again (config ignore)' '
 		cd g &&
 		git svn rebase &&
 		printf "test_qqq\nb\nygg\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -138,7 +138,7 @@ test_expect_success 'update git svn-cloned repo again (option ignore)' '
 		cd c &&
 		git svn rebase --ignore-paths="^www" &&
 		printf "test_qqq\nb\nygg\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
diff --git a/t/t9138-git-svn-authors-prog.sh b/t/t9138-git-svn-authors-prog.sh
index 027b416720..784ec7fc2d 100755
--- a/t/t9138-git-svn-authors-prog.sh
+++ b/t/t9138-git-svn-authors-prog.sh
@@ -27,7 +27,7 @@ test_expect_success 'svn-authors setup' '
 test_expect_success 'setup svnrepo' '
 	for i in aa bb cc-sub dd-sub ee-foo ff
 	do
-		svn mkdir -m $i --username $i "$svnrepo"/$i
+		svn mkdir -m $i --username $i "$svnrepo"/$i || return 1
 	done
 '
 
diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh
index 5f91c0d68b..80cb55fee7 100755
--- a/t/t9146-git-svn-empty-dirs.sh
+++ b/t/t9146-git-svn-empty-dirs.sh
@@ -8,7 +8,7 @@ test_description='git svn creates empty directories'
 test_expect_success 'initialize repo' '
 	for i in a b c d d/e d/e/f "weird file name"
 	do
-		svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i"
+		svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i" || return 1
 	done
 '
 
@@ -102,7 +102,7 @@ test_expect_success 'git svn mkdirs -r works' '
 test_expect_success 'initialize trunk' '
 	for i in trunk trunk/a trunk/"weird file name"
 	do
-		svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i"
+		svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i" || return 1
 	done
 '
 
diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh
index d292bf9f55..257fc8f2f8 100755
--- a/t/t9147-git-svn-include-paths.sh
+++ b/t/t9147-git-svn-include-paths.sh
@@ -28,7 +28,7 @@ test_expect_success 'setup test repository' '
 test_expect_success 'clone an SVN repository with filter to include qqq directory' '
 	git svn clone --include-paths="qqq" "$svnrepo" g &&
 	echo test_qqq > expect &&
-	for i in g/*/*.txt; do cat $i >> expect2; done &&
+	for i in g/*/*.txt; do cat $i >> expect2 || return 1; done &&
 	test_cmp expect expect2
 '
 
@@ -38,7 +38,7 @@ test_expect_success 'init+fetch an SVN repository with included qqq directory' '
 	( cd c && git svn fetch --include-paths="qqq" ) &&
 	rm expect2 &&
 	echo test_qqq > expect &&
-	for i in c/*/*.txt; do cat $i >> expect2; done &&
+	for i in c/*/*.txt; do cat $i >> expect2 || return 1; done &&
 	test_cmp expect expect2
 '
 
@@ -64,7 +64,7 @@ test_expect_success 'update git svn-cloned repo (config include)' '
 		cd g &&
 		git svn rebase &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -75,7 +75,7 @@ test_expect_success 'update git svn-cloned repo (option include)' '
 		cd c &&
 		git svn rebase --include-paths="qqq" &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -96,7 +96,7 @@ test_expect_success 'update git svn-cloned repo (config include)' '
 		cd g &&
 		git svn rebase &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -107,7 +107,7 @@ test_expect_success 'update git svn-cloned repo (option include)' '
 		cd c &&
 		git svn rebase --include-paths="qqq" &&
 		printf "test_qqq\nb\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -129,7 +129,7 @@ test_expect_success 'update git svn-cloned repo again (config include)' '
 		cd g &&
 		git svn rebase &&
 		printf "test_qqq\nb\nygg\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
@@ -140,7 +140,7 @@ test_expect_success 'update git svn-cloned repo again (option include)' '
 		cd c &&
 		git svn rebase --include-paths="qqq" &&
 		printf "test_qqq\nb\nygg\n" > expect &&
-		for i in */*.txt; do cat $i >> expect2; done &&
+		for i in */*.txt; do cat $i >> expect2 || exit 1; done &&
 		test_cmp expect2 expect &&
 		rm expect expect2
 	)
diff --git a/t/t9152-svn-empty-dirs-after-gc.sh b/t/t9152-svn-empty-dirs-after-gc.sh
index 89f285d082..a597c42f77 100755
--- a/t/t9152-svn-empty-dirs-after-gc.sh
+++ b/t/t9152-svn-empty-dirs-after-gc.sh
@@ -8,7 +8,7 @@ test_description='git svn creates empty directories, calls git gc, makes sure th
 test_expect_success 'initialize repo' '
 	for i in a b c d d/e d/e/f "weird file name"
 	do
-		svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i"
+		svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i" || return 1
 	done
 '
 
diff --git a/t/t9304-fast-import-marks.sh b/t/t9304-fast-import-marks.sh
index d4359dba21..bed01c99ea 100755
--- a/t/t9304-fast-import-marks.sh
+++ b/t/t9304-fast-import-marks.sh
@@ -16,7 +16,7 @@ test_expect_success 'setup large marks file' '
 	blob=$(git rev-parse HEAD:one.t) &&
 	for i in $(test_seq 1024 16384)
 	do
-		echo ":$i $blob"
+		echo ":$i $blob" || return 1
 	done >>marks
 '
 
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index a60fe2e19f..dd378df730 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -338,7 +338,7 @@ test_expect_success 'cvs update (subdirectories)' \
   '(for dir in A A/B A/B/C A/D E; do
       mkdir $dir &&
       echo "test file in $dir" >"$dir/file_in_$(echo $dir|sed -e "s#/# #g")"  &&
-      git add $dir
+      git add $dir || exit 1
    done) &&
    git commit -q -m "deep sub directory structure" &&
    git push gitcvs.git >/dev/null &&
@@ -381,7 +381,7 @@ test_expect_success 'cvs update (merge)' \
    for i in 1 2 3 4 5 6 7
    do
      echo Line $i >>merge &&
-     echo Line $i >>expected
+     echo Line $i >>expected || return 1
    done &&
    echo Line 8 >>expected &&
    git add merge &&
diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index 81bc8e8da1..806005a793 100755
--- a/t/t9800-git-p4-basic.sh
+++ b/t/t9800-git-p4-basic.sh
@@ -171,7 +171,7 @@ test_expect_success 'clone using non-numeric revision ranges' '
 			cd "$git" &&
 			git ls-files >lines &&
 			test_line_count = 8 lines
-		)
+		) || return 1
 	done
 '
 
diff --git a/t/t9818-git-p4-block.sh b/t/t9818-git-p4-block.sh
index 0db7ab9918..de591d875c 100755
--- a/t/t9818-git-p4-block.sh
+++ b/t/t9818-git-p4-block.sh
@@ -92,11 +92,11 @@ test_expect_success 'Add some more files' '
 	for i in $(test_seq 0 10)
 	do
 		p4_add_file "included/x$i" &&
-		p4_add_file "excluded/x$i"
+		p4_add_file "excluded/x$i" || return 1
 	done &&
 	for i in $(test_seq 0 10)
 	do
-		p4_add_file "excluded/y$i"
+		p4_add_file "excluded/y$i" || return 1
 	done
 '
 
@@ -123,7 +123,7 @@ test_expect_success 'Create a repo with multiple depot paths' '
 	do
 		for i in $(test_seq 1 10)
 		do
-			p4_add_file "$p/file$p$i"
+			p4_add_file "$p/file$p$i" || return 1
 		done
 	done
 '
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 518203fbe0..caa9d2dc9b 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -879,7 +879,7 @@ test_expect_success '__git_refs - unique remote branches for git checkout DWIMer
 		refs/remotes/remote/branch-in-remote
 	do
 		git update-ref $remote_ref main &&
-		test_when_finished "git update-ref -d $remote_ref"
+		test_when_finished "git update-ref -d $remote_ref" || return 1
 	done &&
 	(
 		cur= &&
@@ -1052,7 +1052,7 @@ test_expect_success '__git_refs - only matching refs - checkout DWIMery' '
 		refs/remotes/remote/branch-in-remote
 	do
 		git update-ref $remote_ref main &&
-		test_when_finished "git update-ref -d $remote_ref"
+		test_when_finished "git update-ref -d $remote_ref" || return 1
 	done &&
 	(
 		cur=mat &&
-- 
2.34.1.307.g9b7440fafd


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH 02/19] t1010: fix unnoticed failure on Windows
  2021-12-09  5:10 ` [PATCH 02/19] t1010: fix unnoticed failure on Windows Eric Sunshine
@ 2021-12-09 16:27   ` Elijah Newren
  2021-12-09 16:45     ` Eric Sunshine
  0 siblings, 1 reply; 47+ messages in thread
From: Elijah Newren @ 2021-12-09 16:27 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git Mailing List, Jeff King, Eric Sunshine

On Thu, Dec 9, 2021 at 12:22 AM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> On Microsoft Windows, a directory name should never end with a period.
> Quoting from Microsoft documentation[1]:
>
>     Do not end a file or directory name with a space or a period.
>     Although the underlying file system may support such names, the
>     Windows shell and user interface does not.
>
> Naming a directory with a trailing period is indeed perilous:
>
>     % git init foo
>     % cd foo
>     % mkdir a.
>     % git status
>     warning: could not open directory 'a./': No such file or directory
>
> The t1010 "setup" test:
>
>     for d in a a. a0
>     do
>         mkdir "$d" && echo "$d/one" >"$d/one" &&
>         git add "$d"
>     done &&
>
> runs afoul of this Windows limitation, as can be observed when running
> the test verbosely:
>
>     error: open("a./one"): No such file or directory
>     error: unable to index file 'a./one'
>     fatal: adding files failed
>
> The reason this problem has gone unnoticed for so long is twofold.
> First, the failed `git add` is swallowed silently because the loop is
> not terminated explicitly by `|| return 1` to signal the failure.
> Second, none of the tests in this script care about the actual directory
> names or even the number of tree entries.

Is this true?  The names look like they were selected on the basis that
    '.' < '/' < '0'

> They care only that the tree
> synthesized in the index and created by `git write-tree` matches the
> tree created by the output of `git ls-tree` fed into `git mktree`, and
> the failure of `git add "a./one"` doesn't change that outcome.

We have multiple paths in the code that write tree structures, and
it's important that the order be
  100644 blob $OID1 a.
  040000 tree $OID2 a
  100644 blob $OID3 a0

i.e. that 'a' as a tree object sorts as though it were actually named
'a/'.  I suspect the code might have been making sure that the
different paths creating tree objects did so consistently, and the
special handling of subdirectories is the edge case that needs careful
checks.

> Skipping these tests on Windows by, for instance, checking the
> FUNNYNAMES predicate would avoid the problem, however, the funny-looking
> name is not what is being tested here. Rather, the tests are about
> checking that `git mktree` produces stable results for various input
> conditions, such as when the input order is not consistent or when an
> object is missing.
>
> Therefore, resolve the problem simply by using a directory name which is
> legal on Windows (i.e. "a-" rather than "a."). While at it, add the
> missing `|| return 1` to the loop body in order to catch this sort of
> problem in the future.

The choice to replace '.' with '-' is excellent since '-' < '/' as well.

>
> [1]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
>  t/t1010-mktree.sh | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
> index 48bfad07ab..3c08194526 100755
> --- a/t/t1010-mktree.sh
> +++ b/t/t1010-mktree.sh
> @@ -6,10 +6,10 @@ TEST_PASSES_SANITIZE_LEAK=true
>  . ./test-lib.sh
>
>  test_expect_success setup '
> -       for d in a a. a0
> +       for d in a a- a0
>         do
>                 mkdir "$d" && echo "$d/one" >"$d/one" &&
> -               git add "$d"
> +               git add "$d" || return 1
>         done &&
>         echo zero >one &&
>         git update-index --add --info-only one &&
> --
> 2.34.1.307.g9b7440fafd

The patch itself looks good; I'm just slightly unsure about the one
claim in the commit message.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions
  2021-12-09  5:11 ` [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions Eric Sunshine
@ 2021-12-09 16:44   ` Elijah Newren
  2021-12-09 16:53     ` Eric Sunshine
  0 siblings, 1 reply; 47+ messages in thread
From: Elijah Newren @ 2021-12-09 16:44 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git Mailing List, Jeff King, Eric Sunshine

On Wed, Dec 8, 2021 at 11:39 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> The top-level &&-chain checker built into t/test-lib.sh causes tests to
> magically exit with code 117 if the &&-chain is broken. However, it has
> the shortcoming that the magic does not work within `{...}` groups,
> `(...)` subshells, `$(...)` substitutions, or within bodies of compound
> statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
> partly fills in the gap by catching broken &&-chains in `(...)`
> subshells, but bugs can still lurk behind broken &&-chains in the other
> cases.
>
> Fix broken &&-chains in `$(...)` command substitutions in order to
> reduce the number of possible lurking bugs.
>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
>  contrib/subtree/t/t7900-subtree.sh |  2 +-
>  t/t0005-signals.sh                 |  2 +-
>  t/t0060-path-utils.sh              |  4 ++--
>  t/t1006-cat-file.sh                | 10 +++++-----
>  t/t3600-rm.sh                      |  2 +-
>  t/t7010-setup.sh                   |  2 +-
>  6 files changed, 11 insertions(+), 11 deletions(-)
>
> diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> index 4153b65321..1c1f76f04a 100755
> --- a/contrib/subtree/t/t7900-subtree.sh
> +++ b/contrib/subtree/t/t7900-subtree.sh
> @@ -1445,7 +1445,7 @@ test_expect_success 'subtree descendant check' '
>         ) &&
>         test_create_commit "$test_count" folder_subtree/0 &&
>         test_create_commit "$test_count" folder_subtree/b &&
> -       cherry=$(cd "$test_count"; git rev-parse HEAD) &&
> +       cherry=$(cd "$test_count" && git rev-parse HEAD) &&
>         (
>                 cd "$test_count" &&
>                 git checkout branch
> diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh
> index a5ec6a0315..eba75a2490 100755
> --- a/t/t0005-signals.sh
> +++ b/t/t0005-signals.sh
> @@ -48,7 +48,7 @@ test_expect_success !MINGW 'a constipated git dies with SIGPIPE' '
>  '
>
>  test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' '
> -       OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) &&
> +       OUT=$( ((trap "" PIPE && large_git; echo $? 1>&3) | :) 3>&1 ) &&

Shouldn't the second ';' be replaced with '&&' as well?

>         test_match_signal 13 "$OUT"
>  '
>
> diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
> index 34d1061f32..71a5d370cc 100755
> --- a/t/t0060-path-utils.sh
> +++ b/t/t0060-path-utils.sh
> @@ -216,7 +216,7 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
>         mkdir second &&
>         ln -s ../first second/other &&
>         mkdir third &&
> -       dir="$(cd .git; pwd -P)" &&
> +       dir="$(cd .git && pwd -P)" &&
>         dir2=third/../second/other/.git &&
>         test "$dir" = "$(test-tool path-utils real_path $dir2)" &&
>         file="$dir"/index &&
> @@ -224,7 +224,7 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
>         basename=blub &&
>         test "$dir/$basename" = "$(cd .git && test-tool path-utils real_path "$basename")" &&
>         ln -s ../first/file .git/syml &&
> -       sym="$(cd first; pwd -P)"/file &&
> +       sym="$(cd first && pwd -P)"/file &&
>         test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")"
>  '
>
> diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
> index 658628375c..67a3f64c2d 100755
> --- a/t/t1006-cat-file.sh
> +++ b/t/t1006-cat-file.sh
> @@ -211,14 +211,14 @@ done
>  test_expect_success "--batch-check for a non-existent named object" '
>      test "foobar42 missing
>  foobar84 missing" = \
> -    "$( ( echo foobar42; echo_without_newline foobar84; ) | git cat-file --batch-check)"
> +    "$( ( echo foobar42 && echo_without_newline foobar84 ) | git cat-file --batch-check)"
>  '
>
>  test_expect_success "--batch-check for a non-existent hash" '
>      test "0000000000000000000000000000000000000042 missing
>  0000000000000000000000000000000000000084 missing" = \
> -    "$( ( echo 0000000000000000000000000000000000000042;
> -        echo_without_newline 0000000000000000000000000000000000000084; ) |
> +    "$( ( echo 0000000000000000000000000000000000000042 &&
> +        echo_without_newline 0000000000000000000000000000000000000084 ) |
>         git cat-file --batch-check)"
>  '
>
> @@ -226,8 +226,8 @@ test_expect_success "--batch for an existent and a non-existent hash" '
>      test "$tag_sha1 tag $tag_size
>  $tag_content
>  0000000000000000000000000000000000000000 missing" = \
> -    "$( ( echo $tag_sha1;
> -        echo_without_newline 0000000000000000000000000000000000000000; ) |
> +    "$( ( echo $tag_sha1 &&
> +        echo_without_newline 0000000000000000000000000000000000000000 ) |
>         git cat-file --batch)"
>  '
>
> diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
> index bb9ef35dac..ed3952eb98 100755
> --- a/t/t3600-rm.sh
> +++ b/t/t3600-rm.sh
> @@ -265,7 +265,7 @@ test_expect_success 'choking "git rm" should not let it die with cruft (induce S
>
>  test_expect_success !MINGW 'choking "git rm" should not let it die with cruft (induce and check SIGPIPE)' '
>         choke_git_rm_setup &&
> -       OUT=$( ((trap "" PIPE; git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&
> +       OUT=$( ((trap "" PIPE && git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&

Same here; shouldn't the second ';' be replaced with '&&' as well?

>         test_match_signal 13 "$OUT" &&
>         test_path_is_missing .git/index.lock
>  '
> diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
> index 0335a9a158..520f96d09f 100755
> --- a/t/t7010-setup.sh
> +++ b/t/t7010-setup.sh
> @@ -137,7 +137,7 @@ test_expect_success 'setup deeper work tree' '
>
>  test_expect_success 'add a directory outside the work tree' '(
>         cd tester &&
> -       d1="$(cd .. ; pwd)" &&
> +       d1="$(cd .. && pwd)" &&
>         test_must_fail git add "$d1"
>  )'
>
> --
> 2.34.1.307.g9b7440fafd
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 02/19] t1010: fix unnoticed failure on Windows
  2021-12-09 16:27   ` Elijah Newren
@ 2021-12-09 16:45     ` Eric Sunshine
  0 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09 16:45 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Git Mailing List, Jeff King

On Thu, Dec 9, 2021 at 11:28 AM Elijah Newren <newren@gmail.com> wrote:
> On Thu, Dec 9, 2021 at 12:22 AM Eric Sunshine <sunshine@sunshineco.com> wrote:
> > The reason this problem has gone unnoticed for so long is twofold.
> > First, the failed `git add` is swallowed silently because the loop is
> > not terminated explicitly by `|| return 1` to signal the failure.
> > Second, none of the tests in this script care about the actual directory
> > names or even the number of tree entries.
>
> Is this true?  The names look like they were selected on the basis that
>     '.' < '/' < '0'
>
> We have multiple paths in the code that write tree structures, and
> it's important that the order be
>   100644 blob $OID1 a.
>   040000 tree $OID2 a
>   100644 blob $OID3 a0
>
> i.e. that 'a' as a tree object sorts as though it were actually named
> 'a/'.  I suspect the code might have been making sure that the
> different paths creating tree objects did so consistently, and the
> special handling of subdirectories is the edge case that needs careful
> checks.

I meant it in the sense that the tests don't care about the literal
names "a", "a.", "a0". They do care about ordering...

> > Skipping these tests on Windows by, for instance, checking the
> > FUNNYNAMES predicate would avoid the problem, however, the funny-looking
> > name is not what is being tested here. Rather, the tests are about
> > checking that `git mktree` produces stable results for various input
> > conditions, such as when the input order is not consistent or when an
> > object is missing.

... which I hoped to convey to readers by saying "stable results ...
when input order is not consistent", but I guess I wasn't clear enough
or obvious enough, or this mention is too far removed from the "don't
care about the actual names" statement.

> > Therefore, resolve the problem simply by using a directory name which is
> > legal on Windows (i.e. "a-" rather than "a."). While at it, add the
> > missing `|| return 1` to the loop body in order to catch this sort of
> > problem in the future.
>
> The choice to replace '.' with '-' is excellent since '-' < '/' as well.

I can rewrite the earlier paragraph to mention name ordering so it's
more obvious that it has significance.

I am a bit hesitant about spamming the list with a reroll of this
lengthy series just for this change, though I can certainly do it if
you consider it important.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 15/19] tests: simplify by dropping unnecessary `for` loops
  2021-12-09  5:11 ` [PATCH 15/19] tests: simplify by dropping unnecessary `for` loops Eric Sunshine
@ 2021-12-09 16:50   ` Elijah Newren
  0 siblings, 0 replies; 47+ messages in thread
From: Elijah Newren @ 2021-12-09 16:50 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git Mailing List, Jeff King, Eric Sunshine

On Wed, Dec 8, 2021 at 11:39 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> Rather than manually looping over a set of items and plugging those
> items into a template string which is printed repeatedly, achieve the
> same effect by taking advantage of `printf` which loops over its
> arguments automatically.

I didn't know this about printf; handy.

Patch looks good.

>
> Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
> ---
>  t/t3005-ls-files-relative.sh      | 10 ++--------
>  t/t3600-rm.sh                     |  5 +----
>  t/t4025-hunk-header.sh            | 10 ++--------
>  t/t4125-apply-ws-fuzz.sh          |  5 +----
>  t/t6416-recursive-corner-cases.sh | 30 ++++++------------------------
>  t/t7110-reset-merge.sh            |  2 +-
>  t/t9400-git-cvsserver-server.sh   |  2 +-
>  7 files changed, 14 insertions(+), 50 deletions(-)
>
> diff --git a/t/t3005-ls-files-relative.sh b/t/t3005-ls-files-relative.sh
> index 6ba8b589cd..fbfa210a50 100755
> --- a/t/t3005-ls-files-relative.sh
> +++ b/t/t3005-ls-files-relative.sh
> @@ -39,10 +39,7 @@ test_expect_success 'ls-files with mixed levels' '
>  test_expect_success 'ls-files -c' '
>         (
>                 cd top/sub &&
> -               for f in ../y*
> -               do
> -                       echo "error: pathspec $SQ$f$SQ did not match any file(s) known to git"
> -               done >expect.err &&
> +               printf "error: pathspec $SQ%s$SQ did not match any file(s) known to git\n" ../y* >expect.err &&
>                 echo "Did you forget to ${SQ}git add${SQ}?" >>expect.err &&
>                 ls ../x* >expect.out &&
>                 test_must_fail git ls-files -c --error-unmatch ../[xy]* >actual.out 2>actual.err &&
> @@ -54,10 +51,7 @@ test_expect_success 'ls-files -c' '
>  test_expect_success 'ls-files -o' '
>         (
>                 cd top/sub &&
> -               for f in ../x*
> -               do
> -                       echo "error: pathspec $SQ$f$SQ did not match any file(s) known to git"
> -               done >expect.err &&
> +               printf "error: pathspec $SQ%s$SQ did not match any file(s) known to git\n" ../x* >expect.err &&
>                 echo "Did you forget to ${SQ}git add${SQ}?" >>expect.err &&
>                 ls ../y* >expect.out &&
>                 test_must_fail git ls-files -o --error-unmatch ../[xy]* >actual.out 2>actual.err &&
> diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
> index ed3952eb98..e74a318ac3 100755
> --- a/t/t3600-rm.sh
> +++ b/t/t3600-rm.sh
> @@ -274,10 +274,7 @@ test_expect_success 'Resolving by removal is not a warning-worthy event' '
>         git reset -q --hard &&
>         test_when_finished "rm -f .git/index.lock msg && git reset -q --hard" &&
>         blob=$(echo blob | git hash-object -w --stdin) &&
> -       for stage in 1 2 3
> -       do
> -               echo "100644 $blob $stage       blob"
> -       done | git update-index --index-info &&
> +       printf "100644 $blob %d\tblob\n" 1 2 3 | git update-index --index-info &&
>         git rm blob >msg 2>&1 &&
>         test_i18ngrep ! "needs merge" msg &&
>         test_must_fail git ls-files -s --error-unmatch blob
> diff --git a/t/t4025-hunk-header.sh b/t/t4025-hunk-header.sh
> index 6356961de4..5397cb7d42 100755
> --- a/t/t4025-hunk-header.sh
> +++ b/t/t4025-hunk-header.sh
> @@ -14,15 +14,9 @@ test_expect_success setup '
>
>         (
>                 echo "A $NS" &&
> -               for c in B C D E F G H I J K
> -               do
> -                       echo "  $c"
> -               done &&
> +               printf "  %s\n" B C D E F G H I J K &&
>                 echo "L  $NS" &&
> -               for c in M N O P Q R S T U V
> -               do
> -                       echo "  $c"
> -               done
> +               printf "  %s\n" M N O P Q R S T U V
>         ) >file &&
>         git add file &&
>
> diff --git a/t/t4125-apply-ws-fuzz.sh b/t/t4125-apply-ws-fuzz.sh
> index 9671de7999..090987c89b 100755
> --- a/t/t4125-apply-ws-fuzz.sh
> +++ b/t/t4125-apply-ws-fuzz.sh
> @@ -10,10 +10,7 @@ test_expect_success setup '
>         git add file &&
>
>         # file-0 is full of whitespace breakages
> -       for l in a bb c d eeee f ggg h
> -       do
> -               echo "$l "
> -       done >file-0 &&
> +       printf "%s \n" a bb c d eeee f ggg h >file-0 &&
>
>         # patch-0 creates a whitespace broken file
>         cat file-0 >file &&
> diff --git a/t/t6416-recursive-corner-cases.sh b/t/t6416-recursive-corner-cases.sh
> index 84f5082366..690c8482b1 100755
> --- a/t/t6416-recursive-corner-cases.sh
> +++ b/t/t6416-recursive-corner-cases.sh
> @@ -24,14 +24,8 @@ test_expect_success 'setup basic criss-cross + rename with no modifications' '
>                 cd basic-rename &&
>
>                 ten="0 1 2 3 4 5 6 7 8 9" &&
> -               for i in $ten
> -               do
> -                       echo line $i in a sample file
> -               done >one &&
> -               for i in $ten
> -               do
> -                       echo line $i in another sample file
> -               done >two &&
> +               printf "line %d in a sample file\n" $ten >one &&
> +               printf "line %d in another sample file\n" $ten >two &&
>                 git add one two &&
>                 test_tick && git commit -m initial &&
>
> @@ -96,14 +90,8 @@ test_expect_success 'setup criss-cross + rename merges with basic modification'
>                 cd rename-modify &&
>
>                 ten="0 1 2 3 4 5 6 7 8 9" &&
> -               for i in $ten
> -               do
> -                       echo line $i in a sample file
> -               done >one &&
> -               for i in $ten
> -               do
> -                       echo line $i in another sample file
> -               done >two &&
> +               printf "line %d in a sample file\n" $ten >one &&
> +               printf "line %d in another sample file\n" $ten >two &&
>                 git add one two &&
>                 test_tick && git commit -m initial &&
>
> @@ -1588,10 +1576,7 @@ test_expect_success 'setup nested conflicts' '
>                 cd nested_conflicts &&
>
>                 # Create some related files now
> -               for i in $(test_seq 1 10)
> -               do
> -                       echo Random base content line $i
> -               done >initial &&
> +               printf "Random base content line %d\n" $(test_seq 1 10) >initial &&
>
>                 cp initial b_L1 &&
>                 cp initial b_R1 &&
> @@ -1777,10 +1762,7 @@ test_expect_success 'setup virtual merge base with nested conflicts' '
>                 cd virtual_merge_base_has_nested_conflicts &&
>
>                 # Create some related files now
> -               for i in $(test_seq 1 10)
> -               do
> -                       echo Random base content line $i
> -               done >content &&
> +               printf "Random base content line %d\n" $(test_seq 1 10) >content &&
>
>                 # Setup original commit
>                 git add content &&
> diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh
> index a82a07a04a..3d62e10b53 100755
> --- a/t/t7110-reset-merge.sh
> +++ b/t/t7110-reset-merge.sh
> @@ -8,7 +8,7 @@ test_description='Tests for "git reset" with "--merge" and "--keep" options'
>  . ./test-lib.sh
>
>  test_expect_success setup '
> -    for i in 1 2 3; do echo line $i; done >file1 &&
> +    printf "line %d\n" 1 2 3 >file1 &&
>      cat file1 >file2 &&
>      git add file1 file2 &&
>      test_tick &&
> diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
> index a6a73effde..a60fe2e19f 100755
> --- a/t/t9400-git-cvsserver-server.sh
> +++ b/t/t9400-git-cvsserver-server.sh
> @@ -591,7 +591,7 @@ test_expect_success 'cvs annotate' '
>      cd cvswork &&
>      GIT_CONFIG="$git_config" cvs annotate merge >../out &&
>      sed -e "s/ .*//" ../out >../actual &&
> -    for i in 3 1 1 1 1 1 1 1 2 4; do echo 1.$i; done >../expect &&
> +    printf "1.%d\n" 3 1 1 1 1 1 1 1 2 4 >../expect &&
>      test_cmp ../expect ../actual
>  '
>
> --
> 2.34.1.307.g9b7440fafd
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions
  2021-12-09 16:44   ` Elijah Newren
@ 2021-12-09 16:53     ` Eric Sunshine
  2021-12-09 16:57       ` Elijah Newren
  2021-12-10  9:27       ` Jeff King
  0 siblings, 2 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09 16:53 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Git Mailing List, Jeff King

On Thu, Dec 9, 2021 at 11:44 AM Elijah Newren <newren@gmail.com> wrote:
> On Wed, Dec 8, 2021 at 11:39 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
> >  test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' '
> > -       OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) &&
> > +       OUT=$( ((trap "" PIPE && large_git; echo $? 1>&3) | :) 3>&1 ) &&
>
> Shouldn't the second ';' be replaced with '&&' as well?

Thanks for reading so carefully. In this case, the answer is "no", the
semicolon is correct. This code legitimately wants to capture in the
OUT variable the numeric exit status of the command preceding `echo
$?`. If the semicolon is replaced with `&&`, then the echo won't be
executed if the exit status is non-zero, but we want `echo` to be
executed regardless of the exit status. So, the code is correct with
the semicolon, and would be incorrect with `&&`. (I hope I'm
explaining this well enough to make sense.)

It's this sort of special case which accounts for why the new linter
(as mentioned in the cover letter) has special understanding that a
broken &&-chain can be legitimate in certain circumstances, such as
explicit handling of `$?`.

> > -       OUT=$( ((trap "" PIPE; git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&
> > +       OUT=$( ((trap "" PIPE && git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&
>
> Same here; shouldn't the second ';' be replaced with '&&' as well?

Same answer as above.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions
  2021-12-09 16:53     ` Eric Sunshine
@ 2021-12-09 16:57       ` Elijah Newren
  2021-12-10  9:27       ` Jeff King
  1 sibling, 0 replies; 47+ messages in thread
From: Elijah Newren @ 2021-12-09 16:57 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git Mailing List, Jeff King

On Thu, Dec 9, 2021 at 8:53 AM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> On Thu, Dec 9, 2021 at 11:44 AM Elijah Newren <newren@gmail.com> wrote:
> > On Wed, Dec 8, 2021 at 11:39 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
> > >  test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' '
> > > -       OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) &&
> > > +       OUT=$( ((trap "" PIPE && large_git; echo $? 1>&3) | :) 3>&1 ) &&
> >
> > Shouldn't the second ';' be replaced with '&&' as well?
>
> Thanks for reading so carefully. In this case, the answer is "no", the
> semicolon is correct. This code legitimately wants to capture in the
> OUT variable the numeric exit status of the command preceding `echo
> $?`. If the semicolon is replaced with `&&`, then the echo won't be
> executed if the exit status is non-zero, but we want `echo` to be
> executed regardless of the exit status. So, the code is correct with
> the semicolon, and would be incorrect with `&&`. (I hope I'm
> explaining this well enough to make sense.)
>
> It's this sort of special case which accounts for why the new linter
> (as mentioned in the cover letter) has special understanding that a
> broken &&-chain can be legitimate in certain circumstances, such as
> explicit handling of `$?`.

Ah, right, you had mentioned this in the cover letter.  Short term
memory on my part, I guess.  Thanks for explaining...again.  :-)

> > > -       OUT=$( ((trap "" PIPE; git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&
> > > +       OUT=$( ((trap "" PIPE && git rm -n "some-file-*"; echo $? 1>&3) | :) 3>&1 ) &&
> >
> > Same here; shouldn't the second ';' be replaced with '&&' as well?
>
> Same answer as above.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/19] tests: fix broken &&-chains & abort loops on error
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (18 preceding siblings ...)
  2021-12-09  5:11 ` [PATCH 19/19] t6000-t9999: " Eric Sunshine
@ 2021-12-09 17:02 ` Elijah Newren
  2021-12-09 19:17   ` Eric Sunshine
  2021-12-11  9:58 ` [PATCH v1.1 2/19] t1010: fix unnoticed failure on Windows Eric Sunshine
  20 siblings, 1 reply; 47+ messages in thread
From: Elijah Newren @ 2021-12-09 17:02 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git Mailing List, Jeff King, Eric Sunshine

On Wed, Dec 8, 2021 at 11:39 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> A while back, Peff successfully nerd-sniped[1] me into tackling a
> long-brewing idea I had about (possibly) improving `chainlint`
> performance by linting all tests in all scripts with a single command
> invocation instead of running `sed` 25300+ times (once for each test).
>
> Beside the obvious improvement of checking all tests in all scripts at
> once, the new linter is also a good deal smarter than chainlint.sed and
> understands not just shell syntax but also some semantics of test
> construction, unlike chainlint.sed which is merely heuristics-based.
> For instance, the new linter recognizes cases when a broken &&-chain is
> legitimate, such as when `$?` is handled explicitly or when a failure is
> signaled directly with `false`, in which case the &&-chain leading up to
> the `false` is immaterial, as well as other cases. Unlike chainlint.sed,
> it recognizes that a semicolon after the last command in a compound
> statement is harmless, thus won't interpret the semicolon as breaking
> the &&-chain.
>
> The new linter also provides considerably better coverage for broken
> &&-chains. The &&-chain checker built into t/test-lib.sh, which causes
> tests to magically exit with code 117 if the &&-chain is broken, only
> works for top-level command invocations. The magic doesn't work within
> `{...}` groups, `(...)` subshells, `$(...)` substitutions, or within
> bodies of compound statements, such as `if`, `for`, `while`, `case`,
> etc. chainlint.sed partly fills the gap by catching broken &&-chains in
> `(...)` subshells one level deep, but bugs can still lurk behind broken
> &&-chains in the other cases. The new linter catches broken &&-chains
> within all those constructs to any depth.
>
> Another important improvement is that the new linter understands that
> shell loops do not terminate automatically when a command in the loop
> body fails, and that the condition needs to be handled explicitly by the
> test author by using `|| return 1` (or `|| exit 1` in a subshell) within
> the loop body to flag the failure. Consequently, the new linter will
> complain when a loop is lacking `|| return 1` (or `|| exit 1`). There
> are a number of other improvements, as well, but the above are some of
> the more important ones.
>
> Although the new chainlint implementation has been complete for several
> months, I'm still working out how to organize its patch series. In the
> meantime, _this_ patch series fixes problems discovered by the new
> linter due to its improved coverage and extra semantic knowledge about
> Git tests. As much as possible, I resisted the temptation to make
> ancillary cleanups (including indentation fixes) to tests even when such
> cleanups would be obvious improvements. Avoiding such unrelated cleanups
> should make the long patches in this series, which touch a lot of tests,
> easier to review (--color-words helps a lot here).

I have to admit to starting to skim once I got to the last four
patches, since they were a bit longer and all the same type of change.

You did an excellent job of explaining the changes and presented them
in a logical fashion.  The few things I thought I caught, you've
already answered were already correct.  I do think making the second
commit message be a bit clearer about the importance of the ordering
would be helpful.  Anyway:

Reviewed-by: Elijah Newren <newren@gmail.com>

> This series merges cleanly with 'next' but conflicts with a couple topics
> in 'seen':
>
> * jh/builtin-fsmonitor-part2
>
>   t/perf/p7519-fsmonitor.sh
>     simple resolution: keep all changes from jh/builtin-fsmonitor-part2
>     (it obviates the need for the fixes made by this series)
>
> * ms/customizable-ident-expansion
>
>   t/t0021-conversion.sh
>     this is a messy conflict but resolution is simple enough: keep all
>     the changes made by ms/customizable-ident-expansion and throw away
>     the changes by this series; this will leave a few broken &&-chains
>     in t0021-conversion.sh but there are a few other topics in 'seen'
>     with such problems already, so it has company; anyhow, "What's
>     Cooking" indicates that ms/customizable-ident-expansion is going to
>     be discarded, so it may not be worth worrying about it
>
> [1]: https://lore.kernel.org/git/YJzGcZpZ+E9R0gYd@coredump.intra.peff.net/
>
> Eric Sunshine (19):
>   t/lib-pager: use sane_unset() to avoid breaking &&-chain
>   t1010: fix unnoticed failure on Windows
>   t1020: avoid aborting entire test script when one test fails
>   t4202: clarify intent by creating expected content less cleverly
>   t5516: drop unnecessary subshell and command invocation
>   t6300: make `%(raw:size) --shell` test more robust
>   t9107: use shell parameter expansion to avoid breaking &&-chain
>   tests: simplify construction of large blocks of text
>   tests: use test_write_lines() to generate line-oriented output
>   tests: fix broken &&-chains in compound statements
>   tests: fix broken &&-chains in `$(...)` command substitutions
>   tests: fix broken &&-chains in `{...}` groups
>   tests: apply modern idiom for signaling test failure
>   tests: apply modern idiom for exiting loop upon failure
>   tests: simplify by dropping unnecessary `for` loops
>   t0000-t3999: detect and signal failure within loop
>   t4000-t4999: detect and signal failure within loop
>   t5000-t5999: detect and signal failure within loop
>   t6000-t9999: detect and signal failure within loop
>
>  .../mw-to-git/t/t9365-continuing-queries.sh   |   2 +-
>  contrib/subtree/t/t7900-subtree.sh            |   2 +-
>  t/annotate-tests.sh                           |   2 +-
>  t/lib-pager.sh                                |   2 +-
>  t/perf/p0005-status.sh                        |  12 +-
>  t/perf/p0006-read-tree-checkout.sh            |  20 +-
>  t/perf/p0007-write-cache.sh                   |   4 +-
>  t/perf/p0100-globbing.sh                      |   4 +-
>  t/perf/p1400-update-ref.sh                    |   4 +-
>  t/perf/p1451-fsck-skip-list.sh                |   2 +-
>  t/perf/p3400-rebase.sh                        |   2 +-
>  t/perf/p5302-pack-index.sh                    |   4 +-
>  t/perf/p5303-many-packs.sh                    |  10 +-
>  t/perf/p7519-fsmonitor.sh                     |   8 +-
>  t/t0005-signals.sh                            |   2 +-
>  t/t0008-ignores.sh                            |   2 +-
>  t/t0011-hashmap.sh                            |   4 +-
>  t/t0020-crlf.sh                               |  28 +-
>  t/t0021-conversion.sh                         |  60 ++--
>  t/t0026-eol-config.sh                         |   4 +-
>  t/t0060-path-utils.sh                         |   4 +-
>  t/t0069-oidtree.sh                            |  12 +-
>  t/t0095-bloom.sh                              |   4 +-
>  t/t0410-partial-clone.sh                      |   2 +-
>  t/t1006-cat-file.sh                           |  12 +-
>  t/t1010-mktree.sh                             |   4 +-
>  t/t1020-subdirectory.sh                       |  10 +-
>  t/t1050-large.sh                              |  34 +-
>  t/t1091-sparse-checkout-builtin.sh            |   2 +-
>  t/t1300-config.sh                             |   6 +-
>  t/t1400-update-ref.sh                         |   4 +-
>  t/t1403-show-ref.sh                           |  12 +-
>  t/t1410-reflog.sh                             |   4 +-
>  t/t1512-rev-parse-disambiguation.sh           |  12 +-
>  t/t1700-split-index.sh                        |   4 +-
>  t/t2004-checkout-cache-temp.sh                |   4 +-
>  t/t2012-checkout-last.sh                      |   4 +-
>  t/t2102-update-index-symlinks.sh              |   2 +-
>  t/t2103-update-index-ignore-missing.sh        |   2 +-
>  t/t2200-add-update.sh                         |  18 +-
>  t/t2201-add-update-typechange.sh              |  10 +-
>  t/t2203-add-intent.sh                         |   2 +-
>  t/t3005-ls-files-relative.sh                  |  10 +-
>  t/t3070-wildmatch.sh                          |   2 +-
>  t/t3202-show-branch.sh                        |   8 +-
>  t/t3303-notes-subtrees.sh                     |   6 +-
>  t/t3305-notes-fanout.sh                       |   4 +-
>  t/t3402-rebase-merge.sh                       |   8 +-
>  t/t3404-rebase-interactive.sh                 |   4 +-
>  t/t3417-rebase-whitespace-fix.sh              |   4 +-
>  t/t3501-revert-cherry-pick.sh                 |   2 +-
>  t/t3508-cherry-pick-many-commits.sh           |   2 +-
>  t/t3600-rm.sh                                 |   7 +-
>  t/t3700-add.sh                                |   8 +-
>  t/t3920-crlf-messages.sh                      |   4 +-
>  t/t4001-diff-rename.sh                        |   2 +-
>  t/t4012-diff-binary.sh                        |   2 +-
>  t/t4013-diff-various.sh                       |  22 +-
>  t/t4014-format-patch.sh                       |  32 +-
>  t/t4015-diff-whitespace.sh                    |   4 +-
>  t/t4018-diff-funcname.sh                      |   2 +-
>  t/t4019-diff-wserror.sh                       |   4 +-
>  t/t4023-diff-rename-typechange.sh             |   6 +-
>  t/t4024-diff-optimize-common.sh               |   2 +-
>  t/t4025-hunk-header.sh                        |  10 +-
>  t/t4038-diff-combined.sh                      |   2 +-
>  t/t4046-diff-unmerged.sh                      |  10 +-
>  t/t4049-diff-stat-count.sh                    |   2 +-
>  t/t4052-stat-output.sh                        |   2 +-
>  t/t4057-diff-combined-paths.sh                |  16 +-
>  t/t4105-apply-fuzz.sh                         |  10 +-
>  t/t4106-apply-stdin.sh                        |   5 +-
>  t/t4116-apply-reverse.sh                      |   4 +-
>  t/t4117-apply-reject.sh                       |  20 +-
>  t/t4118-apply-empty-context.sh                |   6 +-
>  t/t4123-apply-shrink.sh                       |   4 +-
>  t/t4124-apply-ws-rule.sh                      |  58 ++--
>  t/t4125-apply-ws-fuzz.sh                      |   5 +-
>  t/t4126-apply-empty.sh                        |   5 +-
>  t/t4127-apply-same-fn.sh                      |   5 +-
>  t/t4138-apply-ws-expansion.sh                 |  36 +-
>  t/t4150-am.sh                                 |   2 +-
>  t/t4151-am-abort.sh                           |  10 +-
>  t/t4202-log.sh                                |  42 +--
>  t/t4205-log-pretty-formats.sh                 |   2 +-
>  t/t4211-line-log.sh                           |   2 +-
>  t/t4212-log-corrupt.sh                        |   8 +-
>  t/t4216-log-bloom.sh                          |   4 +-
>  t/t5000-tar-tree.sh                           |   4 +-
>  t/t5003-archive-zip.sh                        |   2 +-
>  t/t5004-archive-corner-cases.sh               |   6 +-
>  t/t5100-mailinfo.sh                           |   2 +-
>  t/t5300-pack-object.sh                        |  18 +-
>  t/t5302-pack-index.sh                         |   2 +-
>  t/t5306-pack-nobase.sh                        |   2 +-
>  t/t5307-pack-missing-commit.sh                |   2 +-
>  t/t5310-pack-bitmaps.sh                       |   2 +-
>  t/t5316-pack-delta-depth.sh                   |   7 +-
>  t/t5317-pack-objects-filter-objects.sh        |  30 +-
>  t/t5318-commit-graph.sh                       |   6 +-
>  t/t5319-multi-pack-index.sh                   |  10 +-
>  t/t5322-pack-objects-sparse.sh                |   4 +-
>  t/t5325-reverse-index.sh                      |   2 +-
>  t/t5500-fetch-pack.sh                         |   8 +-
>  t/t5502-quickfetch.sh                         |   2 +-
>  t/t5505-remote.sh                             |   6 +-
>  t/t5510-fetch.sh                              |  14 +-
>  t/t5515-fetch-merge-logic.sh                  |  38 +--
>  t/t5516-fetch-push.sh                         |   5 +-
>  t/t5552-skipping-fetch-negotiator.sh          |  10 +-
>  t/t5562-http-backend-content-length.sh        |   2 +-
>  t/t5570-git-daemon.sh                         |   2 +-
>  t/t5571-pre-push-hook.sh                      |   6 +-
>  t/t5611-clone-config.sh                       |   2 +-
>  t/t5616-partial-clone.sh                      |  30 +-
>  t/t5702-protocol-v2.sh                        |   4 +-
>  t/t6005-rev-list-count.sh                     |   8 +-
>  t/t6009-rev-list-parent.sh                    |   6 +-
>  t/t6019-rev-list-ancestry-path.sh             |  10 +-
>  t/t6060-merge-index.sh                        |   4 +-
>  t/t6101-rev-parse-parents.sh                  |   2 +-
>  t/t6112-rev-list-filters-objects.sh           |  22 +-
>  t/t6120-describe.sh                           |  13 +-
>  t/t6132-pathspec-exclude.sh                   |   2 +-
>  t/t6200-fmt-merge-msg.sh                      |   2 +-
>  t/t6300-for-each-ref.sh                       |   7 +-
>  t/t6406-merge-attr.sh                         |   8 +-
>  t/t6407-merge-binary.sh                       |   4 +-
>  t/t6409-merge-subtree.sh                      |   6 +-
>  t/t6411-merge-filemode.sh                     |   8 +-
>  t/t6412-merge-large-rename.sh                 |  10 +-
>  t/t6416-recursive-corner-cases.sh             |  30 +-
>  t/t6417-merge-ours-theirs.sh                  |   5 +-
>  t/t6430-merge-recursive.sh                    |   2 +-
>  t/t6600-test-reach.sh                         |   4 +-
>  t/t7004-tag.sh                                |   9 +-
>  t/t7010-setup.sh                              |   2 +-
>  t/t7110-reset-merge.sh                        |   2 +-
>  t/t7501-commit-basic-functionality.sh         |   5 +-
>  t/t7505-prepare-commit-msg-hook.sh            |   2 +-
>  t/t7513-interpret-trailers.sh                 |   2 +-
>  t/t7519-status-fsmonitor.sh                   |   2 +-
>  t/t7600-merge.sh                              |   2 +-
>  t/t7602-merge-octopus-many.sh                 |   4 +-
>  t/t7603-merge-reduce-heads.sh                 |   4 +-
>  t/t7700-repack.sh                             |   2 +-
>  t/t7810-grep.sh                               | 310 +++++++++---------
>  t/t8002-blame.sh                              |   2 +-
>  t/t8003-blame-corner-cases.sh                 |  10 +-
>  t/t8014-blame-ignore-fuzzy.sh                 |   4 +-
>  t/t9104-git-svn-follow-parent.sh              |   4 +-
>  t/t9107-git-svn-migrate.sh                    |   8 +-
>  t/t9130-git-svn-authors-file.sh               |   6 +-
>  t/t9134-git-svn-ignore-paths.sh               |  16 +-
>  t/t9138-git-svn-authors-prog.sh               |   2 +-
>  t/t9146-git-svn-empty-dirs.sh                 |   4 +-
>  t/t9147-git-svn-include-paths.sh              |  16 +-
>  t/t9152-svn-empty-dirs-after-gc.sh            |   2 +-
>  t/t9304-fast-import-marks.sh                  |   2 +-
>  t/t9400-git-cvsserver-server.sh               |  11 +-
>  t/t9800-git-p4-basic.sh                       |   2 +-
>  t/t9818-git-p4-block.sh                       |   6 +-
>  t/t9902-completion.sh                         |   4 +-
>  163 files changed, 740 insertions(+), 847 deletions(-)
>
> --
> 2.34.1.307.g9b7440fafd
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/19] tests: fix broken &&-chains & abort loops on error
  2021-12-09 17:02 ` [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Elijah Newren
@ 2021-12-09 19:17   ` Eric Sunshine
  2021-12-10  9:38     ` Jeff King
  0 siblings, 1 reply; 47+ messages in thread
From: Eric Sunshine @ 2021-12-09 19:17 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Git Mailing List, Jeff King

On Thu, Dec 9, 2021 at 12:03 PM Elijah Newren <newren@gmail.com> wrote:
> On Wed, Dec 8, 2021 at 11:39 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
> > Although the new chainlint implementation has been complete for several
> > months, I'm still working out how to organize its patch series. In the
> > meantime, _this_ patch series fixes problems discovered by the new
> > linter due to its improved coverage and extra semantic knowledge about
> > Git tests. As much as possible, I resisted the temptation to make
> > ancillary cleanups (including indentation fixes) to tests even when such
> > cleanups would be obvious improvements. Avoiding such unrelated cleanups
> > should make the long patches in this series, which touch a lot of tests,
> > easier to review (--color-words helps a lot here).
>
> I have to admit to starting to skim once I got to the last four
> patches, since they were a bit longer and all the same type of change.

Understandable. Those bulk-change patches tend to be mind-numbing to
review, though `git diff --color-words` helps out somewhat (at least
by making it easier to skim the changes).

> You did an excellent job of explaining the changes and presented them
> in a logical fashion.  The few things I thought I caught, you've
> already answered were already correct.  I do think making the second
> commit message be a bit clearer about the importance of the ordering
> would be helpful.  Anyway:
>
> Reviewed-by: Elijah Newren <newren@gmail.com>

Thanks. I'll wait a couple days and resend with a clarified commit
message for the second patch unless, perhaps, Junio would accept a
resend of just that patch so I don't have to spam the list again.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/19] t4202: clarify intent by creating expected content less cleverly
  2021-12-09  5:11 ` [PATCH 04/19] t4202: clarify intent by creating expected content less cleverly Eric Sunshine
@ 2021-12-10  9:09   ` Jeff King
  0 siblings, 0 replies; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:09 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Eric Sunshine

On Thu, Dec 09, 2021 at 12:11:00AM -0500, Eric Sunshine wrote:

> Several tests assign the output of `$(...)` command substitution to an
> "expect" variable, taking advantage of the fact that `$(...)` folds out
> the final line terminator while leaving internal line terminators
> intact. They do this because the "actual" string with which "expect"
> will be compared is shaped the same way. However, this intent (having
> internal line terminators, but no final line terminator) is not
> necessarily obvious at first glance and may confuse casual readers. The
> intent can be made more obvious by using `printf` instead, with which
> line termination is stated clearly:
> 
>     printf "sixth\nthird"
> 
> In fact, many other tests in this script already use `printf` for
> precisely this purpose, thus it is an established pattern. Therefore,
> convert these tests to employ `printf`, as well.

Seems reasonable. I don't think these tests actually care about the lack
of trailing newline, so another option is to use tformat. Or its shorter
cousin, --format. E.g.:

> -	actual=$(git log --pretty="format:%s" --diff-filter=M HEAD) &&
> -	expect=$(echo second) &&
> -	verbose test "$actual" = "$expect"
> +	git log --pretty="format:%s" --diff-filter=M HEAD >actual &&
> +	printf "second" >expect &&
> +	test_cmp expect actual

becomes:

  git log --format=%s --diff-filter=M HEAD >actual &&
  echo second >expect &&
  test_cmp expect actual

which is even less magical. But if the existing pattern is there in
nearby tests, I don't have any problem with following it.

> While at it, modernize the tests to use test_cmp() to compare the
> expected and actual output rather than using the semi-deprecated
> `verbose test "$x" = "$y"`.

Yay. Happy to see more "verbose" calls cleaned up.

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 05/19] t5516: drop unnecessary subshell and command invocation
  2021-12-09  5:11 ` [PATCH 05/19] t5516: drop unnecessary subshell and command invocation Eric Sunshine
@ 2021-12-10  9:10   ` Jeff King
  0 siblings, 0 replies; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:10 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Eric Sunshine

On Thu, Dec 09, 2021 at 12:11:01AM -0500, Eric Sunshine wrote:

> To create its "expect" file, this test pipes into `sort` the output of
> `git for-each-ref` and a copy of that same output but with a minor
> textual transformation applied. To do so, it employs a subshell and
> commands `cat` and `sed` even though the same result can be accomplished
> by `sed` alone (without a subshell).

Clever. The ordering of output from sed is different than the original,
but because it all gets fed into sort anyway, that's OK.

In theory it could change the output of a stable sort of lines which
match (which won't be totally identical, because you are sorting with
-k3), but it seems we don't care in this instance.

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/19] t6300: make `%(raw:size) --shell` test more robust
  2021-12-09  5:11 ` [PATCH 06/19] t6300: make `%(raw:size) --shell` test more robust Eric Sunshine
@ 2021-12-10  9:14   ` Jeff King
  0 siblings, 0 replies; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:14 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Eric Sunshine

On Thu, Dec 09, 2021 at 12:11:02AM -0500, Eric Sunshine wrote:

> This test populates its `expect` file solely by appending content but
> fails to ensure that the file starts out empty. The test succeeds only
> because no earlier test populated a file of the exact same name, however
> this is an accident waiting to happen. Make the test more robust by
> ensuring that it contains exactly the intended content.

Agreed.

> While at it, simplify the implementation via a straightforward `sed`
> application and by avoiding dropping out of the single-quote context
> within the test body (thus eliminating a hard-to-digest combination of
> apostrophes and backslashes).

I find them equally ugly. :) The most confusing thing is that we are not
doing any shell quoting at all, just adding single-quote wrappers. But
that is OK because %(raw:size) should never need quoting.

Your solution seems fine to me.

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 09/19] tests: use test_write_lines() to generate line-oriented output
  2021-12-09  5:11 ` [PATCH 09/19] tests: use test_write_lines() to generate line-oriented output Eric Sunshine
@ 2021-12-10  9:22   ` Jeff King
  2021-12-11  6:59     ` Eric Sunshine
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:22 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Eric Sunshine

On Thu, Dec 09, 2021 at 12:11:05AM -0500, Eric Sunshine wrote:

> Take advantage of test_write_lines() to generate line-oriented output
> rather than using for-loops or a series of `echo` commands. Not only is
> test_write_lines() a natural fit for such a task, but there is less
> opportunity for a broken &&-chain.

Makes sense. A few of these append like this:

> -	for w in Some extra lines here; do echo $w; done >>one &&
> +	test_write_lines Some extra lines here >>one &&

which made me wonder if the original really wanted to append, or if they
meant:

  for w in Some extra lines here; do echo $w >>one; done

in the first place. In which case you could write ">one". But in the
cases I peeked at, they really are appending to a file that already
existed. And at any rate, your conversions are all faithful to the
original, which is the right thing to do to avoid introducing bugs.

>  test_expect_success 'color new trailing blank lines' '
> -	{ echo a; echo b; echo; echo; } >x &&
> +	test_write_lines a b "" "" >x &&
>  	git add x &&
> -	{ echo a; echo; echo; echo; echo c; echo; echo; echo; echo; } >x &&
> +	test_write_lines a "" "" "" c "" "" "" "" >x &&

Some of these I think might be more readable as here-docs. But I think
keeping to the minimal change here makes sense (and I admit I do not
overly care much either way; it was just on my mind from the last
patch).

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions
  2021-12-09 16:53     ` Eric Sunshine
  2021-12-09 16:57       ` Elijah Newren
@ 2021-12-10  9:27       ` Jeff King
  1 sibling, 0 replies; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:27 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Elijah Newren, Git Mailing List

On Thu, Dec 09, 2021 at 11:53:47AM -0500, Eric Sunshine wrote:

> On Thu, Dec 9, 2021 at 11:44 AM Elijah Newren <newren@gmail.com> wrote:
> > On Wed, Dec 8, 2021 at 11:39 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
> > >  test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' '
> > > -       OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) &&
> > > +       OUT=$( ((trap "" PIPE && large_git; echo $? 1>&3) | :) 3>&1 ) &&
> >
> > Shouldn't the second ';' be replaced with '&&' as well?
> 
> Thanks for reading so carefully. In this case, the answer is "no", the
> semicolon is correct. This code legitimately wants to capture in the
> OUT variable the numeric exit status of the command preceding `echo
> $?`. If the semicolon is replaced with `&&`, then the echo won't be
> executed if the exit status is non-zero, but we want `echo` to be
> executed regardless of the exit status. So, the code is correct with
> the semicolon, and would be incorrect with `&&`. (I hope I'm
> explaining this well enough to make sense.)

That makes sense to me. I wondered why it was even worth changing the
earlier semi-colon in that case, then, but...

> It's this sort of special case which accounts for why the new linter
> (as mentioned in the cover letter) has special understanding that a
> broken &&-chain can be legitimate in certain circumstances, such as
> explicit handling of `$?`.

...your unseen magic script explains it. :)

All of the changes here look reasonable. We'd either want to know about
failure (e.g., "cd") or don't expect it to fail (e.g., "echo").

These "trap" calls are probably fine. I can't imagine why they'd fail,
but being a weird shell builtin I wonder if it's possible for them to
fail in odd circumstances. I'm happy to leave that as a hypothetical
until we see it in practice.

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups
  2021-12-09  5:11 ` [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups Eric Sunshine
@ 2021-12-10  9:29   ` Jeff King
  2021-12-11  7:14     ` Eric Sunshine
  2021-12-10  9:38   ` Fabian Stelzer
  1 sibling, 1 reply; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:29 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Eric Sunshine

On Thu, Dec 09, 2021 at 12:11:08AM -0500, Eric Sunshine wrote:

> The top-level &&-chain checker built into t/test-lib.sh causes tests to
> magically exit with code 117 if the &&-chain is broken. However, it has
> the shortcoming that the magic does not work within `{...}` groups,
> `(...)` subshells, `$(...)` substitutions, or within bodies of compound
> statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
> partly fills in the gap by catching broken &&-chains in `(...)`
> subshells, but bugs can still lurk behind broken &&-chains in the other
> cases.
> 
> Fix broken &&-chains in `{...}` groups in order to reduce the number of
> possible lurking bugs.

Seems good. This is mostly stuff we don't expect to fail (mostly
"echo"), so I doubt they're important on their own. But getting a clean
state for the linter _is_ important.

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 13/19] tests: apply modern idiom for signaling test failure
  2021-12-09  5:11 ` [PATCH 13/19] tests: apply modern idiom for signaling test failure Eric Sunshine
@ 2021-12-10  9:32   ` Jeff King
  2021-12-11  7:47     ` Eric Sunshine
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:32 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Eric Sunshine

On Thu, Dec 09, 2021 at 12:11:09AM -0500, Eric Sunshine wrote:

> Simplify the way these tests signal failure by employing the modern
> idiom of making the `if` or `case` statement resolve to false when an
> error is detected.

Yeah, these are pretty non-idiomatic, but...

> diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
> index cfde68f193..7e46f4ca85 100755
> --- a/t/t3402-rebase-merge.sh
> +++ b/t/t3402-rebase-merge.sh
> @@ -68,7 +68,7 @@ test_expect_success 'merge and rebase should match' '
>  	if test -s difference
>  	then
>  		cat difference
> -		(exit 1)
> +		false
>  	else
>  		echo happy
>  	fi

...I'd have said the idiom here is just:

  git diff-tree -r test-rebase test-merge >difference &&
  test -s difference

The extra "cat" and "happy" are verbose output that we usually skip in
favor of letting "-x" logging do the talking (and leaving the failed
state so you can "cat difference" yourself).

That said, I'm OK with this minimal change in the name of keeping creep
out of the series.

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 14/19] tests: apply modern idiom for exiting loop upon failure
  2021-12-09  5:11 ` [PATCH 14/19] tests: apply modern idiom for exiting loop upon failure Eric Sunshine
@ 2021-12-10  9:36   ` Jeff King
  0 siblings, 0 replies; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:36 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Eric Sunshine

On Thu, Dec 09, 2021 at 12:11:10AM -0500, Eric Sunshine wrote:

> diff --git a/t/t1050-large.sh b/t/t1050-large.sh
> index 99ff2866b7..0e4267c723 100755
> --- a/t/t1050-large.sh
> +++ b/t/t1050-large.sh
> @@ -51,27 +51,21 @@ EOF
>  test_expect_success 'add a large file or two' '
>  	git add large1 huge large2 &&
>  	# make sure we got a single packfile and no loose objects
> -	bad= count=0 idx= &&
> +	count=0 idx= &&
>  	for p in .git/objects/pack/pack-*.pack
>  	do
>  		count=$(( $count + 1 )) &&
> -		if test_path_is_file "$p" &&
> -		   idx=${p%.pack}.idx && test_path_is_file "$idx"
> -		then
> -			continue
> -		fi
> -		bad=t
> +		test_path_is_file "$p" &&
> +		idx=${p%.pack}.idx &&
> +		test_path_is_file "$idx" || return 1
>  	done &&
> -	test -z "$bad" &&

Thanks goodness. I had to read the original loop several times to
understand what it was trying to do. The post-image is much nicer.

> diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
> index 17f988edd2..a6a73effde 100755
> --- a/t/t9400-git-cvsserver-server.sh
> +++ b/t/t9400-git-cvsserver-server.sh
> @@ -350,10 +350,9 @@ test_expect_success 'cvs update (subdirectories)' \
>  	test_cmp "$dir/$filename" "../$dir/$filename"; then
>          :
>        else
> -        echo >failure
> +        exit 1
>        fi
> -    done) &&
> -   test ! -f failure'
> +    done)'

These all look good. I had to blink a few times to see the subshell in
this one (it's finished by the closing paren after "done", for other
reviewers).

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups
  2021-12-09  5:11 ` [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups Eric Sunshine
  2021-12-10  9:29   ` Jeff King
@ 2021-12-10  9:38   ` Fabian Stelzer
  2021-12-11  7:32     ` Eric Sunshine
  1 sibling, 1 reply; 47+ messages in thread
From: Fabian Stelzer @ 2021-12-10  9:38 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Jeff King, Eric Sunshine

On 09.12.2021 00:11, Eric Sunshine wrote:
>The top-level &&-chain checker built into t/test-lib.sh causes tests to
>magically exit with code 117 if the &&-chain is broken. However, it has
>the shortcoming that the magic does not work within `{...}` groups,
>`(...)` subshells, `$(...)` substitutions, or within bodies of compound
>statements, such as `if`, `for`, `while`, `case`, etc. `chainlint.sed`
>partly fills in the gap by catching broken &&-chains in `(...)`
>subshells, but bugs can still lurk behind broken &&-chains in the other
>cases.
>
>Fix broken &&-chains in `{...}` groups in order to reduce the number of
>possible lurking bugs.
>
>Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
>---
>
>diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
>index 1a1a69ad92..bb3de2701a 100755
>--- a/t/t0021-conversion.sh
>+++ b/t/t0021-conversion.sh
>@@ -76,13 +76,13 @@ test_expect_success setup '
> 	git config filter.rot13.clean ./rot13.sh &&
>
> 	{
>-	    echo "*.t filter=rot13"
>+	    echo "*.t filter=rot13" &&
> 	    echo "*.i ident"
> 	} >.gitattributes &&
>
> 	{
>-	    echo a b c d e f g h i j k l m
>-	    echo n o p q r s t u v w x y z
>+	    echo a b c d e f g h i j k l m &&
>+	    echo n o p q r s t u v w x y z &&
> 	    echo '\''$Id$'\''
> 	} >test &&
> 	cat test >test.t &&
>@@ -159,7 +159,7 @@ test_expect_success expanded_in_repo '
> 		printf "\$Id: NoTerminatingSymbolAtEOF"
> 	} >expected-output-crlf &&
> 	{
>-		echo "expanded-keywords ident"
>+		echo "expanded-keywords ident" &&
> 		echo "expanded-keywords-crlf ident text eol=crlf"
> 	} >>.gitattributes &&
>

Wouldn't some of these be better off as heredocs as well?
There are a couple more below. I personally don't much mind either way but 
since you changed quite a few in an earlier commit why not these?

>diff --git a/t/t0069-oidtree.sh b/t/t0069-oidtree.sh
>index 74cc59bf8a..889db50818 100755
>--- a/t/t0069-oidtree.sh
>+++ b/t/t0069-oidtree.sh
>@@ -28,7 +28,7 @@ test_expect_success 'oidtree insert and contains' '
> 	EOF
> 	{
> 		echoid insert 444 1 2 3 4 5 a b c d e &&
>-		echoid contains 44 441 440 444 4440 4444
>+		echoid contains 44 441 440 444 4440 4444 &&
> 		echo clear
> 	} | test-tool oidtree >actual &&
> 	test_cmp expect actual
>@@ -37,11 +37,11 @@ test_expect_success 'oidtree insert and contains' '
> test_expect_success 'oidtree each' '
> 	echoid "" 123 321 321 >expect &&
> 	{
>-		echoid insert f 9 8 123 321 a b c d e
>-		echo each 12300
>-		echo each 3211
>-		echo each 3210
>-		echo each 32100
>+		echoid insert f 9 8 123 321 a b c d e &&
>+		echo each 12300 &&
>+		echo each 3211 &&
>+		echo each 3210 &&
>+		echo each 32100 &&
> 		echo clear
> 	} | test-tool oidtree >actual &&
> 	test_cmp expect actual
>diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
>index 67a3f64c2d..f6f00c7039 100755
>--- a/t/t1006-cat-file.sh
>+++ b/t/t1006-cat-file.sh
>@@ -283,7 +283,7 @@ test_expect_success "--batch-check with multiple sha1s gives correct format" '
>
> test_expect_success 'setup blobs which are likely to delta' '
> 	test-tool genrandom foo 10240 >foo &&
>-	{ cat foo; echo plus; } >foo-plus &&
>+	{ cat foo && echo plus; } >foo-plus &&
> 	git add foo foo-plus &&
> 	git commit -m foo &&
> 	cat >blobs <<-\EOF
>diff --git a/t/t1300-config.sh b/t/t1300-config.sh
>index 9571649c42..516dd8bfa8 100755
>--- a/t/t1300-config.sh
>+++ b/t/t1300-config.sh
>@@ -901,7 +901,7 @@ test_expect_success 'get --expiry-date' '
> 	EOF
> 	: "work around heredoc parsing bug fixed in dash 0.5.7 (in ec2c84d)" &&
> 	{
>-		echo "$rel_out $(git config --expiry-date date.valid1)"
>+		echo "$rel_out $(git config --expiry-date date.valid1)" &&
> 		git config --expiry-date date.valid2 &&
> 		git config --expiry-date date.valid3 &&
> 		git config --expiry-date date.valid4 &&
>diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
>index 17d3cc1405..bbc01aae34 100755
>--- a/t/t1403-show-ref.sh
>+++ b/t/t1403-show-ref.sh
>@@ -78,7 +78,7 @@ test_expect_success 'show-ref --verify -q' '
> test_expect_success 'show-ref -d' '
> 	{
> 		echo $(git rev-parse refs/tags/A) refs/tags/A &&
>-		echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}"
>+		echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}" &&
> 		echo $(git rev-parse refs/tags/C) refs/tags/C
> 	} >expect &&
> 	git show-ref -d A C >actual &&
>@@ -148,7 +148,7 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' '
>
> 	{
> 		echo $(git rev-parse HEAD) HEAD &&
>-		echo $(git rev-parse refs/heads/B) refs/heads/B
>+		echo $(git rev-parse refs/heads/B) refs/heads/B &&
> 		echo $(git rev-parse refs/tags/B) refs/tags/B
> 	} >expect &&
> 	git show-ref --head B >actual &&
>@@ -156,8 +156,8 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' '
>
> 	{
> 		echo $(git rev-parse HEAD) HEAD &&
>-		echo $(git rev-parse refs/heads/B) refs/heads/B
>-		echo $(git rev-parse refs/tags/B) refs/tags/B
>+		echo $(git rev-parse refs/heads/B) refs/heads/B &&
>+		echo $(git rev-parse refs/tags/B) refs/tags/B &&
> 		echo $(git rev-parse refs/tags/B^0) "refs/tags/B^{}"
> 	} >expect &&
> 	git show-ref --head -d B >actual &&
>diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
>index 67b9cc752f..d2ef0041f9 100755
>--- a/t/t2200-add-update.sh
>+++ b/t/t2200-add-update.sh
>@@ -153,10 +153,10 @@ test_expect_success 'add -u resolves unmerged paths' '
> 			echo "100644 $one 1	$path" &&
> 			echo "100644 $two 2	$path" &&
> 			echo "100644 $three 3	$path"
>-		done
>-		echo "100644 $one 1	path3"
>-		echo "100644 $one 1	path4"
>-		echo "100644 $one 3	path5"
>+		done &&
>+		echo "100644 $one 1	path3" &&
>+		echo "100644 $one 1	path4" &&
>+		echo "100644 $one 3	path5" &&
> 		echo "100644 $one 3	path6"
> 	} |
> 	git update-index --index-info &&
>@@ -173,8 +173,8 @@ test_expect_success 'add -u resolves unmerged paths' '
> 	git add -u &&
> 	git ls-files -s path1 path2 path3 path4 path5 path6 >actual &&
> 	{
>-		echo "100644 $three 0	path1"
>-		echo "100644 $two 0	path3"
>+		echo "100644 $three 0	path1" &&
>+		echo "100644 $two 0	path3" &&
> 		echo "100644 $two 0	path5"
> 	} >expect &&
> 	test_cmp expect actual
>diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh
>index a4eec0a346..687be974d4 100755
>--- a/t/t2201-add-update-typechange.sh
>+++ b/t/t2201-add-update-typechange.sh
>@@ -97,17 +97,17 @@ test_expect_success modify '
> 		"
> 	} >expect &&
> 	{
>-		cat expect
>-		echo ":100644 160000 $_empty $ZERO_OID T	yonk"
>+		cat expect &&
>+		echo ":100644 160000 $_empty $ZERO_OID T	yonk" &&
> 		echo ":100644 000000 $_empty $ZERO_OID D	zifmia"
> 	} >expect-files &&
> 	{
>-		cat expect
>+		cat expect &&
> 		echo ":000000 160000 $ZERO_OID $ZERO_OID A	yonk"
> 	} >expect-index &&
> 	{
>-		echo "100644 $_empty 0	nitfol"
>-		echo "160000 $yomin 0	yomin"
>+		echo "100644 $_empty 0	nitfol" &&
>+		echo "160000 $yomin 0	yomin" &&
> 		echo "160000 $yonk 0	yonk"
> 	} >expect-final
> '
>diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
>index 47d6f35dcc..7cb9909293 100755
>--- a/t/t4023-diff-rename-typechange.sh
>+++ b/t/t4023-diff-rename-typechange.sh
>@@ -55,7 +55,7 @@ test_expect_success 'cross renames to be detected for regular files' '
>
> 	git diff-tree five six -r --name-status -B -M | sort >actual &&
> 	{
>-		echo "R100	foo	bar"
>+		echo "R100	foo	bar" &&
> 		echo "R100	bar	foo"
> 	} | sort >expect &&
> 	test_cmp expect actual
>@@ -66,7 +66,7 @@ test_expect_success 'cross renames to be detected for typechange' '
>
> 	git diff-tree one two -r --name-status -B -M | sort >actual &&
> 	{
>-		echo "R100	foo	bar"
>+		echo "R100	foo	bar" &&
> 		echo "R100	bar	foo"
> 	} | sort >expect &&
> 	test_cmp expect actual
>@@ -78,7 +78,7 @@ test_expect_success 'moves and renames' '
> 	git diff-tree three four -r --name-status -B -M | sort >actual &&
> 	{
> 		# see -B -M (#6) in t4008
>-		echo "C100	foo	bar"
>+		echo "C100	foo	bar" &&
> 		echo "T100	foo"
> 	} | sort >expect &&
> 	test_cmp expect actual
>diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
>index ebff6c6883..ec5c10d2a0 100755
>--- a/t/t4124-apply-ws-rule.sh
>+++ b/t/t4124-apply-ws-rule.sh
>@@ -233,7 +233,7 @@ test_expect_success 'blank at EOF with --whitespace=fix (1)' '
> 	test_write_lines a b c >one &&
> 	git add one &&
> 	test_write_lines a b c >expect &&
>-	{ cat expect; echo; } >one &&
>+	{ cat expect && echo; } >one &&
> 	git diff -- one >patch &&
>
> 	git checkout one &&
>diff --git a/t/t4150-am.sh b/t/t4150-am.sh
>index 2aaaa0d7de..103cd39148 100755
>--- a/t/t4150-am.sh
>+++ b/t/t4150-am.sh
>@@ -116,7 +116,7 @@ test_expect_success setup '
> 		git format-patch --stdout first | sed -e "1d"
> 	} | append_cr >patch1-crlf.eml &&
> 	{
>-		printf "%255s\\n" ""
>+		printf "%255s\\n" "" &&
> 		echo "X-Fake-Field: Line One" &&
> 		echo "X-Fake-Field: Line Two" &&
> 		echo "X-Fake-Field: Line Three" &&
>diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh
>index 03b952c90d..0244888a5a 100755
>--- a/t/t4212-log-corrupt.sh
>+++ b/t/t4212-log-corrupt.sh
>@@ -20,10 +20,10 @@ test_expect_success 'fsck notices broken commit' '
>
> test_expect_success 'git log with broken author email' '
> 	{
>-		echo commit $(cat broken_email.hash)
>-		echo "Author: A U Thor <author@example.com>"
>-		echo "Date:   Thu Apr 7 15:13:13 2005 -0700"
>-		echo
>+		echo commit $(cat broken_email.hash) &&
>+		echo "Author: A U Thor <author@example.com>" &&
>+		echo "Date:   Thu Apr 7 15:13:13 2005 -0700" &&
>+		echo &&
> 		echo "    foo"
> 	} >expect.out &&
>
>diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
>index 759169d074..df524f7b6d 100755
>--- a/t/t5316-pack-delta-depth.sh
>+++ b/t/t5316-pack-delta-depth.sh
>@@ -57,8 +57,11 @@ test_expect_success 'create series of packs' '
> 		git commit -m $i &&
> 		cur=$(git rev-parse HEAD^{tree}) &&
> 		{
>-			test -n "$prev" && echo "-$prev"
>-			echo $cur
>+			if test -n "$prev"
>+			then
>+				echo "-$prev"
>+			fi &&
>+			echo $cur &&
> 			echo "$(git rev-parse :file) file"
> 		} | git pack-objects --stdout >tmp &&
> 		git index-pack --stdin --fix-thin <tmp || return 1
>diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
>index 1892d6615a..01468ce6d8 100755
>--- a/t/t5510-fetch.sh
>+++ b/t/t5510-fetch.sh
>@@ -71,7 +71,7 @@ test_expect_success "fetch test for-merge" '
> 	main_in_two=$(cd ../two && git rev-parse main) &&
> 	one_in_two=$(cd ../two && git rev-parse one) &&
> 	{
>-		echo "$one_in_two	"
>+		echo "$one_in_two	" &&
> 		echo "$main_in_two	not-for-merge"
> 	} >expected &&
> 	cut -f -2 .git/FETCH_HEAD >actual &&
>diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
>index 9d440e2821..c69cfd5c64 100755
>--- a/t/t5515-fetch-merge-logic.sh
>+++ b/t/t5515-fetch-merge-logic.sh
>@@ -191,17 +191,17 @@ do
> 		cp "$expect_r" expect_r &&
> 		convert_expected expect_r sed_script &&
> 		{
>-			echo "# $cmd"
>-			set x $cmd; shift
>-			git symbolic-ref HEAD refs/heads/$1 ; shift
>-			rm -f .git/FETCH_HEAD
>+			echo "# $cmd" &&
>+			set x $cmd && shift &&
>+			git symbolic-ref HEAD refs/heads/$1 && shift &&
>+			rm -f .git/FETCH_HEAD &&
> 			git for-each-ref \
> 				refs/heads refs/remotes/rem refs/tags |
> 			while read val type refname
> 			do
> 				git update-ref -d "$refname" "$val"
>-			done
>-			git fetch "$@" >/dev/null
>+			done &&
>+			git fetch "$@" >/dev/null &&
> 			cat .git/FETCH_HEAD
> 		} >"$actual_f" &&
> 		git show-ref >"$actual_r" &&
>diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
>index 05a58069b0..b68ec22d3f 100755
>--- a/t/t5562-http-backend-content-length.sh
>+++ b/t/t5562-http-backend-content-length.sh
>@@ -63,7 +63,7 @@ test_expect_success 'setup' '
> 	hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) &&
> 	{
> 		printf "%s %s refs/heads/newbranch\\0report-status object-format=%s\\n" \
>-			"$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize_raw
>+			"$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize_raw &&
> 		printf 0000 &&
> 		echo "$hash_next" | git pack-objects --stdout
> 	} >push_body &&
>diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
>index b87ca06a58..1131503b76 100755
>--- a/t/t5570-git-daemon.sh
>+++ b/t/t5570-git-daemon.sh
>@@ -194,7 +194,7 @@ test_expect_success 'hostname cannot break out of directory' '
>
> test_expect_success FAKENC 'hostname interpolation works after LF-stripping' '
> 	{
>-		printf "git-upload-pack /interp.git\n\0host=localhost" | packetize_raw
>+		printf "git-upload-pack /interp.git\n\0host=localhost" | packetize_raw &&
> 		printf "0000"
> 	} >input &&
> 	fake_nc "$GIT_DAEMON_HOST_PORT" <input >output &&
>diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh
>index b043a279f1..80e86d8284 100755
>--- a/t/t5571-pre-push-hook.sh
>+++ b/t/t5571-pre-push-hook.sh
>@@ -114,7 +114,7 @@ test_expect_success 'push to URL' '
>
> test_expect_success 'set up many-ref tests' '
> 	{
>-		nr=1000
>+		nr=1000 &&
> 		while test $nr -lt 2000
> 		do
> 			nr=$(( $nr + 1 )) &&
>diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh
>index 04885d0a5e..97f10905d2 100755
>--- a/t/t7513-interpret-trailers.sh
>+++ b/t/t7513-interpret-trailers.sh
>@@ -156,7 +156,7 @@ test_expect_success 'with config option on the command line' '
> 		Acked-by: Johan
> 		Reviewed-by: Peff
> 	EOF
>-	{ echo; echo "Acked-by: Johan"; } |
>+	{ echo && echo "Acked-by: Johan"; } |
> 	git -c "trailer.Acked-by.ifexists=addifdifferent" interpret-trailers \
> 		--trailer "Reviewed-by: Peff" --trailer "Acked-by: Johan" >actual &&
> 	test_cmp expected actual
>diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
>index 5bb302b1ba..ee4fdd8f18 100755
>--- a/t/t8002-blame.sh
>+++ b/t/t8002-blame.sh
>@@ -97,7 +97,7 @@ test_expect_success 'set up abbrev tests' '
> 	test_commit abbrev &&
> 	sha1=$(git rev-parse --verify HEAD) &&
> 	check_abbrev () {
>-		expect=$1; shift
>+		expect=$1 && shift &&
> 		echo $sha1 | cut -c 1-$expect >expect &&
> 		git blame "$@" abbrev.t >actual &&
> 		perl -lne "/[0-9a-f]+/ and print \$&" <actual >actual.sha &&
>-- 
>2.34.1.307.g9b7440fafd
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/19] tests: fix broken &&-chains & abort loops on error
  2021-12-09 19:17   ` Eric Sunshine
@ 2021-12-10  9:38     ` Jeff King
  2021-12-10  9:57       ` Fabian Stelzer
  0 siblings, 1 reply; 47+ messages in thread
From: Jeff King @ 2021-12-10  9:38 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Elijah Newren, Git Mailing List

On Thu, Dec 09, 2021 at 02:17:32PM -0500, Eric Sunshine wrote:

> > I have to admit to starting to skim once I got to the last four
> > patches, since they were a bit longer and all the same type of change.
> 
> Understandable. Those bulk-change patches tend to be mind-numbing to
> review, though `git diff --color-words` helps out somewhat (at least
> by making it easier to skim the changes).

I likewise think I may have phased in and out of consciousness on those
last four.

> > You did an excellent job of explaining the changes and presented them
> > in a logical fashion.  The few things I thought I caught, you've
> > already answered were already correct.  I do think making the second
> > commit message be a bit clearer about the importance of the ordering
> > would be helpful.  Anyway:
> >
> > Reviewed-by: Elijah Newren <newren@gmail.com>
> 
> Thanks. I'll wait a couple days and resend with a clarified commit
> message for the second patch unless, perhaps, Junio would accept a
> resend of just that patch so I don't have to spam the list again.

These looked good to me. I left a few comments, but nothing that I think
would trigger a re-roll.

-Peff

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/19] t4000-t4999: detect and signal failure within loop
  2021-12-09  5:11 ` [PATCH 17/19] t4000-t4999: " Eric Sunshine
@ 2021-12-10  9:53   ` Fabian Stelzer
  2021-12-11  8:06     ` Eric Sunshine
  0 siblings, 1 reply; 47+ messages in thread
From: Fabian Stelzer @ 2021-12-10  9:53 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git, Jeff King, Eric Sunshine

On 09.12.2021 00:11, Eric Sunshine wrote:
>Failures within `for` and `while` loops can go unnoticed if not detected
>and signaled manually since the loop itself does not abort when a
>contained command fails, nor will a failure necessarily be detected when
>the loop finishes since the loop returns the exit code of the last
>command it ran on the final iteration, which may not be the command
>which failed. Therefore, detect and signal failures manually within
>loops using the idiom `|| return 1` (or `|| exit 1` within subshells).
>
>Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
>---
>diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
>index 2c13b62d3c..ca5adabe14 100755
>--- a/t/t4015-diff-whitespace.sh
>+++ b/t/t4015-diff-whitespace.sh
>@@ -843,7 +843,7 @@ test_expect_success 'whitespace changes with modification reported (diffstat)' '
>
> test_expect_success 'whitespace-only changes reported across renames (diffstat)' '
> 	git reset --hard &&
>-	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
>+	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
> 	git add x &&
> 	git commit -m "base" &&
> 	sed -e "5s/^/ /" x >z &&
>@@ -859,7 +859,7 @@ test_expect_success 'whitespace-only changes reported across renames (diffstat)'
>
> test_expect_success 'whitespace-only changes reported across renames' '
> 	git reset --hard HEAD~1 &&
>-	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
>+	for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
> 	git add x &&
> 	hash_x=$(git hash-object x) &&
> 	before=$(git rev-parse --short "$hash_x") &&

I understand why the `|| return` in loops makes sense. But for these very 
simple ones just using `echo` I'll probably be confused if a linter starts 
to complain about them (probably depending on how specific the lint error 
will be).

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/19] tests: fix broken &&-chains & abort loops on error
  2021-12-10  9:38     ` Jeff King
@ 2021-12-10  9:57       ` Fabian Stelzer
  2021-12-11  8:16         ` Eric Sunshine
  0 siblings, 1 reply; 47+ messages in thread
From: Fabian Stelzer @ 2021-12-10  9:57 UTC (permalink / raw)
  To: Jeff King; +Cc: Eric Sunshine, Elijah Newren, Git Mailing List

On 10.12.2021 04:38, Jeff King wrote:
>On Thu, Dec 09, 2021 at 02:17:32PM -0500, Eric Sunshine wrote:
>
>> > I have to admit to starting to skim once I got to the last four
>> > patches, since they were a bit longer and all the same type of change.
>>
>> Understandable. Those bulk-change patches tend to be mind-numbing to
>> review, though `git diff --color-words` helps out somewhat (at least
>> by making it easier to skim the changes).
>
>I likewise think I may have phased in and out of consciousness on those
>last four.
>
>> > You did an excellent job of explaining the changes and presented them
>> > in a logical fashion.  The few things I thought I caught, you've
>> > already answered were already correct.  I do think making the second
>> > commit message be a bit clearer about the importance of the ordering
>> > would be helpful.  Anyway:
>> >
>> > Reviewed-by: Elijah Newren <newren@gmail.com>
>>
>> Thanks. I'll wait a couple days and resend with a clarified commit
>> message for the second patch unless, perhaps, Junio would accept a
>> resend of just that patch so I don't have to spam the list again.
>
>These looked good to me. I left a few comments, but nothing that I think
>would trigger a re-roll.
>

Very nice work and good explanations. I learned a few new things :)

Thanks

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 09/19] tests: use test_write_lines() to generate line-oriented output
  2021-12-10  9:22   ` Jeff King
@ 2021-12-11  6:59     ` Eric Sunshine
  0 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-11  6:59 UTC (permalink / raw)
  To: Jeff King; +Cc: Git List

On Fri, Dec 10, 2021 at 4:22 AM Jeff King <peff@peff.net> wrote:
> On Thu, Dec 09, 2021 at 12:11:05AM -0500, Eric Sunshine wrote:
> >  test_expect_success 'color new trailing blank lines' '
> > -     { echo a; echo b; echo; echo; } >x &&
> > +     test_write_lines a b "" "" >x &&
> >       git add x &&
> > -     { echo a; echo; echo; echo; echo c; echo; echo; echo; echo; } >x &&
> > +     test_write_lines a "" "" "" c "" "" "" "" >x &&
>
> Some of these I think might be more readable as here-docs. But I think
> keeping to the minimal change here makes sense (and I admit I do not
> overly care much either way; it was just on my mind from the last
> patch).

Indeed, it's a judgment call, but I recall that it was all the
embedded and trailing blank lines in these particular cases which
pushed me toward test_write_lines() rather than here-docs since
test_write_lines() makes it way more compact, which perhaps makes it a
bit easier to get the number and placement of the blank lines correct.
The corresponding here-doc would have been:

    cat <<-\EOF >x &&
    a



    c




   EOF

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups
  2021-12-10  9:29   ` Jeff King
@ 2021-12-11  7:14     ` Eric Sunshine
  0 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-11  7:14 UTC (permalink / raw)
  To: Jeff King; +Cc: Git List

On Fri, Dec 10, 2021 at 4:29 AM Jeff King <peff@peff.net> wrote:
> On Thu, Dec 09, 2021 at 12:11:08AM -0500, Eric Sunshine wrote:
> > Fix broken &&-chains in `{...}` groups in order to reduce the number of
> > possible lurking bugs.
>
> Seems good. This is mostly stuff we don't expect to fail (mostly
> "echo"), so I doubt they're important on their own. But getting a clean
> state for the linter _is_ important.

In this patch, I think the only &&-chain which really matters (i.e.
could hide a genuine failure if broken) is t5515-fetch-merge-logic.sh.
Aside from most of these being unlikely to fail (`echo`), most of the
exit codes are being lost down pipes anyhow. As such, I had a hard
time justifying this patch since it exists mostly to satisfy the
linter which isn't smart enough to distinguish between the cases. What
ultimately convinced me that this patch was worthwhile was (1) that
there are legitimate cases, such as t5515-fetch-merge-logic.sh, where
we really do want to be told about the broken &&-chain, and (2) that
it's easier to have a single simple rule which we can point test
authors at ("chain all your test commands with `&&`") rather than
complex rules laying out cases when you do and don't need to maintain
the &&-chain.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups
  2021-12-10  9:38   ` Fabian Stelzer
@ 2021-12-11  7:32     ` Eric Sunshine
  0 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-11  7:32 UTC (permalink / raw)
  To: Fabian Stelzer; +Cc: Git List, Jeff King

On Fri, Dec 10, 2021 at 4:38 AM Fabian Stelzer <fs@gigacodes.de> wrote:
> On 09.12.2021 00:11, Eric Sunshine wrote:
> >Fix broken &&-chains in `{...}` groups in order to reduce the number of
> >possible lurking bugs.
> >       {
> >-          echo "*.t filter=rot13"
> >+          echo "*.t filter=rot13" &&
> >           echo "*.i ident"
> >       } >.gitattributes &&
> >       {
> >-              echo "expanded-keywords ident"
> >+              echo "expanded-keywords ident" &&
> >               echo "expanded-keywords-crlf ident text eol=crlf"
> >       } >>.gitattributes &&
> >
>
> Wouldn't some of these be better off as heredocs as well?
> There are a couple more below. I personally don't much mind either way but
> since you changed quite a few in an earlier commit why not these?

It's been months since I made these changes, but I think there were at
least a couple reasons for not converting these to here-docs. First,
in these cases, there were only one or two missing `&&` per block. Had
I bulk converted them to here-docs, it would have made for a much more
noisy patch, which would have taxed reviewers more, and
reviewer-fatigue is a real concern when crafting a lengthy patch
series like this one. In the "here-doc conversion" patch, on the other
hand, many of those cases involved a significant number of missing
`&&`; often every line was missing `&&`. So, the changes in that patch
was going to be very noisy anyhow, whether I added missing `&&` or
converted to here-docs.

Second...

> >       {
> >               echoid insert 444 1 2 3 4 5 a b c d e &&
> >-              echoid contains 44 441 440 444 4440 4444
> >+              echoid contains 44 441 440 444 4440 4444 &&
> >               echo clear
> >       } | test-tool oidtree >actual &&

... there are a number of cases like this which look like they could
easily be converted to here-doc, but in fact `echoid` is a function
call, so a here-doc wouldn't work. Also...

> >       {
> >               echo $(git rev-parse refs/tags/A) refs/tags/A &&
> >-              echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}"
> >+              echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}" &&
> >               echo $(git rev-parse refs/tags/C) refs/tags/C
> >       } >expect &&

... this sort of thing could certainly become a here-doc because
$(...) will work in a here-doc, but when there is a preponderance of
this sort of `{ echo && ... }` block in the test script, it would feel
inconsistent to convert a few of them to here-docs.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 13/19] tests: apply modern idiom for signaling test failure
  2021-12-10  9:32   ` Jeff King
@ 2021-12-11  7:47     ` Eric Sunshine
  0 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-11  7:47 UTC (permalink / raw)
  To: Jeff King; +Cc: Git List

On Fri, Dec 10, 2021 at 4:32 AM Jeff King <peff@peff.net> wrote:
> On Thu, Dec 09, 2021 at 12:11:09AM -0500, Eric Sunshine wrote:
> >       if test -s difference
> >       then
> >               cat difference
> > -             (exit 1)
> > +             false
> >       else
> >               echo happy
> >       fi
>
> ...I'd have said the idiom here is just:
>
>   git diff-tree -r test-rebase test-merge >difference &&
>   test -s difference
>
> The extra "cat" and "happy" are verbose output that we usually skip in
> favor of letting "-x" logging do the talking (and leaving the failed
> state so you can "cat difference" yourself).
>
> That said, I'm OK with this minimal change in the name of keeping creep
> out of the series.

Indeed, there's plenty of odd cruft like this in old test scripts
which could eventually use good cleanups such as the one you suggest
here. But I'm also OK with (indeed prefer) this minimal change for the
present in order to reduce likelihood of reviewer fatigue in this
already lengthy patch series.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 17/19] t4000-t4999: detect and signal failure within loop
  2021-12-10  9:53   ` Fabian Stelzer
@ 2021-12-11  8:06     ` Eric Sunshine
  0 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-11  8:06 UTC (permalink / raw)
  To: Fabian Stelzer; +Cc: Git List, Jeff King

On Fri, Dec 10, 2021 at 4:53 AM Fabian Stelzer <fs@gigacodes.de> wrote:
> On 09.12.2021 00:11, Eric Sunshine wrote:
> >-      for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
> >+      for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
>
> I understand why the `|| return` in loops makes sense. But for these very
> simple ones just using `echo` I'll probably be confused if a linter starts
> to complain about them (probably depending on how specific the lint error
> will be).

I understand your concern and had second thoughts about flagging this
sort of thing since there are so many loops which obviously shouldn't
fail, thus inserting `|| return 1` in them is just busy work to pacify
a linter which isn't smart enough to distinguish the important cases
from the unimportant ones. As such, I had some trouble justifying (to
myself) that this linter complaint is really a good idea, but
eventually convinced myself that it's worthwhile in the long run for
the same reasons I mentioned in my response to another patch in this
series. Namely, (1) there are good number of cases in which the loop
body is populated with "real" commands which could fail, so we really
do want to be told about missing `|| return 1` in general, and (2)
it's easier to have a single simple rule which we can point test
authors at ("end all loop bodies with `|| return 1` (or `|| exit 1` in
a subshell)") rather than complex rules laying out cases when you must
or need not use `|| return 1`.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/19] tests: fix broken &&-chains & abort loops on error
  2021-12-10  9:57       ` Fabian Stelzer
@ 2021-12-11  8:16         ` Eric Sunshine
  0 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-11  8:16 UTC (permalink / raw)
  To: Fabian Stelzer; +Cc: Jeff King, Elijah Newren, Git Mailing List

On Fri, Dec 10, 2021 at 4:58 AM Fabian Stelzer <fs@gigacodes.de> wrote:
> On 10.12.2021 04:38, Jeff King wrote:
> >On Thu, Dec 09, 2021 at 02:17:32PM -0500, Eric Sunshine wrote:
> >> Thanks. I'll wait a couple days and resend with a clarified commit
> >> message for the second patch unless, perhaps, Junio would accept a
> >> resend of just that patch so I don't have to spam the list again.
> >
> >These looked good to me. I left a few comments, but nothing that I think
> >would trigger a re-roll.
>
> Very nice work and good explanations. I learned a few new things :)

Thanks Elijah, Peff, and Fabian for reading through the series.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v1.1 2/19] t1010: fix unnoticed failure on Windows
  2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
                   ` (19 preceding siblings ...)
  2021-12-09 17:02 ` [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Elijah Newren
@ 2021-12-11  9:58 ` Eric Sunshine
  20 siblings, 0 replies; 47+ messages in thread
From: Eric Sunshine @ 2021-12-11  9:58 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Elijah Newren, Fabian Stelzer, Eric Sunshine

On Microsoft Windows, a directory name should never end with a period.
Quoting from Microsoft documentation[1]:

    Do not end a file or directory name with a space or a period.
    Although the underlying file system may support such names, the
    Windows shell and user interface does not.

Naming a directory with a trailing period is indeed perilous:

    % git init foo
    % cd foo
    % mkdir a.
    % git status
    warning: could not open directory 'a./': No such file or directory

The t1010 "setup" test:

    for d in a a. a0
    do
        mkdir "$d" && echo "$d/one" >"$d/one" &&
        git add "$d"
    done &&

runs afoul of this Windows limitation, as can be observed when running
the test verbosely:

    error: open("a./one"): No such file or directory
    error: unable to index file 'a./one'
    fatal: adding files failed

The reason this problem has gone unnoticed for so long is twofold.
First, the failed `git add` is swallowed silently because the loop is
not terminated explicitly by `|| return 1` to signal the failure.
Second, none of the tests in this script care about the literal
directory names ("a", "a.", "a0") or the specific number of tree
entries. They care instead about the order of entries in the tree, and
that the tree synthesized in the index and created by `git write-tree`
matches the tree created by the output of `git ls-tree` fed into `git
mktree`, thus the absence of "a./one" has no impact on the tests.

Skipping these tests on Windows by, for instance, checking the
FUNNYNAMES predicate would avoid the problem, however, the funny-looking
name is not what is being tested here. Rather, the tests are about
checking that `git mktree` produces stable results for various input
conditions, such as when the input order is not consistent or when an
object is missing.

Therefore, resolve the problem simply by using a directory name which is
legal on Windows and sorts the same as "a.". While at it, add the
missing `|| return 1` to the loop body in order to catch this sort of
problem in the future.

[1]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Reviewed-by: Elijah Newren <newren@gmail.com>
---

This is a re-roll of patch 2/19 of es/test-chain-lint[1] to improve the
commit message in response to Elijah's review comments[2,3] since the v1
commit message was perhaps a bit too subtle[4].

Rather than spamming the list with a full v2 re-roll, I decided to
re-roll just this one patch with its minor commit message rewrite since
it was the only change requested, thus should be less of a burden on
reviewers, though perhaps a bit more burden on Junio (but it's such a
minor change that the original commit message is probably good enough
should Junio not pick up this single-patch re-roll).

[1]: https://lore.kernel.org/git/20211209051115.52629-1-sunshine@sunshineco.com/
[2]: https://lore.kernel.org/git/CABPp-BGBZ6_CqbUg3=sK2b4yELC5NHHyH68_df22n=t=hARH_g@mail.gmail.com/
[3]: https://lore.kernel.org/git/CABPp-BFM5ZbFAzVfvDE3=zm6Q4LN2fWthPP8WH5kbgVPSxomtA@mail.gmail.com/
[4]: https://lore.kernel.org/git/CAPig+cR0eKhz+ncWb4v9dSY0A03P+K0+WT90J2cBKvLqT8DXrA@mail.gmail.com/

Range-diff against v1:
1:  4e7d8e8c7e ! 1:  95d419ed90 t1010: fix unnoticed failure on Windows
    @@ Commit message
         The reason this problem has gone unnoticed for so long is twofold.
         First, the failed `git add` is swallowed silently because the loop is
         not terminated explicitly by `|| return 1` to signal the failure.
    -    Second, none of the tests in this script care about the actual directory
    -    names or even the number of tree entries. They care only that the tree
    -    synthesized in the index and created by `git write-tree` matches the
    -    tree created by the output of `git ls-tree` fed into `git mktree`, and
    -    the failure of `git add "a./one"` doesn't change that outcome.
    +    Second, none of the tests in this script care about the literal
    +    directory names ("a", "a.", "a0") or the specific number of tree
    +    entries. They care instead about the order of entries in the tree, and
    +    that the tree synthesized in the index and created by `git write-tree`
    +    matches the tree created by the output of `git ls-tree` fed into `git
    +    mktree`, thus the absence of "a./one" has no impact on the tests.
     
         Skipping these tests on Windows by, for instance, checking the
         FUNNYNAMES predicate would avoid the problem, however, the funny-looking
    @@ Commit message
         object is missing.
     
         Therefore, resolve the problem simply by using a directory name which is
    -    legal on Windows (i.e. "a-" rather than "a."). While at it, add the
    +    legal on Windows and sorts the same as "a.". While at it, add the
         missing `|| return 1` to the loop body in order to catch this sort of
         problem in the future.
     
         [1]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
     
         Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
    +    Reviewed-by: Elijah Newren <newren@gmail.com>
     
      ## t/t1010-mktree.sh ##
     @@ t/t1010-mktree.sh: TEST_PASSES_SANITIZE_LEAK=true

 t/t1010-mktree.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh
index 48bfad07ab..3c08194526 100755
--- a/t/t1010-mktree.sh
+++ b/t/t1010-mktree.sh
@@ -6,10 +6,10 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
-	for d in a a. a0
+	for d in a a- a0
 	do
 		mkdir "$d" && echo "$d/one" >"$d/one" &&
-		git add "$d"
+		git add "$d" || return 1
 	done &&
 	echo zero >one &&
 	git update-index --add --info-only one &&
-- 
2.34.1.397.gfae76fe5da


^ permalink raw reply related	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2021-12-11 10:00 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-09  5:10 [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Eric Sunshine
2021-12-09  5:10 ` [PATCH 01/19] t/lib-pager: use sane_unset() to avoid breaking &&-chain Eric Sunshine
2021-12-09  5:10 ` [PATCH 02/19] t1010: fix unnoticed failure on Windows Eric Sunshine
2021-12-09 16:27   ` Elijah Newren
2021-12-09 16:45     ` Eric Sunshine
2021-12-09  5:10 ` [PATCH 03/19] t1020: avoid aborting entire test script when one test fails Eric Sunshine
2021-12-09  5:11 ` [PATCH 04/19] t4202: clarify intent by creating expected content less cleverly Eric Sunshine
2021-12-10  9:09   ` Jeff King
2021-12-09  5:11 ` [PATCH 05/19] t5516: drop unnecessary subshell and command invocation Eric Sunshine
2021-12-10  9:10   ` Jeff King
2021-12-09  5:11 ` [PATCH 06/19] t6300: make `%(raw:size) --shell` test more robust Eric Sunshine
2021-12-10  9:14   ` Jeff King
2021-12-09  5:11 ` [PATCH 07/19] t9107: use shell parameter expansion to avoid breaking &&-chain Eric Sunshine
2021-12-09  5:11 ` [PATCH 08/19] tests: simplify construction of large blocks of text Eric Sunshine
2021-12-09  5:11 ` [PATCH 09/19] tests: use test_write_lines() to generate line-oriented output Eric Sunshine
2021-12-10  9:22   ` Jeff King
2021-12-11  6:59     ` Eric Sunshine
2021-12-09  5:11 ` [PATCH 10/19] tests: fix broken &&-chains in compound statements Eric Sunshine
2021-12-09  5:11 ` [PATCH 11/19] tests: fix broken &&-chains in `$(...)` command substitutions Eric Sunshine
2021-12-09 16:44   ` Elijah Newren
2021-12-09 16:53     ` Eric Sunshine
2021-12-09 16:57       ` Elijah Newren
2021-12-10  9:27       ` Jeff King
2021-12-09  5:11 ` [PATCH 12/19] tests: fix broken &&-chains in `{...}` groups Eric Sunshine
2021-12-10  9:29   ` Jeff King
2021-12-11  7:14     ` Eric Sunshine
2021-12-10  9:38   ` Fabian Stelzer
2021-12-11  7:32     ` Eric Sunshine
2021-12-09  5:11 ` [PATCH 13/19] tests: apply modern idiom for signaling test failure Eric Sunshine
2021-12-10  9:32   ` Jeff King
2021-12-11  7:47     ` Eric Sunshine
2021-12-09  5:11 ` [PATCH 14/19] tests: apply modern idiom for exiting loop upon failure Eric Sunshine
2021-12-10  9:36   ` Jeff King
2021-12-09  5:11 ` [PATCH 15/19] tests: simplify by dropping unnecessary `for` loops Eric Sunshine
2021-12-09 16:50   ` Elijah Newren
2021-12-09  5:11 ` [PATCH 16/19] t0000-t3999: detect and signal failure within loop Eric Sunshine
2021-12-09  5:11 ` [PATCH 17/19] t4000-t4999: " Eric Sunshine
2021-12-10  9:53   ` Fabian Stelzer
2021-12-11  8:06     ` Eric Sunshine
2021-12-09  5:11 ` [PATCH 18/19] t5000-t5999: " Eric Sunshine
2021-12-09  5:11 ` [PATCH 19/19] t6000-t9999: " Eric Sunshine
2021-12-09 17:02 ` [PATCH 00/19] tests: fix broken &&-chains & abort loops on error Elijah Newren
2021-12-09 19:17   ` Eric Sunshine
2021-12-10  9:38     ` Jeff King
2021-12-10  9:57       ` Fabian Stelzer
2021-12-11  8:16         ` Eric Sunshine
2021-12-11  9:58 ` [PATCH v1.1 2/19] t1010: fix unnoticed failure on Windows Eric Sunshine

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).