diff mbox series

[1/1] t1403: prefer test_path_exists helper function

Message ID 20250301105838.1481-2-danimahendra0904@gmail.com (mailing list archive)
State New
Headers show
Series t1403: prefer test_path_exists helper function | expand

Commit Message

Mahendra Dani March 1, 2025, 10:58 a.m. UTC
test -e does not provide a nice error message when
we hit test failures, so use test_path_exists instead.

Signed-off-by: Mahendra Dani <danimahendra0904@gmail.com>
---
 t/t1403-show-ref.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Patrick Steinhardt March 3, 2025, 10:26 a.m. UTC | #1
On Sat, Mar 01, 2025 at 04:28:38PM +0530, Mahendra Dani wrote:
> test -e does not provide a nice error message when
> we hit test failures, so use test_path_exists instead.
> 
> Signed-off-by: Mahendra Dani <danimahendra0904@gmail.com>
> ---
>  t/t1403-show-ref.sh | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
> index 9d698b3cc3..12f7b60024 100755
> --- a/t/t1403-show-ref.sh
> +++ b/t/t1403-show-ref.sh
> @@ -196,7 +196,7 @@ test_expect_success 'show-ref --verify with dangling ref' '
>  
>  	remove_object() {
>  		file=$(sha1_file "$*") &&
> -		test -e "$file" &&
> +		test_path_exists "$file" &&
>  		rm -f "$file"
>  	} &&

The refactoring is true to the original spirit of the preimage indeed.
But we could also improve it even further if we verified that the path
not only exists, but exists and is a file via `test_path_is_file()`. If
we decide to do that we should also explain the change in the commit
message.

Thanks!

Patrick
Mahendra Dani March 4, 2025, 2:27 a.m. UTC | #2
On Mon, Mar 3, 2025 at 3:56 PM Patrick Steinhardt <ps@pks.im> wrote:
>
> On Sat, Mar 01, 2025 at 04:28:38PM +0530, Mahendra Dani wrote:
> > test -e does not provide a nice error message when
> > we hit test failures, so use test_path_exists instead.
> >
> > Signed-off-by: Mahendra Dani <danimahendra0904@gmail.com>
> > ---
> >  t/t1403-show-ref.sh | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
> > index 9d698b3cc3..12f7b60024 100755
> > --- a/t/t1403-show-ref.sh
> > +++ b/t/t1403-show-ref.sh
> > @@ -196,7 +196,7 @@ test_expect_success 'show-ref --verify with dangling ref' '
> >
> >       remove_object() {
> >               file=$(sha1_file "$*") &&
> > -             test -e "$file" &&
> > +             test_path_exists "$file" &&
> >               rm -f "$file"
> >       } &&
>
> The refactoring is true to the original spirit of the preimage indeed.
> But we could also improve it even further if we verified that the path
> not only exists, but exists and is a file via `test_path_is_file()`. If
> we decide to do that we should also explain the change in the commit
> message.
>
> Thanks!
>
> Patrick

Yes, sure.
I will improve it further using the `test_path_is_file()` helper
function and change the commit message in v2 patch.

Thanks,
Mahendra.
Junio C Hamano March 4, 2025, 12:05 p.m. UTC | #3
Mahendra Dani <danimahendra0904@gmail.com> writes:

>> >       remove_object() {
>> >               file=$(sha1_file "$*") &&
>> > -             test -e "$file" &&
>> > +             test_path_exists "$file" &&
>> >               rm -f "$file"
>> >       } &&
>>
>> The refactoring is true to the original spirit of the preimage indeed.
>> But we could also improve it even further if we verified that the path
>> not only exists, but exists and is a file via `test_path_is_file()`. If
>> we decide to do that we should also explain the change in the commit
>> message.
>
> Yes, sure.
> I will improve it further using the `test_path_is_file()` helper
> function and change the commit message in v2 patch.

You may want to think about why there is "-f" there.  If we remove
it, do we still need to have any check there?
Mahendra Dani March 4, 2025, 5:24 p.m. UTC | #4
On Tue, Mar 4, 2025 at 5:35 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Mahendra Dani <danimahendra0904@gmail.com> writes:
>
> >> >       remove_object() {
> >> >               file=$(sha1_file "$*") &&
> >> > -             test -e "$file" &&
> >> > +             test_path_exists "$file" &&
> >> >               rm -f "$file"
> >> >       } &&
> >>
> >> The refactoring is true to the original spirit of the preimage indeed.
> >> But we could also improve it even further if we verified that the path
> >> not only exists, but exists and is a file via `test_path_is_file()`. If
> >> we decide to do that we should also explain the change in the commit
> >> message.
> >
> > Yes, sure.
> > I will improve it further using the `test_path_is_file()` helper
> > function and change the commit message in v2 patch.
>
> You may want to think about why there is "-f" there.  If we remove
> it, do we still need to have any check there?

