mbox series

[v2,00/16] t: replace incorrect test_must_fail usage (part 2)

Message ID cover.1578372682.git.liu.denton@gmail.com (mailing list archive)
Headers show
Series t: replace incorrect test_must_fail usage (part 2) | expand

Message

Denton Liu Jan. 7, 2020, 4:52 a.m. UTC
The overall scope of these patches is to replace inappropriate uses of
test_must_fail. IOW, we should only allow test_must_fail to run on `git`
and `test-tool`. Ultimately, we will conclude by making test_must_fail
error out on non-git commands. An advance view of the final series can
be found here[1].

This is the second part. It focuses on t[234]*.sh. The first part can be
found here[2].

Changes since v1:

* Rewrite commit messages to be shorter and use the present tense when
  referring to the present state

* Clean up as suggested by Eric

* Replace 12/16 with J6t's patch

* Drop "let sed open its own files"

[1]: (may be rebased at any time) https://github.com/Denton-L/git/tree/ready/cleanup-test-must-fail2
[2]: https://lore.kernel.org/git/cover.1576583819.git.liu.denton@gmail.com/

Denton Liu (15):
  t2018: remove trailing space from test description
  t2018: add space between function name and ()
  t2018: improve style of if-statement
  t2018: use test_expect_code for failing git commands
  t2018: teach do_checkout() to accept `!` arg
  t2018: don't lose return code of git commands
  t2018: replace "sha" with "oid"
  t3030: use test_path_is_missing()
  t3310: extract common notes_merge_files_gone()
  t3415: stop losing return codes of git commands
  t3415: increase granularity of test_auto_{fixup,squash}()
  t3419: stop losing return code of git command
  t3507: fix indentation
  t3507: use test_path_is_missing()
  t4124: only mark git command with test_must_fail

Johannes Sixt (1):
  t3504: do check for conflict marker after failed cherry-pick

 t/t2018-checkout-branch.sh            |  77 ++++++++-----
 t/t3030-merge-recursive.sh            |   2 +-
 t/t3310-notes-merge-manual-resolve.sh |  22 ++--
 t/t3415-rebase-autosquash.sh          | 153 +++++++++++++++++++-------
 t/t3419-rebase-patch-id.sh            |   3 +-
 t/t3504-cherry-pick-rerere.sh         |   6 +-
 t/t3507-cherry-pick-conflict.sh       |  28 ++---
 t/t4124-apply-ws-rule.sh              |  10 +-
 8 files changed, 205 insertions(+), 96 deletions(-)