Here, the "-f" flag in `rm -f "$file"` does not produce an error message even
if the file does not exist [1], thus the `test -e "$file"` check was redundant,
as pointed out by Patrick in [2].

However, switching to `test_path_is_file()` would provide additional safety by
ensuring that we only attempt to remove a regular file and not a directory.

[References]
1. https://man7.org/linux/man-pages/man1/rm.1.html
2. https://lore.kernel.org/git/Z8bd3iHrhXb4WH6A@pks.im/
Junio C Hamano March 4, 2025, 5:26 p.m. UTC | #5
Mahendra Dani <danimahendra0904@gmail.com> writes:

> On Tue, Mar 4, 2025 at 5:35 PM Junio C Hamano <gitster@pobox.com> wrote:
>>
>> Mahendra Dani <danimahendra0904@gmail.com> writes:
>>
>> >> >       remove_object() {
>> >> >               file=$(sha1_file "$*") &&
>> >> > -             test -e "$file" &&
>> >> > +             test_path_exists "$file" &&
>> >> >               rm -f "$file"
>> >> >       } &&
>>
>> You may want to think about why there is "-f" there.  If we remove
>> it, do we still need to have any check there?
>
> Here, the "-f" flag in `rm -f "$file"` does not produce an error message even
> if the file does not exist [1], thus the `test -e "$file"` check was redundant,
> as pointed out by Patrick in [2].

So what happens if you dropped "-f" as I hinted?  We'll notice the
lack of file and the command exits with non-zero status.  So "test -e"
was not necessary in the first place, was it?
Mahendra Dani March 4, 2025, 5:35 p.m. UTC | #6
On Tue, Mar 4, 2025 at 10:57 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Mahendra Dani <danimahendra0904@gmail.com> writes:
>
> > On Tue, Mar 4, 2025 at 5:35 PM Junio C Hamano <gitster@pobox.com> wrote:
> >>
> >> Mahendra Dani <danimahendra0904@gmail.com> writes:
> >>
> >> >> >       remove_object() {
> >> >> >               file=$(sha1_file "$*") &&
> >> >> > -             test -e "$file" &&
> >> >> > +             test_path_exists "$file" &&
> >> >> >               rm -f "$file"
> >> >> >       } &&
> >>
> >> You may want to think about why there is "-f" there.  If we remove
> >> it, do we still need to have any check there?
> >
> > Here, the "-f" flag in `rm -f "$file"` does not produce an error message even
> > if the file does not exist [1], thus the `test -e "$file"` check was redundant,
> > as pointed out by Patrick in [2].
>
> So what happens if you dropped "-f" as I hinted?  We'll notice the
> lack of file and the command exits with non-zero status.  So "test -e"
> was not necessary in the first place, was it?
>

Yes, due to the use of the "-f" flag, it's not necessary to explicitly
check the lack of file using `test -e`.
But if we drop the "-f" flag, we will have to check the lack of file
using `test -e` or
`test_path_is_file()`.

Thanks,
Mahendra
Eric Sunshine March 4, 2025, 5:35 p.m. UTC | #7
On Tue, Mar 4, 2025 at 7:05 AM Junio C Hamano <gitster@pobox.com> wrote:
> Mahendra Dani <danimahendra0904@gmail.com> writes:
> >> >       remove_object() {
> >> >               file=$(sha1_file "$*") &&
> >> > -             test -e "$file" &&
> >> > +             test_path_exists "$file" &&
> >> >               rm -f "$file"
> >> >       } &&
> >>
> >> The refactoring is true to the original spirit of the preimage indeed.
> >> But we could also improve it even further if we verified that the path
> >> not only exists, but exists and is a file via `test_path_is_file()`. If
> >> we decide to do that we should also explain the change in the commit
> >> message.
> >
> > I will improve it further using the `test_path_is_file()` helper
> > function and change the commit message in v2 patch.
>
> You may want to think about why there is "-f" there.  If we remove
> it, do we still need to have any check there?

That's a good question to ask, but isn't the implied suggestion of
dropping "-f" going in the wrong direction? If I'm reading
remove_object() correctly, `test -e` is being used as control flow,
*not* as an assertion that the file exists. That is, the expectation
of the caller is that the file will not exist once the call completes
and that remove_object() will return a success code whether the file
was present before the call or not. By control flow, I mean that the
function, as written, is the same as this more explicit version:

    remove_object() {
        file=$(sha1_file "$*") &&
        if test -e "$file"
        then
            rm -f "$file"
        fi
    } &&

Given this understanding, then it becomes apparent that this GSoC
microproject shouldn't be applying *any* test_path_foo() to this
function. As an alternative, given that `rm -f` returns a success code
whether or not the file exists, the microproject could instead
*remove* the `test -e "$file" &&` line entirely (and the commit
message should explain why doing so is a reasonable thing to do).
Junio C Hamano March 4, 2025, 5:44 p.m. UTC | #8
Mahendra Dani <danimahendra0904@gmail.com> writes:

> Yes, due to the use of the "-f" flag, it's not necessary to explicitly
> check the lack of file using `test -e`.
> But if we drop the "-f" flag, we will have to check the lack of file
> using `test -e` or
> `test_path_is_file()`.

Isn't it the other way around?

    $ rm -f nosuch ; echo $?
    0
    $ rm nosuch ; echo $?
    rm: cannot remove 'nosuch': No such file or directory
    1
Junio C Hamano March 4, 2025, 5:49 p.m. UTC | #9
Eric Sunshine <sunshine@sunshineco.com> writes:

> On Tue, Mar 4, 2025 at 7:05 AM Junio C Hamano <gitster@pobox.com> wrote:
>> Mahendra Dani <danimahendra0904@gmail.com> writes:
>> >> >       remove_object() {
>> >> >               file=$(sha1_file "$*") &&
>> >> > -             test -e "$file" &&
>> >> > +             test_path_exists "$file" &&
>> >> >               rm -f "$file"
>> >> >       } &&
> That's a good question to ask, but isn't the implied suggestion of
> dropping "-f" going in the wrong direction? If I'm reading
> remove_object() correctly, `test -e` is being used as control flow,
> *not* as an assertion that the file exists.

If sha1_file says the loose object must be at path $file, and the
call to test -e "$file" returns false, two things happen in this
function:

 (1) control stops and "rm -f" does not trigger
 (2) the function returns non-zero status to the caller

If you omit the check and say rm "$file" instead, under the same
scenario, (1) "rm" is attempted, but there is nothing to remove so
the command returns non-zero status, and (2) the function returns
that non-zero status to the caller

If the file does exist, both will remove the file, and give the
caller zero status return.

So?
Mahendra Dani March 4, 2025, 5:49 p.m. UTC | #10
On Tue, Mar 4, 2025 at 11:14 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Mahendra Dani <danimahendra0904@gmail.com> writes:
>
> > Yes, due to the use of the "-f" flag, it's not necessary to explicitly
> > check the lack of file using `test -e`.
> > But if we drop the "-f" flag, we will have to check the lack of file
> > using `test -e` or
> > `test_path_is_file()`.
>
> Isn't it the other way around?
>
>     $ rm -f nosuch ; echo $?
>     0
>     $ rm nosuch ; echo $?
>     rm: cannot remove 'nosuch': No such file or directory
>     1
>

Yes, you are right.
With the "-f" flag, `rm` returns exit code 0 irrespective of whether
the file is present or not.
Thus, the `test -e` check is _required_ if we drop the "-f" flag to
return the correct exit code.

I apologize for the mistake.

Thanks,
Mahendra
Eric Sunshine March 4, 2025, 6:07 p.m. UTC | #11
On Tue, Mar 4, 2025 at 12:49 PM Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
> > On Tue, Mar 4, 2025 at 7:05 AM Junio C Hamano <gitster@pobox.com> wrote:
> >> Mahendra Dani <danimahendra0904@gmail.com> writes:
> >> >> >       remove_object() {
> >> >> >               file=$(sha1_file "$*") &&
> >> >> > -             test -e "$file" &&
> >> >> > +             test_path_exists "$file" &&
> >> >> >               rm -f "$file"
> >> >> >       } &&
> > That's a good question to ask, but isn't the implied suggestion of
> > dropping "-f" going in the wrong direction? If I'm reading
> > remove_object() correctly, `test -e` is being used as control flow,
> > *not* as an assertion that the file exists.
>
> If sha1_file says the loose object must be at path $file, and the
> call to test -e "$file" returns false, two things happen in this
> function:
>
>  (1) control stops and "rm -f" does not trigger
>  (2) the function returns non-zero status to the caller

True enough. I was misreading `test -e "$file"` as _only_ control flow.

However, it's still not clear to me why this function is making the
`test -e "$file"` assertion in the first place or why the enclosing
test should care, especially since that assertion is only checking
that `git commit` worked correctly, but that's not the intent of this
particular test[1]. So, `test -e "$file"` seems pointless or at least
misleading.

> If you omit the check and say rm "$file" instead, under the same
> scenario, (1) "rm" is attempted, but there is nothing to remove so
> the command returns non-zero status, and (2) the function returns
> that non-zero status to the caller