Range-diff against v1:
 1:  7517159cc1 =  1:  a0199f1e48 t2018: remove trailing space from test description
 2:  0674eee69e !  2:  f0f541b520 t2018: add space between function name and ()
    @@ Metadata
      ## Commit message ##
         t2018: add space between function name and ()
     
    +    Add a space between the function name and () which brings the style in
    +    line with Git's coding guidelines.
    +
      ## t/t2018-checkout-branch.sh ##
     @@ t/t2018-checkout-branch.sh: test_description='checkout'
      #   2) HEAD is <sha>; if <sha> is not specified, the old HEAD is used.
 -:  ---------- >  3:  501eb147c3 t2018: improve style of if-statement
 3:  2451bff3af !  4:  587e53053f t2018: use test_must_fail for failing git commands
    @@ Metadata
     Author: Denton Liu <liu.denton@gmail.com>
     
      ## Commit message ##
    -    t2018: use test_must_fail for failing git commands
    +    t2018: use test_expect_code for failing git commands
     
    -    Before, when we expected `git diff` to fail, we negated its status with
    +    When we are expecting `git diff` to fail, we negate its status with
         `!`. However, if git ever exits unexpectedly, say due to a segfault, we
         would not be able to tell the difference between that and a controlled
    -    failure. Use `test_must_fail git diff` instead so that if an unepxected
    -    failure occurs, we can catch it.
    +    failure. Use `test_expect_code 1 git diff` instead so that if an
    +    unexpected failure occurs, we can catch it.
     
    -    We had some instances of `test_must_fail test_dirty_{un,}mergable`.
    -    However, `test_must_fail` should only be used on git commands. Teach
    -    test_dirty_{un,}mergable() to accept `!` as a potential first argument
    -    which will run the git command without test_must_fail(). This prevents
    -    the double-negation where we were effectively running
    -    `test_must_fail test_must_fail git diff ...`.
    +    We have some instances of `test_must_fail test_dirty_{un,}mergable`.
    +    However, `test_must_fail` should only be used on git commands. Convert
    +    these instances to use the `test_dirty_{un,}mergeable_discards_changes`
    +    helper functions so that we remove the double-negation.
     
         While we're at it, remove redirections to /dev/null since output is
    -    silenced when running without `-v` and debugging output is useful with
    -    `-v`, remove redirections to /dev/null as it is not useful.
    +    silenced when running without `-v` anyway.
     
      ## t/t2018-checkout-branch.sh ##
     @@ t/t2018-checkout-branch.sh: do_checkout () {
    @@ t/t2018-checkout-branch.sh: do_checkout () {
      
      test_dirty_unmergeable () {
     -	! git diff --exit-code >/dev/null
    -+	should_fail="test_expect_code 1" &&
    -+	if test "x$1" = "x!"
    -+	then
    -+		should_fail=
    -+	fi &&
    -+	$should_fail git diff --exit-code
    ++	test_expect_code 1 git diff --exit-code
    ++}
    ++
    ++test_dirty_unmergeable_discards_changes () {
    ++	git diff --exit-code
      }
      
      setup_dirty_unmergeable () {
    @@ t/t2018-checkout-branch.sh: setup_dirty_unmergeable () {
      
      test_dirty_mergeable () {
     -	! git diff --cached --exit-code >/dev/null
    -+	should_fail="test_expect_code 1"  &&
    -+	if test "x$1" = "x!"
    -+	then
    -+		should_fail=
    -+	fi &&
    -+	$should_fail git diff --cached --exit-code
    ++	test_expect_code 1 git diff --cached --exit-code
    ++}
    ++
    ++test_dirty_mergeable_discards_changes () {
    ++	git diff --cached --exit-code
      }
      
      setup_dirty_mergeable () {
    @@ t/t2018-checkout-branch.sh: test_expect_success 'checkout -f -b to a new branch
      	# still dirty and on branch1
      	do_checkout branch2 $HEAD1 "-f -b" &&
     -	test_must_fail test_dirty_unmergeable
    -+	test_dirty_unmergeable !
    ++	test_dirty_unmergeable_discards_changes
      '
      
      test_expect_success 'checkout -b to a new branch preserves mergeable changes' '
    @@ t/t2018-checkout-branch.sh: test_expect_success 'checkout -f -b to a new branch
      	setup_dirty_mergeable &&
      	do_checkout branch2 $HEAD1 "-f -b" &&
     -	test_must_fail test_dirty_mergeable
    -+	test_dirty_mergeable !
    ++	test_dirty_mergeable_discards_changes
      '
      
      test_expect_success 'checkout -b to an existing branch fails' '
    @@ t/t2018-checkout-branch.sh: test_expect_success 'checkout -B to an existing bran
      	# still dirty and on branch1
      	do_checkout branch2 $HEAD1 "-f -B" &&
     -	test_must_fail test_dirty_unmergeable
    -+	test_dirty_unmergeable !
    ++	test_dirty_unmergeable_discards_changes
      '
      
      test_expect_success 'checkout -B to an existing branch preserves mergeable changes' '
    @@ t/t2018-checkout-branch.sh: test_expect_success 'checkout -f -B to an existing b
      	setup_dirty_mergeable &&
      	do_checkout branch2 $HEAD1 "-f -B" &&
     -	test_must_fail test_dirty_mergeable
    -+	test_dirty_mergeable !
    ++	test_dirty_mergeable_discards_changes
      '
      
      test_expect_success 'checkout -b <describe>' '
 4:  bc6330557e !  5:  c43c11b912 t2018: teach do_checkout() to accept `!` arg
    @@ Metadata
      ## Commit message ##
         t2018: teach do_checkout() to accept `!` arg
     
    -    Before, we were running `test_must_fail do_checkout`. However,
    +    We are running `test_must_fail do_checkout`. However,
         `test_must_fail` should only be used on git commands. Teach
         do_checkout() to accept `!` as a potential first argument which will
    -    prepend `test_must_fail` to the enclosed git command and skips the
    -    remainder of the function.
    +    cause the function to expect the "git checkout" to fail.
     
         This increases the granularity of the test as, instead of blindly
         checking that do_checkout() failed, we check that only the specific
    @@ Commit message
     
      ## t/t2018-checkout-branch.sh ##
     @@ t/t2018-checkout-branch.sh: test_description='checkout'
    + 
    + . ./test-lib.sh
    + 
    +-# Arguments: <branch> <sha> [<checkout options>]
    ++# Arguments: [!] <branch> <sha> [<checkout options>]
    + #
    + # Runs "git checkout" to switch to <branch>, testing that
    + #
    +@@ t/t2018-checkout-branch.sh: test_description='checkout'
    + #   2) HEAD is <sha>; if <sha> is not specified, the old HEAD is used.
      #
      # If <checkout options> is not specified, "git checkout" is run with -b.
    ++#
    ++# If the first argument is `!`, "git checkout" is expected to fail when
    ++# it is run.
      do_checkout () {
     +	should_fail= &&
     +	if test "x$1" = "x!"
     +	then
    -+		should_fail=test_must_fail &&
    ++		should_fail=yes &&
     +		shift
     +	fi &&
      	exp_branch=$1 &&
    @@ t/t2018-checkout-branch.sh: do_checkout () {
      	fi
      
     -	git checkout $opts $exp_branch $exp_sha &&
    -+	$should_fail git checkout $opts $exp_branch $exp_sha &&
    - 
    +-
     -	test $exp_ref = $(git rev-parse --symbolic-full-name HEAD) &&
     -	test $exp_sha = $(git rev-parse --verify HEAD)
    -+	if test -z "$should_fail"
    ++	if test -n "$should_fail"
     +	then
    ++		test_must_fail git checkout $opts $exp_branch $exp_sha
    ++	else
    ++		git checkout $opts $exp_branch $exp_sha &&
     +		test $exp_ref = $(git rev-parse --symbolic-full-name HEAD) &&
     +		test $exp_sha = $(git rev-parse --verify HEAD)
     +	fi
 5:  fb2b865e6a !  6:  e09a70f6ca t2018: don't lose return code of git commands
    @@ Metadata
      ## Commit message ##
         t2018: don't lose return code of git commands
     
    -    We had some git commands wrapped in non-assignment command substitutions
    -    which would result in their return codes to be lost. Rewrite these
    -    instances so that their return codes are now checked.
    +    Fix invocations of git commands so their exit codes are not lost
    +    within non-assignment command substitutions.
     
      ## t/t2018-checkout-branch.sh ##
     @@ t/t2018-checkout-branch.sh: do_checkout () {
    - 	exp_ref="refs/heads/$exp_branch" &&
    - 
    - 	# if <sha> is not specified, use HEAD.
    --	exp_sha=${2:-$(git rev-parse --verify HEAD)} &&
    -+	head=$(git rev-parse --verify HEAD) &&
    -+	exp_sha=${2:-$head} &&
    - 
    - 	# default options for git checkout: -b
    - 	if [ -z "$3" ]; then
    -@@ t/t2018-checkout-branch.sh: do_checkout () {
    - 
    - 	if test -z "$should_fail"
    - 	then
    + 		test_must_fail git checkout $opts $exp_branch $exp_sha
    + 	else
    + 		git checkout $opts $exp_branch $exp_sha &&
     -		test $exp_ref = $(git rev-parse --symbolic-full-name HEAD) &&
     -		test $exp_sha = $(git rev-parse --verify HEAD)
     +		echo "$exp_ref" >ref.expect &&
 6:  7c26b921c3 !  7:  71f84811c7 t2018: replace "sha" with "oid"
    @@ t/t2018-checkout-branch.sh: test_description='checkout'
      
      . ./test-lib.sh
      
    --# Arguments: <branch> <sha> [<checkout options>]
    -+# Arguments: <branch> <oid> [<checkout options>]
    +-# Arguments: [!] <branch> <sha> [<checkout options>]
    ++# Arguments: [!] <branch> <oid> [<checkout options>]
      #
      # Runs "git checkout" to switch to <branch>, testing that
      #
    @@ t/t2018-checkout-branch.sh: test_description='checkout'
     +#   2) HEAD is <oid>; if <oid> is not specified, the old HEAD is used.
      #
      # If <checkout options> is not specified, "git checkout" is run with -b.
    - do_checkout () {
    + #
     @@ t/t2018-checkout-branch.sh: do_checkout () {
      	exp_branch=$1 &&
      	exp_ref="refs/heads/$exp_branch" &&
      
     -	# if <sha> is not specified, use HEAD.
    +-	exp_sha=${2:-$(git rev-parse --verify HEAD)} &&
     +	# if <oid> is not specified, use HEAD.
    - 	head=$(git rev-parse --verify HEAD) &&
    --	exp_sha=${2:-$head} &&
    -+	exp_oid=${2:-$head} &&
    ++	exp_oid=${2:-$(git rev-parse --verify HEAD)} &&
      
      	# default options for git checkout: -b
    - 	if [ -z "$3" ]; then
    + 	if test -z "$3"
     @@ t/t2018-checkout-branch.sh: do_checkout () {
    - 		opts="$3"
    - 	fi
      
    --	$should_fail git checkout $opts $exp_branch $exp_sha &&
    -+	$should_fail git checkout $opts $exp_branch $exp_oid &&
    - 
    - 	if test -z "$should_fail"
    + 	if test -n "$should_fail"
      	then
    +-		test_must_fail git checkout $opts $exp_branch $exp_sha
    ++		test_must_fail git checkout $opts $exp_branch $exp_oid
    + 	else
    +-		git checkout $opts $exp_branch $exp_sha &&
    ++		git checkout $opts $exp_branch $exp_oid &&
      		echo "$exp_ref" >ref.expect &&
      		git rev-parse --symbolic-full-name HEAD >ref.actual &&
      		test_cmp ref.expect ref.actual &&
 7:  9e37358f38 !  8:  f0da1d6350 t3030: use test_path_is_missing()
    @@ Metadata
      ## Commit message ##
         t3030: use test_path_is_missing()
     
    -    Previously, we would use `test_must_fail test -d` to ensure that the
    -    directory is removed. However, test_must_fail() should only be used for
    -    git commands. Use test_path_is_missing() instead to check that the
    -    directory has been removed.
    +    We use `test_must_fail test -d` to ensure that the directory is removed.
    +    However, test_must_fail() should only be used for git commands. Use
    +    test_path_is_missing() instead to check that the directory has been
    +    removed.
     
      ## t/t3030-merge-recursive.sh ##
     @@ t/t3030-merge-recursive.sh: test_expect_success 'merge removes empty directories' '
 8:  9705769841 !  9:  46fe82b856 t3310: extract common no_notes_merge_left()
    @@ Metadata
     Author: Denton Liu <liu.denton@gmail.com>
     
      ## Commit message ##
    -    t3310: extract common no_notes_merge_left()
    +    t3310: extract common notes_merge_files_gone()
     
    -    We had many statements which were duplicated. Extract and replace these
    -    duplicate statements with no_notes_merge_left().
    +    We have many statements which are duplicated. Extract and replace these
    +    duplicate statements with notes_merge_files_gone().
     
         While we're at it, replace the test_might_fail(), which should only be
    -    used on git commands, with a compound command that always returns 0,
    -    even if the underlying ls fails.
    +    used on git commands.
     
         Also, remove the redirection from stderr to /dev/null. This is because
         the test scripts automatically suppress output already. Otherwise, if a
    @@ t/t3310-notes-merge-manual-resolve.sh: verify_notes () {
      	test_cmp "expect_log_$notes_ref" "output_log_$notes_ref"
      }
      
    -+no_notes_merge_left () {
    ++notes_merge_files_gone () {
    ++	# No .git/NOTES_MERGE_* files left
     +	{ ls .git/NOTES_MERGE_* >output || :; } &&
     +	test_must_be_empty output
     +}
    @@ t/t3310-notes-merge-manual-resolve.sh: EOF
     -	# No .git/NOTES_MERGE_* files left
     -	test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
     -	test_must_be_empty output &&
    -+	no_notes_merge_left &&
    ++	notes_merge_files_gone &&
      	# Merge commit has pre-merge y and pre-merge z as parents
      	test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
      	test "$(git rev-parse refs/notes/m^2)" = "$(cat pre_merge_z)" &&
    @@ t/t3310-notes-merge-manual-resolve.sh: test_expect_success 'redo merge of z into
     -	# No .git/NOTES_MERGE_* files left
     -	test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
     -	test_must_be_empty output &&
    -+	no_notes_merge_left &&
    ++	notes_merge_files_gone &&
      	# m has not moved (still == y)
      	test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)" &&
      	# Verify that other notes refs has not changed (w, x, y and z)
    @@ t/t3310-notes-merge-manual-resolve.sh: EOF
     -	# No .git/NOTES_MERGE_* files left
     -	test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
     -	test_must_be_empty output &&
    -+	no_notes_merge_left &&
    ++	notes_merge_files_gone &&
      	# Merge commit has pre-merge y and pre-merge z as parents
      	test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
      	test "$(git rev-parse refs/notes/m^2)" = "$(cat pre_merge_z)" &&
    @@ t/t3310-notes-merge-manual-resolve.sh: EOF
     -	# No .git/NOTES_MERGE_* files left
     -	test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
     -	test_must_be_empty output &&
    -+	no_notes_merge_left &&
    ++	notes_merge_files_gone &&
      	# m has not moved (still == w)
      	test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)" &&
      	# Verify that other notes refs has not changed (w, x, y and z)
 9:  b6d8f6a6e1 ! 10:  32d2051b31 t3415: stop losing return codes of git commands
    @@ Metadata
      ## Commit message ##
         t3415: stop losing return codes of git commands
     
    -    When a command is in a non-assignment subshell, the return code will be
    -    lost in favour of the surrounding command's. Rewrite instances of this
    -    such that the return code of git commands is no longer lost.
    +    Fix invocations of git commands so their exit codes are not lost
    +    within non-assignment command substitutions.
     
      ## t/t3415-rebase-autosquash.sh ##
     @@ t/t3415-rebase-autosquash.sh: test_auto_fixup () {
10:  e2818d1761 ! 11:  8b716c6a81 t3415: increase granularity of test_auto_{fixup,squash}()
    @@ Metadata
      ## Commit message ##
         t3415: increase granularity of test_auto_{fixup,squash}()
     
    -    We used to use `test_must_fail test_auto_{fixup,squash}` which would
    +    We are using `test_must_fail test_auto_{fixup,squash}` which would
         ensure that the function failed. However, this is a little ham-fisted as
         there is no way of ensuring that the expected part of the function
         actually fails.
11:  0357bb8533 ! 12:  ea36028d53 t3419: stop losing return code of git command
    @@ Metadata
      ## Commit message ##
         t3419: stop losing return code of git command
     
    -    We had an instance of a git command in a non-assignment command
    -    substitution. Its return code was lost so we would not be able to detect
    -    if the command failed for some reason. Since we were testing to make
    -    sure the output of the command was empty, rewrite it in a more canonical
    -    way.
    +    Fix invocation of git command so its exit codes is not lost within
    +    a non-assignment command substitution.
     
      ## t/t3419-rebase-patch-id.sh ##
     @@ t/t3419-rebase-patch-id.sh: do_tests () {
12:  35e32f21e1 <  -:  ---------- t3504: don't use `test_must_fail test_cmp`
 -:  ---------- > 13:  88134bb6d1 t3504: do check for conflict marker after failed cherry-pick
13:  1c38a5b3f7 ! 14:  96310b7d28 t3507: fix indentation
    @@ Metadata
      ## Commit message ##
         t3507: fix indentation
     
    -    We had some test cases which were indented 7-spaces instead of a tab.
    -    Fix this by reindenting with a tab instead.
    +    We have some test cases which are indented 7-spaces instead of a tab.
    +    Reindent with a tab instead.
     
         This patch should appear empty with `--ignore-all-space`.
     
14:  7fa886809e = 15:  69125b8e2f t3507: use test_path_is_missing()
15:  e214e1a667 ! 16:  b93ebc0e42 t4124: only mark git command with test_must_fail
    @@ t/t4124-apply-ws-rule.sh: prepare_test_file () {
      }
      
      apply_patch () {
    -+	should_fail= &&
    ++	cmd_prefix= &&
     +	if test "x$1" = 'x!'
     +	then
    -+		should_fail=test_must_fail &&
    ++		cmd_prefix=test_must_fail &&
     +		shift
     +	fi &&
      	>target &&
      	sed -e "s|\([ab]\)/file|\1/target|" <patch |
     -	git apply "$@"
    -+	$should_fail git apply "$@"
    ++	$cmd_prefix git apply "$@"
      }
      
      test_fix () {
16:  31aa0c7d15 <  -:  ---------- t4124: let sed open its own files

Comments

Eric Sunshine Jan. 10, 2020, 9:45 p.m. UTC | #1
On Mon, Jan 6, 2020 at 11:53 PM Denton Liu <liu.denton@gmail.com> wrote:
> Changes since v1:
> * Clean up as suggested by Eric
> * Replace 12/16 with J6t's patch

In the future, please also provide a link in the mailing list archive
to the previous round (v1 [1], in this case) to help reviewers
understand what these bullet points mean since the points themselves
are quite lacking in detail. Pointing people at the previous round
helps not only those who reviewed that round -- who may have already
forgotten the details of their own and others' review comments -- but
will also help onboard people who start reviewing at this round.

> Range-diff against v1:
>  -:  ---------- >  3:  501eb147c3 t2018: improve style of if-statement
> 16:  31aa0c7d15 <  -:  ---------- t4124: let sed open its own files

Dropping patches when re-rolling is fine, but please do not sneak in
new patches unrelated to any of the original changes in this series.
Not only is it likely that such a patch will get overlooked by
reviewers, but even when it is noticed, reviewers have to spend extra
time and effort trying to understand why the patch was added in the
first place (especially since there is not even a mention of it in the
cover letter). After digging into it, I can see that this newly-added
patch (3/16) is an additional sensible style cleanup to the same test
script that many of the other patches are touching, so in some sense
one could argue that it's very vaguely related to v1, but please keep
in mind the potentially negative effect it can have on reviewers[2]
when new changes are added to a series, causing the series to diverge
rather than converge.

[1]: https://lore.kernel.org/git/cover.1577454401.git.liu.denton@gmail.com/
[2]: https://lore.kernel.org/git/CAPig+cQqK-HiDjmnBFo-qeE6cZ73EveWg6Ygb-4BX3X_iPSJZA@mail.gmail.com/