Yes, I understood the implication of your suggestion, but as mentioned
above, it's not clear (at least to me) why `test -e "$file"` is there
at all since this test is not about checking functionality of `git
commit`.

[1]: d01b8203ec (show-ref: detect dangling refs under --verify as
well, 2017-01-23) doesn't explain why `test -e "$file"` was used.
Junio C Hamano March 4, 2025, 6:07 p.m. UTC | #12
Mahendra Dani <danimahendra0904@gmail.com> writes:

> On Tue, Mar 4, 2025 at 11:14 PM Junio C Hamano <gitster@pobox.com> wrote:
>>
>> Mahendra Dani <danimahendra0904@gmail.com> writes:
>>
>> > Yes, due to the use of the "-f" flag, it's not necessary to explicitly
>> > check the lack of file using `test -e`.
>> > But if we drop the "-f" flag, we will have to check the lack of file
>> > using `test -e` or
>> > `test_path_is_file()`.
>>
>> Isn't it the other way around?
>>
>>     $ rm -f nosuch ; echo $?
>>     0
>>     $ rm nosuch ; echo $?
>>     rm: cannot remove 'nosuch': No such file or directory
>>     1
>>
>
> Yes, you are right.
> With the "-f" flag, `rm` returns exit code 0 irrespective of whether
> the file is present or not.
> Thus, the `test -e` check is _required_ if we drop the "-f" flag to
> return the correct exit code.
>
> I apologize for the mistake.

No need for an apology when correcting technical mistakes, which we
all make.
Eric Sunshine March 4, 2025, 6:28 p.m. UTC | #13
On Tue, Mar 4, 2025 at 1:07 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
> > >> >> >       remove_object() {
> > >> >> >               file=$(sha1_file "$*") &&
> > >> >> > -             test -e "$file" &&
> > >> >> > +             test_path_exists "$file" &&
> > >> >> >               rm -f "$file"
> > >> >> >       } &&
>
> However, it's still not clear to me why this function is making the
> `test -e "$file"` assertion in the first place or why the enclosing
> test should care, especially since that assertion is only checking
> that `git commit` worked correctly, but that's not the intent of this
> particular test[1]. So, `test -e "$file"` seems pointless or at least
> misleading.

Perhaps, I'm falling into the trap of assuming that a lone `git
commit` in a new repository will unconditionally create a loose
object, and that that will always be the case? If, down the road, `git
commit` no longer works that way, then the assumption about the loose
object becomes invalid, in which case I can see how the `test -e
"$file"` assertion is protecting the test against that future.
Junio C Hamano March 4, 2025, 6:30 p.m. UTC | #14
Eric Sunshine <sunshine@sunshineco.com> writes:

> On Tue, Mar 4, 2025 at 12:49 PM Junio C Hamano <gitster@pobox.com> wrote:
>> Eric Sunshine <sunshine@sunshineco.com> writes:
>> > On Tue, Mar 4, 2025 at 7:05 AM Junio C Hamano <gitster@pobox.com> wrote:
>> >> Mahendra Dani <danimahendra0904@gmail.com> writes:
>> >> >> >       remove_object() {
>> >> >> >               file=$(sha1_file "$*") &&
>> >> >> > -             test -e "$file" &&
>> >> >> > +             test_path_exists "$file" &&
>> >> >> >               rm -f "$file"
>> >> >> >       } &&
> ...
> Yes, I understood the implication of your suggestion, but as mentioned
> above, it's not clear (at least to me) why `test -e "$file"` is there
> at all since this test is not about checking functionality of `git
> commit`.

Yup, I do not see much point in "test -e" there in the original, and
it does not change even if it were "test -f".

I would understand if the author wanted to have a "slightly more
intelligent 'rm -f' that knows where a loose object is located, and
removes the named object no matter what", but if the objective were
to ensure the object is missing, I wouldn't have written it to
return non-zero when the object were missing in the first place.

And if the purpose of the function is to catch unexpected cases,
such as "the loose object file should be there but isn't" and "we
located the file but we failed to remove it", then it shouldn't have
the 'test -e' guard and 'rm' shouldn't have been used with '-f'.

So, I agree with you that the original is already iffy.

Thanks.
diff mbox series

Patch

diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
index 9d698b3cc3..12f7b60024 100755
--- a/t/t1403-show-ref.sh
+++ b/t/t1403-show-ref.sh
@@ -196,7 +196,7 @@  test_expect_success 'show-ref --verify with dangling ref' '
 
 	remove_object() {
 		file=$(sha1_file "$*") &&
-		test -e "$file" &&
+		test_path_exists "$file" &&
 		rm -f "$file"
 	} &&