threads / rfc / 36279

RFC patchBetter control of the tests run by a test suite

Subject: [RFC/PATCH] Better control of the tests run by a test suite

## tl;dr

23 messages between Mar 24, 2014 and Mar 31, 2014. Diffs are folded; open one to read it.

replies: 22people: 6as markdown or json

Ilya Bobyr· Mar 24, 2014, 08:49 UTC · lore
Hello,
This is a second attempt on a functionality I proposed in
    [PATCH 2/2] test-lib: GIT_TEST_ONLY to run only specific tests
    http://www.mail-archive.com/git%40vger.kernel.org/msg44828.html
except that the implementation is quite different now.

I hope that I have accounted for the comments that were voiced so far. Let's see :)

The idea behind the change is that sometimes it is convenient to run only certain tests from a test suite. Specifically I am thinking about the following two use cases:

 1. You are developing new functionality.  You add a test that
    fails and then you add and modify code to make it pass.
    
 2. You have a failed test and you need to understand what is
    wrong.
    
In the first case you when you run the test suite, you probably
want to run some setup tests and then only one test that you are
focused on.

For code written in C time between you make a change and see a test result is considerably increased by the compilation. But for script code turn around time is mostly due to the run time of the test suite itself. [1]

For the second case you actually want the test suite to stop after the failing test, so that you can examine the trash directory without any modifications from the subsequent tests. You probably do not care about them.

In the previous patch I've added an environment variable to control tests to be run in a test suite. I thought that it would be similar to an already existing GIT_SKIP_TESTS. As I did not provide a cover letter that caused some misunderstanding I think.

This patch adds new command line argument '--run' that accepts a list of patterns and restrictions on the test numbers that would be included or excluded from this run of the test suite.

During discussion of the previous patch there were some talks about extending GIT_SKIP_TESTS syntax. In particular here:

Show 21 quoted lines
> That is
> 
>         GIT_SKIP_TESTS='t9??? !t91??'
> 
> would skip nine-thousand series, but would run 91xx series, and all
> the others are not excluded.
> 
> Simple rules to consider:
> 
>  - If the list consists of _only_ negated patterns, pretend that
>    there is "unless otherwise specified with negatives, skip all
>    tests", i.e. treat GIT_SKIP_TESTS='!t91??' just the same way you
>    would treat GIT_SKIP_TESTS='* !t91??'.
> 
>  - The orders should not matter for simplicity of the semantics;
>    before running each test, check if it matches any negative (and
>    run it if it matches, without looking at any positives), and
>    otherwise check if it matches any positive (and skip it if it
>    does not).
> 
> Hmm?
    http://www.mail-archive.com/git%40vger.kernel.org/msg44922.html

I've used that as a basis, but the end result is somewhat different. Plus I've added boundary checks as in "<123".

Here are some examples of how functionality added by the patch could be used. In order to run setup tests and then only a specific test (use case 1) one can do:

    $ ./t0000-init.sh --run='1 2 25'
or:
    $ ./t0000-init.sh --run='<3 25'
('<=' is also supported, as well as '>' and '>=').
In order to run up to a specific test (use case 2) one can do:
    $ ./t0000-init.sh --run='<=34'
or:
    $ ./t0000-init.sh --run='!>34'

Simple semantics described above is easy to implement, but at the same time is probably not that convenient. Rules implemented by the patch are as follows:

 - Order does matter.  Whatever is specified on the right has
   higher precedence.
 - When the first pattern is positive the initial set of the
   tests to be run is empty.  You are adding to an empty set as
   in '1 2 25'.
   When the first pattern is negative the initial set of the
   tests to run contains all the tests.  You are subtracting
   from that set as in '!>34'.

It seems that for simple cases that gives simple syntax and is almost unbiased if you think about preferring inclusion over exclusion. While it is unlikely it also allows for complicated expressions. And the implementation is quite simple as well.

Main functionality is in the third patch. First two are just minor fixes in related parts of the code.

P.S. I did not reply to the previous patch thread as this one is quite different.

[1] Here are some times I see on Cygin:
    $ touch builtin/rev-parse.c
    
    $ time make
    ...
    
    real    0m10.382s
    user    0m3.829s
    sys     0m5.269s
Running the t0000-init.sh test suite is like this:
    $ time ./t0001-init.sh
    [...]
    1..36
    real    0m6.693s
    user    0m1.505s
    sys     0m3.937s

If I run only the 1, 2, 4 and 5th tests, it only half the time to run the tests:

    $ time GIT_SKIP_TESTS='t0001.[36789] t0001.??' ./t0001-init.sh
    [...]
    1..36
    real    0m3.313s
    user    0m0.769s
    sys     0m1.844s 
Overall the change is from 17 to 14 seconds it is not that big.

If you only consider the test suite, as you do while you develop an sh based tool, for example, the change is from 6.6 to 3.3 seconds. That is quite noticeable.

 t/README         |   75 ++++++++++++--
 t/t0000-basic.sh |  296 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/test-lib.sh    |   96 +++++++++++++++++-
 3 files changed, 454 insertions(+), 13 deletions(-)
Ilya Bobyr· Mar 24, 2014, 08:49 UTC · re: Ilya Bobyr · lore

[PATCH 1/3] test-lib: Document short options in t/README

Most arguments that could be provided to a test have short forms. Unless documented the only way to learn then is to read the code.

Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
---
 t/README |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)
Show changes to t/README +5 −0
diff --git a/t/README b/t/README
index caeeb9d..ccb5989 100644
--- a/t/README
+++ b/t/README
@@ -71,7 +71,7 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
 (or -i) command line argument to the test, or by setting GIT_TEST_OPTS
 appropriately before running "make".
 
---verbose::
+-v,--verbose::
 	This makes the test more verbose.  Specifically, the
 	command being run and their output if any are also
 	output.
@@ -81,7 +81,7 @@ appropriately before running "make".
 	numbers matching <pattern>.  The number matched against is
 	simply the running count of the test within the file.
 
---debug::
+-d,--debug::
 	This may help the person who is developing a new test.
 	It causes the command defined with test_debug to run.
 	The "trash" directory (used to store all temporary data
@@ -89,18 +89,18 @@ appropriately before running "make".
 	failed tests so that you can inspect its contents after
 	the test finished.
 
---immediate::
+-i,--immediate::
 	This causes the test to immediately exit upon the first
 	failed test. Cleanup commands requested with
 	test_when_finished are not executed if the test failed,
 	in order to keep the state for inspection by the tester
 	to diagnose the bug.
 
---long-tests::
+-l,--long-tests::
 	This causes additional long-running tests to be run (where
 	available), for more exhaustive testing.
 
---valgrind=<tool>::
+-v,--valgrind=<tool>::
 	Execute all Git binaries under valgrind tool <tool> and exit
 	with status 126 on errors (just like regular tests, this will
 	only stop the test script when running under -i).
-- 
1.7.9
Ramsay Jones· Mar 24, 2014, 11:39 UTC · re: Ilya Bobyr · lore

Re: [PATCH 1/3] test-lib: Document short options in t/README

On 24/03/14 08:49, Ilya Bobyr wrote:
Show 18 quoted lines
> Most arguments that could be provided to a test have short forms.
> Unless documented the only way to learn then is to read the code.
> 
> Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
> ---
>  t/README |   10 +++++-----
>  1 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/t/README b/t/README
> index caeeb9d..ccb5989 100644
> --- a/t/README
> +++ b/t/README
> @@ -71,7 +71,7 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
>  (or -i) command line argument to the test, or by setting GIT_TEST_OPTS
>  appropriately before running "make".
>  
> ---verbose::
> +-v,--verbose::
OK
Show 31 quoted lines
>  	This makes the test more verbose.  Specifically, the
>  	command being run and their output if any are also
>  	output.
> @@ -81,7 +81,7 @@ appropriately before running "make".
>  	numbers matching <pattern>.  The number matched against is
>  	simply the running count of the test within the file.
>  
> ---debug::
> +-d,--debug::
>  	This may help the person who is developing a new test.
>  	It causes the command defined with test_debug to run.
>  	The "trash" directory (used to store all temporary data
> @@ -89,18 +89,18 @@ appropriately before running "make".
>  	failed tests so that you can inspect its contents after
>  	the test finished.
>  
> ---immediate::
> +-i,--immediate::
>  	This causes the test to immediately exit upon the first
>  	failed test. Cleanup commands requested with
>  	test_when_finished are not executed if the test failed,
>  	in order to keep the state for inspection by the tester
>  	to diagnose the bug.
>  
> ---long-tests::
> +-l,--long-tests::
>  	This causes additional long-running tests to be run (where
>  	available), for more exhaustive testing.
>  
> ---valgrind=<tool>::
> +-v,--valgrind=<tool>::
The -v short option is taken, above ... :-P
>  	Execute all Git binaries under valgrind tool <tool> and exit
>  	with status 126 on errors (just like regular tests, this will
>  	only stop the test script when running under -i).
> 

ATB, Ramsay Jones

Ilya Bobyr· Mar 24, 2014, 17:19 UTC · re: Ramsay Jones · lore

Re: [PATCH 1/3] test-lib: Document short options in t/README

On 3/24/2014 4:39 AM, Ramsay Jones wrote:
Show 26 quoted lines
> On 24/03/14 08:49, Ilya Bobyr wrote:
>> Most arguments that could be provided to a test have short forms.
>> Unless documented the only way to learn then is to read the code.
>>
>> Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
>> ---
>>  t/README |   10 +++++-----
>>  1 files changed, 5 insertions(+), 5 deletions(-)
>>
>> diff --git a/t/README b/t/README
>> index caeeb9d..ccb5989 100644
>> --- a/t/README
>> +++ b/t/README
>> @@ -71,7 +71,7 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
>>  (or -i) command line argument to the test, or by setting GIT_TEST_OPTS
>>  appropriately before running "make".
>>  
>> ---verbose::
>> +-v,--verbose::
> OK
>
>> [...]
>>  
>> ---valgrind=<tool>::
>> +-v,--valgrind=<tool>::
> The -v short option is taken, above ... :-P

Right %) Thanks :) This one starts only with "--va", will fix it.

Junio C Hamano· Mar 25, 2014, 17:23 UTC · re: Ilya Bobyr · lore

Re: [PATCH 1/3] test-lib: Document short options in t/README

Ilya Bobyr <ilya.bobyr@gmail.com> writes:
Show 31 quoted lines
> On 3/24/2014 4:39 AM, Ramsay Jones wrote:
>> On 24/03/14 08:49, Ilya Bobyr wrote:
>>> Most arguments that could be provided to a test have short forms.
>>> Unless documented the only way to learn then is to read the code.
>>>
>>> Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
>>> ---
>>>  t/README |   10 +++++-----
>>>  1 files changed, 5 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/t/README b/t/README
>>> index caeeb9d..ccb5989 100644
>>> --- a/t/README
>>> +++ b/t/README
>>> @@ -71,7 +71,7 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
>>>  (or -i) command line argument to the test, or by setting GIT_TEST_OPTS
>>>  appropriately before running "make".
>>>  
>>> ---verbose::
>>> +-v,--verbose::
>> OK
>>
>>> [...]
>>>  
>>> ---valgrind=<tool>::
>>> +-v,--valgrind=<tool>::
>> The -v short option is taken, above ... :-P
>
> Right %)
> Thanks :)
> This one starts only with "--va", will fix it.
Please don't.

In general, when option names can be shortened by taking a unique prefix, it is better not to give short form in the documentation at all. There is no guarantee that the short form you happen to pick when you document it will continue to be unique forever. When we add another --vasomething option, --va will become ambiguous and one of these two things must happen:

 (1) --valgrind and --vasomething are equally useful and often used.
     Neither will get --va and either --val or --vas needs to be
     given.
 (2) Because we documented --va as --valgrind, people feel that they
     are entitled to expect --va will stay forever to be a shorthand
     for --valgrind and nothing else.  The shortened forms will be
     between --va (or longer prefix of --valgrind) and --vas (or
     longer prefix of --vasomething).

We would rather want to see (1), as people new to the system do not have to learn that --valgrind can be spelled --va merely by being the first to appear, and --vasomething must be spelled --vas because it happened to come later. Longer term, nobody should care how the system evolved into the current shape, but (2) will require that to understand and remember why one is --va and the other has to be --vas.

We already have this suboptimal (2) situation between "--valgrind" and "--verbose" options, but a shorter form "v" that is used for "verbose" is so widely understood and used that I think it is an acceptable exception. So

         --verbose::
        +-v::
                Give verbose output from the test
is OK, but "--valgrind can be shortened to --va" is not.
Ilya Bobyr· Mar 27, 2014, 09:39 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/3] test-lib: Document short options in t/README

On 3/25/2014 10:23 AM, Junio C Hamano wrote:
Show 49 quoted lines
> Ilya Bobyr <ilya.bobyr@gmail.com> writes:
>
>> On 3/24/2014 4:39 AM, Ramsay Jones wrote:
>>> On 24/03/14 08:49, Ilya Bobyr wrote:
>>> [...]
>>>> [...]
>>>>  
>>>> ---valgrind=<tool>::
>>>> +-v,--valgrind=<tool>::
>>> The -v short option is taken, above ... :-P
>> Right %)
>> Thanks :)
>> This one starts only with "--va", will fix it.
> Please don't.
>
> In general, when option names can be shortened by taking a unique
> prefix, it is better not to give short form in the documentation at
> all.  There is no guarantee that the short form you happen to pick
> when you document it will continue to be unique forever.  When we
> add another --vasomething option, --va will become ambiguous and one
> of these two things must happen:
>
>  (1) --valgrind and --vasomething are equally useful and often used.
>      Neither will get --va and either --val or --vas needs to be
>      given.
>
>  (2) Because we documented --va as --valgrind, people feel that they
>      are entitled to expect --va will stay forever to be a shorthand
>      for --valgrind and nothing else.  The shortened forms will be
>      between --va (or longer prefix of --valgrind) and --vas (or
>      longer prefix of --vasomething).
>
> We would rather want to see (1), as people new to the system do not
> have to learn that --valgrind can be spelled --va merely by being
> the first to appear, and --vasomething must be spelled --vas because
> it happened to come later.  Longer term, nobody should care how the
> system evolved into the current shape, but (2) will require that to
> understand and remember why one is --va and the other has to be --vas.
>
> We already have this suboptimal (2) situation between "--valgrind"
> and "--verbose" options, but a shorter form "v" that is used for
> "verbose" is so widely understood and used that I think it is an
> acceptable exception.  So
>
>          --verbose::
>         +-v::
>                 Give verbose output from the test
>
> is OK, but "--valgrind can be shortened to --va" is not.

Sure, this is exactly what I meant, but I guess, I was too short so it created ambiguity =) I was going to just remove the '-v' from '--valgrind'.

Shortening is a separate issue. I did not look at it. I can see that it is also not documented. At the same time shortening is entirely consistent at the moment, and does not work for options that take arguments.

My main intent was to document '-r' :) As no other short form were documented, I had to fix that issue first.

If there is decision on how shortening should work for all the options, maybe I could add a paragraph on that and make existing options more consistent.

I guess the questions would be, should it possible to use short forms for options that take arguments?

If so, '--valgrind' becomes impossible to shorten because there is '--valgrind-only' that is a separate option. Same for '--verbose' and '--verbose-only'.

For convenience here is the relevant switch in the way it is right now:

    case "$1" in
    -d|--d|--de|--deb|--debu|--debug)
        debug=t; shift ;;
   
-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
        immediate=t; shift ;;
   
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
        GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
    -r)
        shift; test "$#" -ne 0 || {
            echo 'error: -r requires an argument' >&2;
            exit 1;
        }
        run_list=$1; shift ;;
    --run=*)
        run_list=$(expr "z$1" : 'z[^=]*=\(.*\)'); shift ;;
    -h|--h|--he|--hel|--help)
        help=t; shift ;;
    -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
        verbose=t; shift ;;
    --verbose-only=*)
        verbose_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
        shift ;;
    -q|--q|--qu|--qui|--quie|--quiet)
        # Ignore --quiet under a TAP::Harness. Saying how many tests
        # passed without the ok/not ok details is always an error.
        test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
    --with-dashes)
        with_dashes=t; shift ;;
    --no-color)
        color=; shift ;;
    --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
        valgrind=memcheck
        shift ;;
    --valgrind=*)
        valgrind=$(expr "z$1" : 'z[^=]*=\(.*\)')
        shift ;;
    --valgrind-only=*)
        valgrind_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
        shift ;;
    --tee)
        shift ;; # was handled already
    --root=*)
        root=$(expr "z$1" : 'z[^=]*=\(.*\)')
        shift ;;
    *)
        echo "error: unknown test option '$1'" >&2; exit 1 ;;
    esac

P.S. Sorry it takes me this long to reply. I will try to be more responsive, should there will be a discussion :)

Junio C Hamano· Mar 27, 2014, 16:35 UTC · re: Ilya Bobyr · lore

Re: [PATCH 1/3] test-lib: Document short options in t/README

Ilya Bobyr <ilya.bobyr@gmail.com> writes:
> If there is decision on how shortening should work for all the
> options, maybe I could add a paragraph on that and make existing
> options more consistent.

We should strive to make the following from gitcli.txt apply throughout the system:

 * many commands allow a long option `--option` to be abbreviated
   only to their unique prefix (e.g. if there is no other option
   whose name begins with `opt`, you may be able to spell `--opt` to
   invoke the `--option` flag), but you should fully spell them out
   when writing your scripts; later versions of Git may introduce a
   new option whose name shares the same prefix, e.g. `--optimize`,
   to make a short prefix that used to be unique no longer unique.
> If so, '--valgrind' becomes impossible to shorten because there
> is '--valgrind-only' that is a separate option.  Same for
> '--verbose'  and '--verbose-only'.

Correct. If you really cared, --valgrind={yes,no,only} would be (or have been) a better possibility, though.

Junio C Hamano· Mar 28, 2014, 17:20 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/3] test-lib: Document short options in t/README

Junio C Hamano <gitster@pobox.com> writes:
Show 23 quoted lines
> Ilya Bobyr <ilya.bobyr@gmail.com> writes:
>
>> If there is decision on how shortening should work for all the
>> options, maybe I could add a paragraph on that and make existing
>> options more consistent.
>
> We should strive to make the following from gitcli.txt apply
> throughout the system:
>
>  * many commands allow a long option `--option` to be abbreviated
>    only to their unique prefix (e.g. if there is no other option
>    whose name begins with `opt`, you may be able to spell `--opt` to
>    invoke the `--option` flag), but you should fully spell them out
>    when writing your scripts; later versions of Git may introduce a
>    new option whose name shares the same prefix, e.g. `--optimize`,
>    to make a short prefix that used to be unique no longer unique.
>
>> If so, '--valgrind' becomes impossible to shorten because there
>> is '--valgrind-only' that is a separate option.  Same for
>> '--verbose'  and '--verbose-only'.
>
> Correct.  If you really cared, --valgrind={yes,no,only} would be (or
> have been) a better possibility, though.

Also, these existing bits are simply being lazy. You do not have to emulate and spread the laziness.

 t/test-lib.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Show changes to t/test-lib.sh +2 −2
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 87f327f..f37973a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -209,10 +209,10 @@ do
 	--va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
 		valgrind=memcheck
 		shift ;;
-	--valgrind=*)
+	--va=*|--val=*|--valg=*|--valgr=*|--valgri=*|--valgrin=*|--valgrind=*)
 		valgrind=$(expr "z$1" : 'z[^=]*=\(.*\)')
 		shift ;;
-	--valgrind-only=*)
+  	--valgrind-o=*|--valgrind-on=*|--valgrind-onl=*|--valgrind-only=*)
 		valgrind_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
 		shift ;;
 	--tee)
Eric Sunshine· Mar 25, 2014, 05:52 UTC · re: Ilya Bobyr · lore

Re: [PATCH 1/3] test-lib: Document short options in t/README

On Mon, Mar 24, 2014 at 4:49 AM, Ilya Bobyr <ilya.bobyr@gmail.com> wrote:
> Most arguments that could be provided to a test have short forms.
> Unless documented the only way to learn then is to read the code.
s/then/them/
(Also, add a comma after "documented".)
Show 52 quoted lines
> Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
> ---
>  t/README |   10 +++++-----
>  1 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/t/README b/t/README
> index caeeb9d..ccb5989 100644
> --- a/t/README
> +++ b/t/README
> @@ -71,7 +71,7 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
>  (or -i) command line argument to the test, or by setting GIT_TEST_OPTS
>  appropriately before running "make".
>
> ---verbose::
> +-v,--verbose::
>         This makes the test more verbose.  Specifically, the
>         command being run and their output if any are also
>         output.
> @@ -81,7 +81,7 @@ appropriately before running "make".
>         numbers matching <pattern>.  The number matched against is
>         simply the running count of the test within the file.
>
> ---debug::
> +-d,--debug::
>         This may help the person who is developing a new test.
>         It causes the command defined with test_debug to run.
>         The "trash" directory (used to store all temporary data
> @@ -89,18 +89,18 @@ appropriately before running "make".
>         failed tests so that you can inspect its contents after
>         the test finished.
>
> ---immediate::
> +-i,--immediate::
>         This causes the test to immediately exit upon the first
>         failed test. Cleanup commands requested with
>         test_when_finished are not executed if the test failed,
>         in order to keep the state for inspection by the tester
>         to diagnose the bug.
>
> ---long-tests::
> +-l,--long-tests::
>         This causes additional long-running tests to be run (where
>         available), for more exhaustive testing.
>
> ---valgrind=<tool>::
> +-v,--valgrind=<tool>::
>         Execute all Git binaries under valgrind tool <tool> and exit
>         with status 126 on errors (just like regular tests, this will
>         only stop the test script when running under -i).
> --
> 1.7.9
>
Ilya Bobyr· Mar 24, 2014, 08:49 UTC · re: Ilya Bobyr · lore

[PATCH 2/3] test-lib: tests skipped by GIT_SKIP_TESTS say so

We used to show "(missing )" next to tests skipped because they are specified in GIT_SKIP_TESTS. Use "(GIT_SKIP_TESTS)" instead.

Plus tests that check basic GIT_SKIP_TESTS functions.
Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
---
 t/t0000-basic.sh |   63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/test-lib.sh    |   13 ++++++----
 2 files changed, 71 insertions(+), 5 deletions(-)
Show changes to 2 files +71 −5

t/t0000-basic.sh, t/test-lib.sh

diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index a2bb63c..ae8874e 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -270,6 +270,69 @@ test_expect_success 'test --verbose-only' '
 	EOF
 '
 
+test_expect_success 'GIT_SKIP_TESTS' "
+	GIT_SKIP_TESTS='git.2' \
+		run_sub_test_lib_test git-skip-tests-basic \
+		'GIT_SKIP_TESTS' <<-\\EOF &&
+	for i in 1 2 3
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test git-skip-tests-basic <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
+	> ok 3 - passing test #3
+	> # passed all 3 test(s)
+	> 1..3
+	EOF
+"
+
+test_expect_success 'GIT_SKIP_TESTS several tests' "
+	GIT_SKIP_TESTS='git.2 git.5' \
+		run_sub_test_lib_test git-skip-tests-several \
+		'GIT_SKIP_TESTS several tests' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test git-skip-tests-several <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 # skip passing test #5 (GIT_SKIP_TESTS)
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success 'GIT_SKIP_TESTS sh pattern' "
+	GIT_SKIP_TESTS='git.[2-5]' \
+		run_sub_test_lib_test git-skip-tests-sh-pattern \
+		'GIT_SKIP_TESTS sh pattern' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test git-skip-tests-sh-pattern <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
+	> ok 3 # skip passing test #3 (GIT_SKIP_TESTS)
+	> ok 4 # skip passing test #4 (GIT_SKIP_TESTS)
+	> ok 5 # skip passing test #5 (GIT_SKIP_TESTS)
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
 test_set_prereq HAVEIT
 haveit=no
 test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 569b52d..e035f36 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -452,25 +452,28 @@ test_finish_ () {
 
 test_skip () {
 	to_skip=
+	skipped_reason=
 	if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS
 	then
 		to_skip=t
+		skipped_reason="GIT_SKIP_TESTS"
 	fi
 	if test -z "$to_skip" && test -n "$test_prereq" &&
 	   ! test_have_prereq "$test_prereq"
 	then
 		to_skip=t
-	fi
-	case "$to_skip" in
-	t)
+
 		of_prereq=
 		if test "$missing_prereq" != "$test_prereq"
 		then
 			of_prereq=" of $test_prereq"
 		fi
-
+		skipped_reason="missing $missing_prereq${of_prereq}"
+	fi
+	case "$to_skip" in
+	t)
 		say_color skip >&3 "skipping test: $@"
-		say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
+		say_color skip "ok $test_count # skip $1 ($skipped_reason)"
 		: true
 		;;
 	*)
-- 
1.7.9
Ilya Bobyr· Mar 24, 2014, 08:49 UTC · re: Ilya Bobyr · lore

[PATCH 3/3] test-lib: '--run' to run only specific tests

Allow better control of the set of tests that will be executed for a single test suite. Mostly useful while debugging or developing as it allows to focus on a specific test.

Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
---
 t/README         |   65 ++++++++++++++-
 t/t0000-basic.sh |  233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/test-lib.sh    |   85 ++++++++++++++++++++
 3 files changed, 379 insertions(+), 4 deletions(-)
Show changes to 3 files +379 −4

t/README, t/t0000-basic.sh, t/test-lib.sh

diff --git a/t/README b/t/README
index ccb5989..519f0dc 100644
--- a/t/README
+++ b/t/README
@@ -100,6 +100,10 @@ appropriately before running "make".
 	This causes additional long-running tests to be run (where
 	available), for more exhaustive testing.
 
+-r,--run=<test numbers>::
+	This causes only specific tests to be included or excluded.  See
+	section "Skipping Tests" below for "<test numbers>" syntax.
+
 -v,--valgrind=<tool>::
 	Execute all Git binaries under valgrind tool <tool> and exit
 	with status 126 on errors (just like regular tests, this will
@@ -187,10 +191,63 @@ and either can match the "t[0-9]{4}" part to skip the whole
 test, or t[0-9]{4} followed by ".$number" to say which
 particular test to skip.
 
-Note that some tests in the existing test suite rely on previous
-test item, so you cannot arbitrarily disable one and expect the
-remainder of test to check what the test originally was intended
-to check.
+For an individual test suite --run could be used to specify that
+only some tests should be run or that some tests should be
+excluded from a run.
+
+--run argument is a list of patterns with optional prefixes that
+are matched against test numbers within the current test suite.
+Supported pattern:
+
+ - A number matches a test with that number.
+
+ - sh metacharacters such as '*', '?' and '[]' match as usual in
+   shell.
+
+ - A number prefixed with '<', '<=', '>', or '>=' matches all
+   tests 'before', 'before or including', 'after', or 'after or
+   including' the specified one.
+
+Optional prefixes are:
+
+ - '+' or no prefix: test(s) matching the pattern are included in
+   the run.
+
+ - '-' or '!': test(s) matching the pattern are exluded from the
+   run.
+
+If --run starts with '+' or unprefixed pattern the initial set of
+tests to run is empty. If the first pattern starts with '-' or
+'!' all the tests are added to the initial set.  After initial
+set is determined every pattern, test number or range is added or
+excluded from the set one by one, from left to right.
+
+For example, common case is to run several setup tests and then a
+specific test that relies on that setup:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='1 2 3 21'
+
+or:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='<4 21'
+
+To run only tests up to a specific test one could do this:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='!>=21'
+
+As noted above test set is build going though patterns left to
+right, so this:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='<5 !3'
+
+will run tests 1, 2, and 4.
+
+Some tests in the existing test suite rely on previous test item,
+so you cannot arbitrarily disable one and expect the remainder of
+test to check what the test originally was intended to check.
+--run is mostly useful when you want to focus on a specific test
+and know what you are doing.  Or when you want to run up to a
+certain test.
 
 
 Naming Tests
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index ae8874e..4da527f 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -333,6 +333,239 @@ test_expect_success 'GIT_SKIP_TESTS sh pattern' "
 	EOF
 "
 
+test_expect_success '--run basic' "
+	run_sub_test_lib_test run-basic \
+		'--run basic' --run='1 3 5' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-basic <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with <' "
+	run_sub_test_lib_test run-lt \
+		'--run with <' --run='<4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-lt <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 - passing test #3
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 # skip passing test #5 (--run)
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with <=' "
+	run_sub_test_lib_test run-le \
+		'--run with <=' --run='<=4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-le <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 # skip passing test #5 (--run)
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with >' "
+	run_sub_test_lib_test run-gt \
+		'--run with >' --run='>4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-gt <<-\\EOF
+	> ok 1 # skip passing test #1 (--run)
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with >=' "
+	run_sub_test_lib_test run-ge \
+		'--run with >=' --run='>=4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-ge <<-\\EOF
+	> ok 1 # skip passing test #1 (--run)
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with basic negation' "
+	run_sub_test_lib_test run-basic-neg \
+		'--run with basic negation' --run='-3' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-basic-neg <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with two negations' "
+	run_sub_test_lib_test run-two-neg \
+		'--run with two negation' --run='"'!3 !6'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-two-neg <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run < and negation' "
+	run_sub_test_lib_test run-lt-neg \
+		'--run < and negation' --run='"'<5 !2'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-lt-neg <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 # skip passing test #5 (--run)
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run range negation' "
+	run_sub_test_lib_test run-range-neg \
+		'--run range negation' --run='-<3' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-range-neg <<-\\EOF
+	> ok 1 # skip passing test #1 (--run)
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run include, exclude and include' "
+	run_sub_test_lib_test run-inc-neg-inc \
+		'--run include, exclude and include' \
+		--run='"'<=5 !<3 1'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-inc-neg-inc <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+test_expect_success '--run exclude and include' "
+	run_sub_test_lib_test run-neg-inc \
+		'--run exclude and include' \
+		--run='"'!>2 5'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-neg-inc <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+
 test_set_prereq HAVEIT
 haveit=no
 test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
diff --git a/t/test-lib.sh b/t/test-lib.sh
index e035f36..63e481a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -191,6 +191,14 @@ do
 		immediate=t; shift ;;
 	-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
 		GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
+	-r)
+		shift; test "$#" -ne 0 || {
+			echo 'error: -r requires an argument' >&2;
+			exit 1;
+		}
+		run_list=$1; shift ;;
+	--run=*)
+		run_list=$(expr "z$1" : 'z[^=]*=\(.*\)'); shift ;;
 	-h|--h|--he|--hel|--help)
 		help=t; shift ;;
 	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
@@ -366,6 +374,76 @@ match_pattern_list () {
 	return 1
 }
 
+match_run_pattern_list () {
+	arg="$1"
+	shift
+	test -z "$*" && return 0
+
+	# If the first patern is negative we include by default.
+	include=
+	case "$1" in
+		[-!]*) include=t ;;
+	esac
+
+	for pattern_
+	do
+		orig_pattern=$pattern_
+
+		positive=t
+		case "$pattern_" in
+			[-!]*)
+				positive=
+				pattern_=${pattern_##?}
+				;;
+		esac
+
+		# Short cut for "obvious" cases
+		[ "x$include" = "x" -a "x$positive" = "x" ] && continue
+		[ "x$include" = "xt" -a "x$positive" = "xt" ] && continue
+
+		pattern_op=
+		case "$pattern_" in
+			\<=*)
+				pattern_op='-le'
+				pattern_=${pattern_##??}
+				;;
+			\<*)
+				pattern_op='-lt'
+				pattern_=${pattern_##?}
+				;;
+			\>=*)
+				pattern_op='-ge'
+				pattern_=${pattern_##??}
+				;;
+			\>*)
+				pattern_op='-gt'
+				pattern_=${pattern_##?}
+				;;
+		esac
+
+		if test -n "$pattern_op"
+		then
+			if expr "z$pattern_" : "z[0-9]*[^0-9]" >/dev/null
+			then
+				echo "error: --run: test number contains" \
+					"non-digits: '$orig_pattern'" >&2
+				exit 1
+			fi
+			if test $arg $pattern_op $pattern_
+			then
+				include=$positive
+			fi
+		else
+			case "$arg" in
+				$pattern_)
+					include=$positive
+			esac
+		fi
+	done
+
+	test -n "$include"
+}
+
 maybe_teardown_verbose () {
 	test -z "$verbose_only" && return
 	exec 4>/dev/null 3>/dev/null
@@ -470,6 +548,13 @@ test_skip () {
 		fi
 		skipped_reason="missing $missing_prereq${of_prereq}"
 	fi
+	if test -z "$to_skip" && test -n "$run_list" &&
+		! match_run_pattern_list $test_count $run_list
+	then
+		to_skip=t
+		skipped_reason="--run"
+	fi
+
 	case "$to_skip" in
 	t)
 		say_color skip >&3 "skipping test: $@"
-- 
1.7.9
Jeff King· Mar 24, 2014, 23:03 UTC · re: Ilya Bobyr · lore

Re: [RFC/PATCH] Better control of the tests run by a test suite

On Mon, Mar 24, 2014 at 01:49:44AM -0700, Ilya Bobyr wrote:
Show 11 quoted lines
> Here are some examples of how functionality added by the patch
> could be used.  In order to run setup tests and then only a
> specific test (use case 1) one can do:
> 
>     $ ./t0000-init.sh --run='1 2 25'
> 
> or:
> 
>     $ ./t0000-init.sh --run='<3 25'
> 
> ('<=' is also supported, as well as '>' and '>=').

I don't have anything against this in principle, but I suspect it will end up being a big pain to figure out which of the early tests are required to set up the state, and which are not. Having "<" makes specifying it easier, but you still have to read the test script to figure out which tests need to be run.

I wonder if it would make sense to "auto-select" tests that match a regex like "set.?up|create"? A while ago, Jonathan made a claim that this would cover most tests that are dependencies of other tests. I did not believe him, but looking into it, I recall that we did seem to have quite a few matching that pattern. If there were a good feature like this that gave us a reason to follow that pattern, I think people might fix the remainder

-Peff
Junio C Hamano· Mar 25, 2014, 04:58 UTC · re: Jeff King · lore

Re: [RFC/PATCH] Better control of the tests run by a test suite

Jeff King <peff@peff.net> writes:
Show 19 quoted lines
> On Mon, Mar 24, 2014 at 01:49:44AM -0700, Ilya Bobyr wrote:
>
>> Here are some examples of how functionality added by the patch
>> could be used.  In order to run setup tests and then only a
>> specific test (use case 1) one can do:
>> 
>>     $ ./t0000-init.sh --run='1 2 25'
>> 
>> or:
>> 
>>     $ ./t0000-init.sh --run='<3 25'
>> 
>> ('<=' is also supported, as well as '>' and '>=').
>
> I don't have anything against this in principle, but I suspect it will
> end up being a big pain to figure out which of the early tests are
> required to set up the state, and which are not. Having "<" makes
> specifying it easier, but you still have to read the test script to
> figure out which tests need to be run.
Likewise.
Show 7 quoted lines
> I wonder if it would make sense to "auto-select" tests that match a
> regex like "set.?up|create"? A while ago, Jonathan made a claim that
> this would cover most tests that are dependencies of other tests. I did
> not believe him, but looking into it, I recall that we did seem to have
> quite a few matching that pattern. If there were a good feature like
> this that gave us a reason to follow that pattern, I think people might
> fix the remainder
This may be worth experimenting with, I would think.
Ilya Bobyr· Mar 27, 2014, 10:15 UTC · re: Junio C Hamano · lore

Re: [RFC/PATCH] Better control of the tests run by a test suite

On 3/24/2014 9:58 PM, Junio C Hamano wrote:
Show 21 quoted lines
> Jeff King <peff@peff.net> writes:
>
>> On Mon, Mar 24, 2014 at 01:49:44AM -0700, Ilya Bobyr wrote:
>>
>>> Here are some examples of how functionality added by the patch
>>> could be used.  In order to run setup tests and then only a
>>> specific test (use case 1) one can do:
>>>
>>>     $ ./t0000-init.sh --run='1 2 25'
>>>
>>> or:
>>>
>>>     $ ./t0000-init.sh --run='<3 25'
>>>
>>> ('<=' is also supported, as well as '>' and '>=').
>> I don't have anything against this in principle, but I suspect it will
>> end up being a big pain to figure out which of the early tests are
>> required to set up the state, and which are not. Having "<" makes
>> specifying it easier, but you still have to read the test script to
>> figure out which tests need to be run.
> Likewise.

The idea is that you will use that option when you know what setup the test need. And the case that I was targeting is when you are the author of the test, because you are also writing the relevant functionality or you are really familiar with the test because you are, again, working on something in that area.

It does not mean you actually have to do it. It is just a possibility.

And as you mentioned, "<" helps in another case - when you do not know enough about the test, but want to run it. For example when you are just starting with a failed test.

My experience, thought quite limited, is that it is very simple to understand what the test needs and where it is prepared, if you are actually adding new test to a test suite. Or if you spent some time figuring how specific test works. I think this is mostly because all the tests are rather simple. Which is definitely a good thing.

This is not for cases when you treat test suites as black boxes. For example, when you are just checking someone else code.

Show 8 quoted lines
>> I wonder if it would make sense to "auto-select" tests that match a
>> regex like "set.?up|create"? A while ago, Jonathan made a claim that
>> this would cover most tests that are dependencies of other tests. I did
>> not believe him, but looking into it, I recall that we did seem to have
>> quite a few matching that pattern. If there were a good feature like
>> this that gave us a reason to follow that pattern, I think people might
>> fix the remainder
> This may be worth experimenting with, I would think.

I was also thinking about it a bit. I do not have that much knowledge on how all the tests are organized. But I did see some cases where this rule would fail.

One example would be "t\t0000-basic.sh". It could probably be considered a very special test suite, but if you skip one of these tests:

 - "test runs if prerequisite is satisfied"
 - "unmet prerequisite causes test to be skipped"

the test suite would just exit in the middle. There is a number of other tests that you do not want to skip for the same reason. Also, in the same test suite "showing tree with git ls-tree -r" is a setup test for the next one "git ls-tree -r output for a known tree". And the same pattern is repeated for some other tests.

I've also looked at "t5601-clone.sh". There is indeed a test called "setup" at the very beginning. But somewhere in the middle there is a test called "clone from .git file" that creates a folder used in two subsequent tests.

In "t0001-init.sh", "re-init on .git file" creates a folder that is used in the next test called "re-init to update git link".

Maybe these are just some outliers, I do not know for sure. These were the only test suites I've looked at so far.

I think that if there is a desire to support automatic setup for tests maybe a rule could be introduced that a test must succeed, if there is no breakage, if all the tests that match regex '^(setup|cleanup)\>' before it have been run. It should not be too complicated to create a target that would automate checking of this rule.

I am not 100% sure that this kind of change is worth the trouble. People who run individual tests should probably know why they are doing it. And as such that might know the prerequisites.

Otherwise I can not come up with a reason to run an individual test.

On the other hand, the rule may add a bit more structure to the tests and automated checking could enforce that.

Ilya Bobyr· Mar 27, 2014, 10:32 UTC · re: Ilya Bobyr · lore

[RFC/PATCH v2] Better control of the tests run by a test suite

This is an update verson of the patches I've posted here:
    [RFC/PATCH] Better control of the tests run by a test suite
    http://www.mail-archive.com/git@vger.kernel.org/msg46419.html
Chanes are only in the first patch, according to
    http://www.mail-archive.com/git@vger.kernel.org/msg46423.html
    Ramsay Jones
and
    http://www.mail-archive.com/git@vger.kernel.org/msg46512.html
    Eric Sunshine

The description below is identical to the previous one, but here it is for convenience if someone would want to quote it in a comment.

---
Hello,
This is a second attempt on a functionality I proposed in
    [PATCH 2/2] test-lib: GIT_TEST_ONLY to run only specific tests
    http://www.mail-archive.com/git%40vger.kernel.org/msg44828.html
except that the implementation is quite different now.

I hope that I have accounted for the comments that were voiced so far. Let's see

The idea behind the change is that sometimes it is convenient to run only certain tests from a test suite. Specifically I am thinking about the following two use cases:

 1. You are developing new functionality.  You add a test that
    fails and then you add and modify code to make it pass.
    
 2. You have a failed test and you need to understand what is
    wrong.
    
In the first case you when you run the test suite, you probably
want to run some setup tests and then only one test that you are
focused on.

For code written in C time between you make a change and see a test result is considerably increased by the compilation. But for script code turn around time is mostly due to the run time of the test suite itself. [1]

For the second case you actually want the test suite to stop after the failing test, so that you can examine the trash directory without any modifications from the subsequent tests. You probably do not care about them.

In the previous patch I've added an environment variable to control tests to be run in a test suite. I thought that it would be similar to an already existing GIT_SKIP_TESTS. As I did not provide a cover letter that caused some misunderstanding I think.

This patch adds new command line argument '--run' that accepts a list of patterns and restrictions on the test numbers that would be included or excluded from this run of the test suite.

During discussion of the previous patch there were some talks about extending GIT_SKIP_TESTS syntax. In particular here:

Show 21 quoted lines
> That is
>
>         GIT_SKIP_TESTS='t9??? !t91??'
>
> would skip nine-thousand series, but would run 91xx series, and all
> the others are not excluded.
>
> Simple rules to consider:
>
>  - If the list consists of _only_ negated patterns, pretend that
>    there is "unless otherwise specified with negatives, skip all
>    tests", i.e. treat GIT_SKIP_TESTS='!t91??' just the same way you
>    would treat GIT_SKIP_TESTS='* !t91??'.
>
>  - The orders should not matter for simplicity of the semantics;
>    before running each test, check if it matches any negative (and
>    run it if it matches, without looking at any positives), and
>    otherwise check if it matches any positive (and skip it if it
>    does not).
>
> Hmm?
    http://www.mail-archive.com/git%40vger.kernel.org/msg44922.html

I've used that as a basis, but the end result is somewhat different. Plus I've added boundary checks as in "<123".

Here are some examples of how functionality added by the patch could be used. In order to run setup tests and then only a specific test (use case 1) one can do:

    $ ./t0000-init.sh --run='1 2 25'
or:
    $ ./t0000-init.sh --run='<3 25'
('<=' is also supported, as well as '>' and '>=').
In order to run up to a specific test (use case 2) one can do:
    $ ./t0000-init.sh --run='<=34'
or:
    $ ./t0000-init.sh --run='!>34'

Simple semantics described above is easy to implement, but at the same time is probably not that convenient. Rules implemented by the patch are as follows:

 - Order does matter.  Whatever is specified on the right has
   higher precedence.
 - When the first pattern is positive the initial set of the
   tests to be run is empty.  You are adding to an empty set as
   in '1 2 25'.
   When the first pattern is negative the initial set of the
   tests to run contains all the tests.  You are subtracting
   from that set as in '!>34'.

It seems that for simple cases that gives simple syntax and is almost unbiased if you think about preferring inclusion over exclusion. While it is unlikely it also allows for complicated expressions. And the implementation is quite simple as well.

Main functionality is in the third patch. First two are just minor fixes in related parts of the code.

P.S. I did not reply to the previous patch thread as this one is quite different.

[1] Here are some times I see on Cygin:
    $ touch builtin/rev-parse.c
    
    $ time make
    ...
    
    real    0m10.382s
    user    0m3.829s
    sys     0m5.269s
Running the t0000-init.sh test suite is like this:
    $ time ./t0001-init.sh
    [...]
    1..36
    real    0m6.693s
    user    0m1.505s
    sys     0m3.937s

If I run only the 1, 2, 4 and 5th tests, it only half the time to run the tests:

    $ time GIT_SKIP_TESTS='t0001.[36789] t0001.??' ./t0001-init.sh
    [...]
    1..36
    real    0m3.313s
    user    0m0.769s
    sys     0m1.844s 
Overall the change is from 17 to 14 seconds it is not that big.

If you only consider the test suite, as you do while you develop an sh based tool, for example, the change is from 6.6 to 3.3 seconds. That is quite noticeable.

 t/README         |   73 ++++++++++++--
 t/t0000-basic.sh |  296 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/test-lib.sh    |   96 +++++++++++++++++-
 3 files changed, 453 insertions(+), 12 deletions(-)
Ilya Bobyr· Mar 27, 2014, 10:32 UTC · re: Ilya Bobyr · lore

[PATCH 1/3] test-lib: Document short options in t/README

Most arguments that could be provided to a test have short forms. Unless documented, the only way to learn them is to read the code.

Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
---
 Minor changes according to comments in
    http://www.mail-archive.com/git@vger.kernel.org/msg46423.html
    Ramsay Jones
 and
    http://www.mail-archive.com/git@vger.kernel.org/msg46512.html
    Eric Sunshine
 t/README |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
Show changes to t/README +4 −0
diff --git a/t/README b/t/README
index caeeb9d..6b93aca 100644
--- a/t/README
+++ b/t/README
@@ -71,7 +71,7 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
 (or -i) command line argument to the test, or by setting GIT_TEST_OPTS
 appropriately before running "make".
 
---verbose::
+-v,--verbose::
 	This makes the test more verbose.  Specifically, the
 	command being run and their output if any are also
 	output.
@@ -81,7 +81,7 @@ appropriately before running "make".
 	numbers matching <pattern>.  The number matched against is
 	simply the running count of the test within the file.
 
---debug::
+-d,--debug::
 	This may help the person who is developing a new test.
 	It causes the command defined with test_debug to run.
 	The "trash" directory (used to store all temporary data
@@ -89,14 +89,14 @@ appropriately before running "make".
 	failed tests so that you can inspect its contents after
 	the test finished.
 
---immediate::
+-i,--immediate::
 	This causes the test to immediately exit upon the first
 	failed test. Cleanup commands requested with
 	test_when_finished are not executed if the test failed,
 	in order to keep the state for inspection by the tester
 	to diagnose the bug.
 
---long-tests::
+-l,--long-tests::
 	This causes additional long-running tests to be run (where
 	available), for more exhaustive testing.
 
-- 
1.7.9
Ilya Bobyr· Mar 27, 2014, 10:32 UTC · re: Ilya Bobyr · lore

[PATCH 2/3] test-lib: tests skipped by GIT_SKIP_TESTS say so

We used to show "(missing )" next to tests skipped because they are specified in GIT_SKIP_TESTS. Use "(GIT_SKIP_TESTS)" instead.

Plus tests that check basic GIT_SKIP_TESTS functions.
Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
---
 No changes from the previous version.
 t/t0000-basic.sh |   63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/test-lib.sh    |   13 ++++++----
 2 files changed, 71 insertions(+), 5 deletions(-)
Show changes to 2 files +71 −5

t/t0000-basic.sh, t/test-lib.sh

diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index a2bb63c..ae8874e 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -270,6 +270,69 @@ test_expect_success 'test --verbose-only' '
 	EOF
 '
 
+test_expect_success 'GIT_SKIP_TESTS' "
+	GIT_SKIP_TESTS='git.2' \
+		run_sub_test_lib_test git-skip-tests-basic \
+		'GIT_SKIP_TESTS' <<-\\EOF &&
+	for i in 1 2 3
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test git-skip-tests-basic <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
+	> ok 3 - passing test #3
+	> # passed all 3 test(s)
+	> 1..3
+	EOF
+"
+
+test_expect_success 'GIT_SKIP_TESTS several tests' "
+	GIT_SKIP_TESTS='git.2 git.5' \
+		run_sub_test_lib_test git-skip-tests-several \
+		'GIT_SKIP_TESTS several tests' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test git-skip-tests-several <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 # skip passing test #5 (GIT_SKIP_TESTS)
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success 'GIT_SKIP_TESTS sh pattern' "
+	GIT_SKIP_TESTS='git.[2-5]' \
+		run_sub_test_lib_test git-skip-tests-sh-pattern \
+		'GIT_SKIP_TESTS sh pattern' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test git-skip-tests-sh-pattern <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (GIT_SKIP_TESTS)
+	> ok 3 # skip passing test #3 (GIT_SKIP_TESTS)
+	> ok 4 # skip passing test #4 (GIT_SKIP_TESTS)
+	> ok 5 # skip passing test #5 (GIT_SKIP_TESTS)
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
 test_set_prereq HAVEIT
 haveit=no
 test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 569b52d..e035f36 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -452,25 +452,28 @@ test_finish_ () {
 
 test_skip () {
 	to_skip=
+	skipped_reason=
 	if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS
 	then
 		to_skip=t
+		skipped_reason="GIT_SKIP_TESTS"
 	fi
 	if test -z "$to_skip" && test -n "$test_prereq" &&
 	   ! test_have_prereq "$test_prereq"
 	then
 		to_skip=t
-	fi
-	case "$to_skip" in
-	t)
+
 		of_prereq=
 		if test "$missing_prereq" != "$test_prereq"
 		then
 			of_prereq=" of $test_prereq"
 		fi
-
+		skipped_reason="missing $missing_prereq${of_prereq}"
+	fi
+	case "$to_skip" in
+	t)
 		say_color skip >&3 "skipping test: $@"
-		say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
+		say_color skip "ok $test_count # skip $1 ($skipped_reason)"
 		: true
 		;;
 	*)
-- 
1.7.9
Ilya Bobyr· Mar 27, 2014, 10:32 UTC · re: Ilya Bobyr · lore

[PATCH 3/3] test-lib: '--run' to run only specific tests

Allow better control of the set of tests that will be executed for a single test suite. Mostly useful while debugging or developing as it allows to focus on a specific test.

Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
---
 No changes from the previous version.
 t/README         |   65 ++++++++++++++-
 t/t0000-basic.sh |  233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/test-lib.sh    |   85 ++++++++++++++++++++
 3 files changed, 379 insertions(+), 4 deletions(-)
Show changes to 3 files +379 −4

t/README, t/t0000-basic.sh, t/test-lib.sh

diff --git a/t/README b/t/README
index 6b93aca..c911f89 100644
--- a/t/README
+++ b/t/README
@@ -100,6 +100,10 @@ appropriately before running "make".
 	This causes additional long-running tests to be run (where
 	available), for more exhaustive testing.
 
+-r,--run=<test numbers>::
+	This causes only specific tests to be included or excluded.  See
+	section "Skipping Tests" below for "<test numbers>" syntax.
+
 --valgrind=<tool>::
 	Execute all Git binaries under valgrind tool <tool> and exit
 	with status 126 on errors (just like regular tests, this will
@@ -187,10 +191,63 @@ and either can match the "t[0-9]{4}" part to skip the whole
 test, or t[0-9]{4} followed by ".$number" to say which
 particular test to skip.
 
-Note that some tests in the existing test suite rely on previous
-test item, so you cannot arbitrarily disable one and expect the
-remainder of test to check what the test originally was intended
-to check.
+For an individual test suite --run could be used to specify that
+only some tests should be run or that some tests should be
+excluded from a run.
+
+--run argument is a list of patterns with optional prefixes that
+are matched against test numbers within the current test suite.
+Supported pattern:
+
+ - A number matches a test with that number.
+
+ - sh metacharacters such as '*', '?' and '[]' match as usual in
+   shell.
+
+ - A number prefixed with '<', '<=', '>', or '>=' matches all
+   tests 'before', 'before or including', 'after', or 'after or
+   including' the specified one.
+
+Optional prefixes are:
+
+ - '+' or no prefix: test(s) matching the pattern are included in
+   the run.
+
+ - '-' or '!': test(s) matching the pattern are exluded from the
+   run.
+
+If --run starts with '+' or unprefixed pattern the initial set of
+tests to run is empty. If the first pattern starts with '-' or
+'!' all the tests are added to the initial set.  After initial
+set is determined every pattern, test number or range is added or
+excluded from the set one by one, from left to right.
+
+For example, common case is to run several setup tests and then a
+specific test that relies on that setup:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='1 2 3 21'
+
+or:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='<4 21'
+
+To run only tests up to a specific test one could do this:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='!>=21'
+
+As noted above test set is build going though patterns left to
+right, so this:
+
+    $ sh ./t9200-git-cvsexport-commit.sh --run='<5 !3'
+
+will run tests 1, 2, and 4.
+
+Some tests in the existing test suite rely on previous test item,
+so you cannot arbitrarily disable one and expect the remainder of
+test to check what the test originally was intended to check.
+--run is mostly useful when you want to focus on a specific test
+and know what you are doing.  Or when you want to run up to a
+certain test.
 
 
 Naming Tests
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index ae8874e..4da527f 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -333,6 +333,239 @@ test_expect_success 'GIT_SKIP_TESTS sh pattern' "
 	EOF
 "
 
+test_expect_success '--run basic' "
+	run_sub_test_lib_test run-basic \
+		'--run basic' --run='1 3 5' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-basic <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with <' "
+	run_sub_test_lib_test run-lt \
+		'--run with <' --run='<4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-lt <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 - passing test #3
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 # skip passing test #5 (--run)
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with <=' "
+	run_sub_test_lib_test run-le \
+		'--run with <=' --run='<=4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-le <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 # skip passing test #5 (--run)
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with >' "
+	run_sub_test_lib_test run-gt \
+		'--run with >' --run='>4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-gt <<-\\EOF
+	> ok 1 # skip passing test #1 (--run)
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with >=' "
+	run_sub_test_lib_test run-ge \
+		'--run with >=' --run='>=4' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-ge <<-\\EOF
+	> ok 1 # skip passing test #1 (--run)
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with basic negation' "
+	run_sub_test_lib_test run-basic-neg \
+		'--run with basic negation' --run='-3' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-basic-neg <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run with two negations' "
+	run_sub_test_lib_test run-two-neg \
+		'--run with two negation' --run='"'!3 !6'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-two-neg <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run < and negation' "
+	run_sub_test_lib_test run-lt-neg \
+		'--run < and negation' --run='"'<5 !2'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-lt-neg <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 # skip passing test #5 (--run)
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run range negation' "
+	run_sub_test_lib_test run-range-neg \
+		'--run range negation' --run='-<3' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-range-neg <<-\\EOF
+	> ok 1 # skip passing test #1 (--run)
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 - passing test #6
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+test_expect_success '--run include, exclude and include' "
+	run_sub_test_lib_test run-inc-neg-inc \
+		'--run include, exclude and include' \
+		--run='"'<=5 !<3 1'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-inc-neg-inc <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 # skip passing test #2 (--run)
+	> ok 3 - passing test #3
+	> ok 4 - passing test #4
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+test_expect_success '--run exclude and include' "
+	run_sub_test_lib_test run-neg-inc \
+		'--run exclude and include' \
+		--run='"'!>2 5'"' <<-\\EOF &&
+	for i in 1 2 3 4 5 6
+	do
+		test_expect_success \"passing test #\$i\" 'true'
+	done
+	test_done
+	EOF
+	check_sub_test_lib_test run-neg-inc <<-\\EOF
+	> ok 1 - passing test #1
+	> ok 2 - passing test #2
+	> ok 3 # skip passing test #3 (--run)
+	> ok 4 # skip passing test #4 (--run)
+	> ok 5 - passing test #5
+	> ok 6 # skip passing test #6 (--run)
+	> # passed all 6 test(s)
+	> 1..6
+	EOF
+"
+
+
 test_set_prereq HAVEIT
 haveit=no
 test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
diff --git a/t/test-lib.sh b/t/test-lib.sh
index e035f36..63e481a 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -191,6 +191,14 @@ do
 		immediate=t; shift ;;
 	-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
 		GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
+	-r)
+		shift; test "$#" -ne 0 || {
+			echo 'error: -r requires an argument' >&2;
+			exit 1;
+		}
+		run_list=$1; shift ;;
+	--run=*)
+		run_list=$(expr "z$1" : 'z[^=]*=\(.*\)'); shift ;;
 	-h|--h|--he|--hel|--help)
 		help=t; shift ;;
 	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
@@ -366,6 +374,76 @@ match_pattern_list () {
 	return 1
 }
 
+match_run_pattern_list () {
+	arg="$1"
+	shift
+	test -z "$*" && return 0
+
+	# If the first patern is negative we include by default.
+	include=
+	case "$1" in
+		[-!]*) include=t ;;
+	esac
+
+	for pattern_
+	do
+		orig_pattern=$pattern_
+
+		positive=t
+		case "$pattern_" in
+			[-!]*)
+				positive=
+				pattern_=${pattern_##?}
+				;;
+		esac
+
+		# Short cut for "obvious" cases
+		[ "x$include" = "x" -a "x$positive" = "x" ] && continue
+		[ "x$include" = "xt" -a "x$positive" = "xt" ] && continue
+
+		pattern_op=
+		case "$pattern_" in
+			\<=*)
+				pattern_op='-le'
+				pattern_=${pattern_##??}
+				;;
+			\<*)
+				pattern_op='-lt'
+				pattern_=${pattern_##?}
+				;;
+			\>=*)
+				pattern_op='-ge'
+				pattern_=${pattern_##??}
+				;;
+			\>*)
+				pattern_op='-gt'
+				pattern_=${pattern_##?}
+				;;
+		esac
+
+		if test -n "$pattern_op"
+		then
+			if expr "z$pattern_" : "z[0-9]*[^0-9]" >/dev/null
+			then
+				echo "error: --run: test number contains" \
+					"non-digits: '$orig_pattern'" >&2
+				exit 1
+			fi
+			if test $arg $pattern_op $pattern_
+			then
+				include=$positive
+			fi
+		else
+			case "$arg" in
+				$pattern_)
+					include=$positive
+			esac
+		fi
+	done
+
+	test -n "$include"
+}
+
 maybe_teardown_verbose () {
 	test -z "$verbose_only" && return
 	exec 4>/dev/null 3>/dev/null
@@ -470,6 +548,13 @@ test_skip () {
 		fi
 		skipped_reason="missing $missing_prereq${of_prereq}"
 	fi
+	if test -z "$to_skip" && test -n "$run_list" &&
+		! match_run_pattern_list $test_count $run_list
+	then
+		to_skip=t
+		skipped_reason="--run"
+	fi
+
 	case "$to_skip" in
 	t)
 		say_color skip >&3 "skipping test: $@"
-- 
1.7.9
Eric Sunshine· Mar 28, 2014, 03:36 UTC · re: Ilya Bobyr · lore

Re: [PATCH 3/3] test-lib: '--run' to run only specific tests

On Thu, Mar 27, 2014 at 6:32 AM, Ilya Bobyr <ilya.bobyr@gmail.com> wrote:
Show 22 quoted lines
> Allow better control of the set of tests that will be executed for a
> single test suite.  Mostly useful while debugging or developing as it
> allows to focus on a specific test.
>
> Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
> ---
>  No changes from the previous version.
>
>  t/README         |   65 ++++++++++++++-
>  t/t0000-basic.sh |  233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  t/test-lib.sh    |   85 ++++++++++++++++++++
>  3 files changed, 379 insertions(+), 4 deletions(-)
>
> diff --git a/t/README b/t/README
> index 6b93aca..c911f89 100644
> --- a/t/README
> +++ b/t/README
> @@ -100,6 +100,10 @@ appropriately before running "make".
>         This causes additional long-running tests to be run (where
>         available), for more exhaustive testing.
>
> +-r,--run=<test numbers>::
Perhaps <test-selection> or something similar would be closer to the truth.
> +       This causes only specific tests to be included or excluded.  See

This is phrased somewhat oddly, as if you had already been talking about tests being included or excluded, and that this option merely changes that selection. Perhaps something like:

    Run only the subset of tests indicated by <test-selection>.
Show 18 quoted lines
> +       section "Skipping Tests" below for "<test numbers>" syntax.
> +
>  --valgrind=<tool>::
>         Execute all Git binaries under valgrind tool <tool> and exit
>         with status 126 on errors (just like regular tests, this will
> @@ -187,10 +191,63 @@ and either can match the "t[0-9]{4}" part to skip the whole
>  test, or t[0-9]{4} followed by ".$number" to say which
>  particular test to skip.
>
> -Note that some tests in the existing test suite rely on previous
> -test item, so you cannot arbitrarily disable one and expect the
> -remainder of test to check what the test originally was intended
> -to check.
> +For an individual test suite --run could be used to specify that
> +only some tests should be run or that some tests should be
> +excluded from a run.
> +
> +--run argument is a list of patterns with optional prefixes that
"The argument for --run is a list...
Show 11 quoted lines
> +are matched against test numbers within the current test suite.
> +Supported pattern:
> +
> + - A number matches a test with that number.
> +
> + - sh metacharacters such as '*', '?' and '[]' match as usual in
> +   shell.
> +
> + - A number prefixed with '<', '<=', '>', or '>=' matches all
> +   tests 'before', 'before or including', 'after', or 'after or
> +   including' the specified one.

I think you want "and" rather than "or": "before and including", "after and including".

Show 7 quoted lines
> +Optional prefixes are:
> +
> + - '+' or no prefix: test(s) matching the pattern are included in
> +   the run.
> +
> + - '-' or '!': test(s) matching the pattern are exluded from the
> +   run.

I've been playing with --run, and I find that test selection is not especially intuitive. For instance, ">=16 !>24 !20" is easier to reason about when written instead with ranges, such as "16-19 21-24", or perhaps "16-24 !20". Open-ended ranges make sense too: "5-" means tests 5 through the last, and "-5" means tests 1 through 5. (Yes, this conflicts with your use of '-' to mean negation, but you already have the perfectly serviceable '!' as an alias for negation.)

Show 8 quoted lines
> +If --run starts with '+' or unprefixed pattern the initial set of
> +tests to run is empty. If the first pattern starts with '-' or
> +'!' all the tests are added to the initial set.  After initial
> +set is determined every pattern, test number or range is added or
> +excluded from the set one by one, from left to right.
> +
> +For example, common case is to run several setup tests and then a
> +specific test that relies on that setup:
Perhaps be a bit more specific:
    ...run several setup tests (1, 2, 3) and then a
    specific test (21) that relies...
Show 5 quoted lines
> +    $ sh ./t9200-git-cvsexport-commit.sh --run='1 2 3 21'
> +
> +or:
> +
> +    $ sh ./t9200-git-cvsexport-commit.sh --run='<4 21'
It might be clearer to say "<=3" rather than "<4".
> +To run only tests up to a specific test one could do this:
s/specific test/specific test,/
Also perhaps:
    ...up to a specific test (21), one...
> +    $ sh ./t9200-git-cvsexport-commit.sh --run='!>=21'
> +
> +As noted above test set is build going though patterns left to

s/above/above,/ s/test set/the test set/ s/build/built/

    As noted above, the test set is built...
Show 44 quoted lines
> +right, so this:
> +
> +    $ sh ./t9200-git-cvsexport-commit.sh --run='<5 !3'
> +
> +will run tests 1, 2, and 4.
> +
> +Some tests in the existing test suite rely on previous test item,
> +so you cannot arbitrarily disable one and expect the remainder of
> +test to check what the test originally was intended to check.
> +--run is mostly useful when you want to focus on a specific test
> +and know what you are doing.  Or when you want to run up to a
> +certain test.
>
>
>  Naming Tests
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index e035f36..63e481a 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -191,6 +191,14 @@ do
>                 immediate=t; shift ;;
>         -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
>                 GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
> +       -r)
> +               shift; test "$#" -ne 0 || {
> +                       echo 'error: -r requires an argument' >&2;
> +                       exit 1;
> +               }
> +               run_list=$1; shift ;;
> +       --run=*)
> +               run_list=$(expr "z$1" : 'z[^=]*=\(.*\)'); shift ;;
>         -h|--h|--he|--hel|--help)
>                 help=t; shift ;;
>         -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
> @@ -366,6 +374,76 @@ match_pattern_list () {
>         return 1
>  }
>
> +match_run_pattern_list () {
> +       arg="$1"
> +       shift
> +       test -z "$*" && return 0
> +
> +       # If the first patern is negative we include by default.
s/patern/pattern/
Show 19 quoted lines
> +       include=
> +       case "$1" in
> +               [-!]*) include=t ;;
> +       esac
> +
> +       for pattern_
> +       do
> +               orig_pattern=$pattern_
> +
> +               positive=t
> +               case "$pattern_" in
> +                       [-!]*)
> +                               positive=
> +                               pattern_=${pattern_##?}
> +                               ;;
> +               esac
> +
> +               # Short cut for "obvious" cases
> +               [ "x$include" = "x" -a "x$positive" = "x" ] && continue

Although there are a few exceptions in this script, 'test' is generally preferred over '['. Also, -a doesn't have great portability, so && may be better.

    test -z "$include" && test -z "$positive" && continue
> +               [ "x$include" = "xt" -a "x$positive" = "xt" ] && continue
Since you're inside double quotes, you can drop the 'x' prefix:
    test "$include" = t && test "$positive" = t && continue
Show 23 quoted lines
> +               pattern_op=
> +               case "$pattern_" in
> +                       \<=*)
> +                               pattern_op='-le'
> +                               pattern_=${pattern_##??}
> +                               ;;
> +                       \<*)
> +                               pattern_op='-lt'
> +                               pattern_=${pattern_##?}
> +                               ;;
> +                       \>=*)
> +                               pattern_op='-ge'
> +                               pattern_=${pattern_##??}
> +                               ;;
> +                       \>*)
> +                               pattern_op='-gt'
> +                               pattern_=${pattern_##?}
> +                               ;;
> +               esac
> +
> +               if test -n "$pattern_op"
> +               then
> +                       if expr "z$pattern_" : "z[0-9]*[^0-9]" >/dev/null
Inside double quotes: you can drop the 'z' prefix.
Show 32 quoted lines
> +                       then
> +                               echo "error: --run: test number contains" \
> +                                       "non-digits: '$orig_pattern'" >&2
> +                               exit 1
> +                       fi
> +                       if test $arg $pattern_op $pattern_
> +                       then
> +                               include=$positive
> +                       fi
> +               else
> +                       case "$arg" in
> +                               $pattern_)
> +                                       include=$positive
> +                       esac
> +               fi
> +       done
> +
> +       test -n "$include"
> +}
> +
>  maybe_teardown_verbose () {
>         test -z "$verbose_only" && return
>         exec 4>/dev/null 3>/dev/null
> @@ -470,6 +548,13 @@ test_skip () {
>                 fi
>                 skipped_reason="missing $missing_prereq${of_prereq}"
>         fi
> +       if test -z "$to_skip" && test -n "$run_list" &&
> +               ! match_run_pattern_list $test_count $run_list
> +       then
> +               to_skip=t
> +               skipped_reason="--run"
A few pure bike-shedding comments (to be ignore if desired):

I still don't understand the need to distinguish between a test skipped due to --run and and one skipped due to GIT_SKIP_TESTS.

The skip-reason "GIT_SKIP_TESTS" (in patch 2/3) still seems unnecessarily verbose and loud.

The skip-reason "excluded" (suggested in an earlier review) is short and sweet, and equally applicable to a test skipped either via --run or GIT_SKIP_TESTS.

Show 8 quoted lines
> +       fi
> +
>         case "$to_skip" in
>         t)
>                 say_color skip >&3 "skipping test: $@"
> --
> 1.7.9
>
Ilya Bobyr· Mar 28, 2014, 07:05 UTC · re: Eric Sunshine · lore

Re: [PATCH 3/3] test-lib: '--run' to run only specific tests

On 3/27/2014 8:36 PM, Eric Sunshine wrote:
Show 24 quoted lines
> On Thu, Mar 27, 2014 at 6:32 AM, Ilya Bobyr <ilya.bobyr@gmail.com> wrote:
>> Allow better control of the set of tests that will be executed for a
>> single test suite.  Mostly useful while debugging or developing as it
>> allows to focus on a specific test.
>>
>> Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
>> ---
>>  No changes from the previous version.
>>
>>  t/README         |   65 ++++++++++++++-
>>  t/t0000-basic.sh |  233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  t/test-lib.sh    |   85 ++++++++++++++++++++
>>  3 files changed, 379 insertions(+), 4 deletions(-)
>>
>> diff --git a/t/README b/t/README
>> index 6b93aca..c911f89 100644
>> --- a/t/README
>> +++ b/t/README
>> @@ -100,6 +100,10 @@ appropriately before running "make".
>>         This causes additional long-running tests to be run (where
>>         available), for more exhaustive testing.
>>
>> +-r,--run=<test numbers>::
> Perhaps <test-selection> or something similar would be closer to the truth.
I think your naming is better.  I will include it in the next version.
Show 6 quoted lines
>> +       This causes only specific tests to be included or excluded.  See
> This is phrased somewhat oddly, as if you had already been talking
> about tests being included or excluded, and that this option merely
> changes that selection. Perhaps something like:
>
>     Run only the subset of tests indicated by <test-selection>.
Will use that sentence as well :)
Show 19 quoted lines
>> +       section "Skipping Tests" below for "<test numbers>" syntax.
>> +
>>  --valgrind=<tool>::
>>         Execute all Git binaries under valgrind tool <tool> and exit
>>         with status 126 on errors (just like regular tests, this will
>> @@ -187,10 +191,63 @@ and either can match the "t[0-9]{4}" part to skip the whole
>>  test, or t[0-9]{4} followed by ".$number" to say which
>>  particular test to skip.
>>
>> -Note that some tests in the existing test suite rely on previous
>> -test item, so you cannot arbitrarily disable one and expect the
>> -remainder of test to check what the test originally was intended
>> -to check.
>> +For an individual test suite --run could be used to specify that
>> +only some tests should be run or that some tests should be
>> +excluded from a run.
>> +
>> +--run argument is a list of patterns with optional prefixes that
> "The argument for --run is a list...

I think it could be either. But I am not a native speaker. So, I will use your version :)

Show 13 quoted lines
>> +are matched against test numbers within the current test suite.
>> +Supported pattern:
>> +
>> + - A number matches a test with that number.
>> +
>> + - sh metacharacters such as '*', '?' and '[]' match as usual in
>> +   shell.
>> +
>> + - A number prefixed with '<', '<=', '>', or '>=' matches all
>> +   tests 'before', 'before or including', 'after', or 'after or
>> +   including' the specified one.
> I think you want "and" rather than "or": "before and including",
> "after and including".

I was thinking about an analogy to the corresponding mathematical operations here. In mathematics, '<=' is called "less than or equal to"[1].

If you are thinking about test numbers you can say that you include a test if it has a number before or equal to the given one. The sentence is "A number prefixed with <= matches all tests [with numbers] before or including the specified [number]."

Maybe if I change "one" to "number" it would be a bit less ambiguous. Or even include all the omitted words.

I would not mind a completely different way to say it, but I am not yet sure that if I replace "or" with "and" it would make it a lot better.

[1] https://en.wikipedia.org/wiki/Inequality_%28mathematics%29
Show 14 quoted lines
>> +Optional prefixes are:
>> +
>> + - '+' or no prefix: test(s) matching the pattern are included in
>> +   the run.
>> +
>> + - '-' or '!': test(s) matching the pattern are exluded from the
>> +   run.
> I've been playing with --run, and I find that test selection is not
> especially intuitive. For instance, ">=16 !>24 !20" is easier to
> reason about when written instead with ranges, such as "16-19 21-24",
> or perhaps "16-24 !20". Open-ended ranges make sense too: "5-" means
> tests 5 through the last, and "-5" means tests 1 through 5. (Yes, this
> conflicts with your use of '-' to mean negation, but you already have
> the perfectly serviceable '!' as an alias for negation.)

I completely agree that ranges allow one to express certain "obvious" things much easier than just inequalities. I was even thinking on a possible syntax. But then I realized that I do not have a real use case for it.

The only use case that I had is described in the cover letter: to run several setup tests and then the target test. For that even simple lists were enough and I was using that original version with an environment variable. After a conversation on the list I thought that it would be nice to be able to say '<', as it would save typing several extra characters for cases like '1 2 3 4 25'. While test suits that I've seen so far actually have no more than two tests that do the setup.

The next use case that I could come up with was running up to a specific test. I was in a situation were that would have been a nice option. And inequalities allow that.

Once again, I do not have a use case where I would need to run tests from 1 to 10, then 14 to 19 and then 100 and up to the end.

Do you have something on your mind where that would be useful?

As for the syntax, ! is replaced in bash by the last executed command. That happens inside double quotes as well and the original command line is not preserved (at lest for me). So if it would be the only option that seemed like a limitation. It is possible to escape it or use single quotes, of course. I was thinking about a comma as a separator for ranges.

As for the open ended ranges - they are the same as inequalities.
Show 12 quoted lines
>> +If --run starts with '+' or unprefixed pattern the initial set of
>> +tests to run is empty. If the first pattern starts with '-' or
>> +'!' all the tests are added to the initial set.  After initial
>> +set is determined every pattern, test number or range is added or
>> +excluded from the set one by one, from left to right.
>> +
>> +For example, common case is to run several setup tests and then a
>> +specific test that relies on that setup:
> Perhaps be a bit more specific:
>
>     ...run several setup tests (1, 2, 3) and then a
>     specific test (21) that relies...

Good idea, though it clutters the sentence a bit. Will use it.

Show 6 quoted lines
>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='1 2 3 21'
>> +
>> +or:
>> +
>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='<4 21'
> It might be clearer to say "<=3" rather than "<4".

I thought that < is less typing, so it should be the first one to show. Non-strict inequalities were next. I will change this example and show '<' and '>' in the next two.

Show 6 quoted lines
>> +To run only tests up to a specific test one could do this:
> s/specific test/specific test,/
>
> Also perhaps:
>
>     ...up to a specific test (21), one...
Fixed.
Show 8 quoted lines
>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='!>=21'
>> +
>> +As noted above test set is build going though patterns left to
> s/above/above,/
> s/test set/the test set/
> s/build/built/
>
>     As noted above, the test set is built...
Thanks :)
Show 45 quoted lines
>> +right, so this:
>> +
>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='<5 !3'
>> +
>> +will run tests 1, 2, and 4.
>> +
>> +Some tests in the existing test suite rely on previous test item,
>> +so you cannot arbitrarily disable one and expect the remainder of
>> +test to check what the test originally was intended to check.
>> +--run is mostly useful when you want to focus on a specific test
>> +and know what you are doing.  Or when you want to run up to a
>> +certain test.
>>
>>
>>  Naming Tests
>> diff --git a/t/test-lib.sh b/t/test-lib.sh
>> index e035f36..63e481a 100644
>> --- a/t/test-lib.sh
>> +++ b/t/test-lib.sh
>> @@ -191,6 +191,14 @@ do
>>                 immediate=t; shift ;;
>>         -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
>>                 GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
>> +       -r)
>> +               shift; test "$#" -ne 0 || {
>> +                       echo 'error: -r requires an argument' >&2;
>> +                       exit 1;
>> +               }
>> +               run_list=$1; shift ;;
>> +       --run=*)
>> +               run_list=$(expr "z$1" : 'z[^=]*=\(.*\)'); shift ;;
>>         -h|--h|--he|--hel|--help)
>>                 help=t; shift ;;
>>         -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
>> @@ -366,6 +374,76 @@ match_pattern_list () {
>>         return 1
>>  }
>>
>> +match_run_pattern_list () {
>> +       arg="$1"
>> +       shift
>> +       test -z "$*" && return 0
>> +
>> +       # If the first patern is negative we include by default.
> s/patern/pattern/
Fixed.
Show 24 quoted lines
>> +       include=
>> +       case "$1" in
>> +               [-!]*) include=t ;;
>> +       esac
>> +
>> +       for pattern_
>> +       do
>> +               orig_pattern=$pattern_
>> +
>> +               positive=t
>> +               case "$pattern_" in
>> +                       [-!]*)
>> +                               positive=
>> +                               pattern_=${pattern_##?}
>> +                               ;;
>> +               esac
>> +
>> +               # Short cut for "obvious" cases
>> +               [ "x$include" = "x" -a "x$positive" = "x" ] && continue
> Although there are a few exceptions in this script, 'test' is
> generally preferred over '['. Also, -a doesn't have great portability,
> so && may be better.
>
>     test -z "$include" && test -z "$positive" && continue
Did not know that.  Changed.
>> +               [ "x$include" = "xt" -a "x$positive" = "xt" ] && continue
> Since you're inside double quotes, you can drop the 'x' prefix:
>
>     test "$include" = t && test "$positive" = t && continue

Did not know that either %) Fixed. I saw it was used like that in the part that does argument parsing. So I just used style from there =)

Show 24 quoted lines
>> +               pattern_op=
>> +               case "$pattern_" in
>> +                       \<=*)
>> +                               pattern_op='-le'
>> +                               pattern_=${pattern_##??}
>> +                               ;;
>> +                       \<*)
>> +                               pattern_op='-lt'
>> +                               pattern_=${pattern_##?}
>> +                               ;;
>> +                       \>=*)
>> +                               pattern_op='-ge'
>> +                               pattern_=${pattern_##??}
>> +                               ;;
>> +                       \>*)
>> +                               pattern_op='-gt'
>> +                               pattern_=${pattern_##?}
>> +                               ;;
>> +               esac
>> +
>> +               if test -n "$pattern_op"
>> +               then
>> +                       if expr "z$pattern_" : "z[0-9]*[^0-9]" >/dev/null
> Inside double quotes: you can drop the 'z' prefix.
Thanks.
Show 43 quoted lines
>> +                       then
>> +                               echo "error: --run: test number contains" \
>> +                                       "non-digits: '$orig_pattern'" >&2
>> +                               exit 1
>> +                       fi
>> +                       if test $arg $pattern_op $pattern_
>> +                       then
>> +                               include=$positive
>> +                       fi
>> +               else
>> +                       case "$arg" in
>> +                               $pattern_)
>> +                                       include=$positive
>> +                       esac
>> +               fi
>> +       done
>> +
>> +       test -n "$include"
>> +}
>> +
>>  maybe_teardown_verbose () {
>>         test -z "$verbose_only" && return
>>         exec 4>/dev/null 3>/dev/null
>> @@ -470,6 +548,13 @@ test_skip () {
>>                 fi
>>                 skipped_reason="missing $missing_prereq${of_prereq}"
>>         fi
>> +       if test -z "$to_skip" && test -n "$run_list" &&
>> +               ! match_run_pattern_list $test_count $run_list
>> +       then
>> +               to_skip=t
>> +               skipped_reason="--run"
> A few pure bike-shedding comments (to be ignore if desired):
>
> I still don't understand the need to distinguish between a test
> skipped due to --run and and one skipped due to GIT_SKIP_TESTS.
>
> The skip-reason "GIT_SKIP_TESTS" (in patch 2/3) still seems
> unnecessarily verbose and loud.
>
> The skip-reason "excluded" (suggested in an earlier review) is short
> and sweet, and equally applicable to a test skipped either via --run
> or GIT_SKIP_TESTS.

Well, technically, it already says that the test is skipped. So adding "excluded" is actually a bit redundant. Part that is in the parenthesis explains the reason, at least for the case when a test is skipped because a prerequisite is missing.

When you are just starting, I think, it is nice when the tool tells you exactly why it was skipped - so that you do not have to know everything to search in the right direction, if it does not work the way you want it to. When you already know what are you doing, you probably ignore the exact text any way. At least this is how it is for me.

I am not sure I understand why "GIT_SKIP_TESTS" is verbose and loud while "excluded" is sweet :) Maybe I do not spend enough time in the mail lists to have that association of all caps with loud. But in the land of Unix command line tools all caps means "environment variable". This is what I think when I see "GIT_SKIP_TESTS".

P.S. Thanks for reviewing it :)
Eric Sunshine· Mar 30, 2014, 09:41 UTC · re: Ilya Bobyr · lore

Re: [PATCH 3/3] test-lib: '--run' to run only specific tests

On Fri, Mar 28, 2014 at 3:05 AM, Ilya Bobyr <ilya.bobyr@gmail.com> wrote:
Show 82 quoted lines
> On 3/27/2014 8:36 PM, Eric Sunshine wrote:
>> On Thu, Mar 27, 2014 at 6:32 AM, Ilya Bobyr <ilya.bobyr@gmail.com> wrote:
>>> Allow better control of the set of tests that will be executed for a
>>> single test suite.  Mostly useful while debugging or developing as it
>>> allows to focus on a specific test.
>>>
>>> Signed-off-by: Ilya Bobyr <ilya.bobyr@gmail.com>
>>> ---
>>>  No changes from the previous version.
>>>
>>>  t/README         |   65 ++++++++++++++-
>>>  t/t0000-basic.sh |  233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  t/test-lib.sh    |   85 ++++++++++++++++++++
>>>  3 files changed, 379 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/t/README b/t/README
>>> index 6b93aca..c911f89 100644
>>> --- a/t/README
>>> +++ b/t/README
>>> @@ -100,6 +100,10 @@ appropriately before running "make".
>>>         This causes additional long-running tests to be run (where
>>>         available), for more exhaustive testing.
>>>
>>> +-r,--run=<test numbers>::
>> Perhaps <test-selection> or something similar would be closer to the truth.
>
> I think your naming is better.  I will include it in the next version.
>
>>> +       This causes only specific tests to be included or excluded.  See
>> This is phrased somewhat oddly, as if you had already been talking
>> about tests being included or excluded, and that this option merely
>> changes that selection. Perhaps something like:
>>
>>     Run only the subset of tests indicated by <test-selection>.
>
> Will use that sentence as well :)
>
>>> +       section "Skipping Tests" below for "<test numbers>" syntax.
>>> +
>>>  --valgrind=<tool>::
>>>         Execute all Git binaries under valgrind tool <tool> and exit
>>>         with status 126 on errors (just like regular tests, this will
>>> @@ -187,10 +191,63 @@ and either can match the "t[0-9]{4}" part to skip the whole
>>>  test, or t[0-9]{4} followed by ".$number" to say which
>>>  particular test to skip.
>>>
>>> -Note that some tests in the existing test suite rely on previous
>>> -test item, so you cannot arbitrarily disable one and expect the
>>> -remainder of test to check what the test originally was intended
>>> -to check.
>>> +For an individual test suite --run could be used to specify that
>>> +only some tests should be run or that some tests should be
>>> +excluded from a run.
>>> +
>>> +--run argument is a list of patterns with optional prefixes that
>> "The argument for --run is a list...
>
> I think it could be either.  But I am not a native speaker.
> So, I will use your version :)
>
>>> +are matched against test numbers within the current test suite.
>>> +Supported pattern:
>>> +
>>> + - A number matches a test with that number.
>>> +
>>> + - sh metacharacters such as '*', '?' and '[]' match as usual in
>>> +   shell.
>>> +
>>> + - A number prefixed with '<', '<=', '>', or '>=' matches all
>>> +   tests 'before', 'before or including', 'after', or 'after or
>>> +   including' the specified one.
>> I think you want "and" rather than "or": "before and including",
>> "after and including".
>
> I was thinking about an analogy to the corresponding mathematical
> operations here.  In mathematics, '<=' is called "less than or
> equal to"[1].
>
> If you are thinking about test numbers you can say that you
> include a test if it has a number before or equal to the given
> one.  The sentence is "A number prefixed with <= matches all
> tests [with numbers] before or including the specified [number]."

In English, it is idiomatic to say "less than or equal" for '<=', and "greater than or equal" for '>='. "before or including" and "after or including" are not used and sound odd. They also sound rather odd when "or" is replaced with "and". Using the idiomatic forms should be fine.

> Maybe if I change "one" to "number" it would be a bit less
> ambiguous.  Or even include all the omitted words.
Changing "all tests" to "all test numbers" and using the idiomatic forms gives:
    A number prefixed with '<', '<=', '>', or '>=' matches,
    respectively, all test numbers less than, less than or equal,
    greater than, or greater than or equal to the specified one.
which isn't bad, though a bit verbose.
> I would not mind a completely different way to say it, but I am
> not yet sure that if I replace "or" with "and" it would make it
> a lot better.

Since the relational operators are fairly self-explanatory, you could drop the prose explanation, though that might make it too cryptic:

    A number prefixed with '<', '<=', '>', or '>=' matches test
    numbers meeting the specified relation.
Show 39 quoted lines
> [1] https://en.wikipedia.org/wiki/Inequality_%28mathematics%29
>
>>> +Optional prefixes are:
>>> +
>>> + - '+' or no prefix: test(s) matching the pattern are included in
>>> +   the run.
>>> +
>>> + - '-' or '!': test(s) matching the pattern are exluded from the
>>> +   run.
>> I've been playing with --run, and I find that test selection is not
>> especially intuitive. For instance, ">=16 !>24 !20" is easier to
>> reason about when written instead with ranges, such as "16-19 21-24",
>> or perhaps "16-24 !20". Open-ended ranges make sense too: "5-" means
>> tests 5 through the last, and "-5" means tests 1 through 5. (Yes, this
>> conflicts with your use of '-' to mean negation, but you already have
>> the perfectly serviceable '!' as an alias for negation.)
>
> I completely agree that ranges allow one to express certain
> "obvious" things much easier than just inequalities.  I was even
> thinking on a possible syntax.  But then I realized that I do not
> have a real use case for it.
>
> The only use case that I had is described in the cover letter: to
> run several setup tests and then the target test.  For that even
> simple lists were enough and I was using that original version
> with an environment variable.  After a conversation on the list I
> thought that it would be nice to be able to say '<', as it would
> save typing several extra characters for cases like '1 2 3 4 25'.
> While test suits that I've seen so far actually have no more than
> two tests that do the setup.
>
> The next use case that I could come up with was running up to a
> specific test.  I was in a situation were that would have been a
> nice option.  And inequalities allow that.
>
> Once again, I do not have a use case where I would need to run
> tests from 1 to 10, then 14 to 19 and then 100 and up to the end.
>
> Do you have something on your mind where that would be useful?

I don't have a particular use-case. I was just observing how much easier it was to reason about ranges than relational operators, especially when negation is involved. The two modes are not mutually exclusive, though implementing both seems overkill.

Show 5 quoted lines
> As for the syntax, ! is replaced in bash by the last executed
> command.  That happens inside double quotes as well and the
> original command line is not preserved (at lest for me).  So if
> it would be the only option that seemed like a limitation.  It is
> possible to escape it or use single quotes, of course.

It's not unprecedented to use '!' in a command argument. 'sed', 'find', 'awk' (to name a few) all accept '!' for some use or another, and users of those commands are likely already comfortable escaping or using single-quotes.

Tilde (~) has some mnemonic value as an inversion operator.
> I was thinking about a comma as a separator for ranges.

Are you saying "1,5" would be the range 1-5? That likely would be too easily misread as just tests 1 and 5.

Show 28 quoted lines
> As for the open ended ranges - they are the same as inequalities.
>
>>> +If --run starts with '+' or unprefixed pattern the initial set of
>>> +tests to run is empty. If the first pattern starts with '-' or
>>> +'!' all the tests are added to the initial set.  After initial
>>> +set is determined every pattern, test number or range is added or
>>> +excluded from the set one by one, from left to right.
>>> +
>>> +For example, common case is to run several setup tests and then a
>>> +specific test that relies on that setup:
>> Perhaps be a bit more specific:
>>
>>     ...run several setup tests (1, 2, 3) and then a
>>     specific test (21) that relies...
>
> Good idea, though it clutters the sentence a bit.
> Will use it.
>
>>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='1 2 3 21'
>>> +
>>> +or:
>>> +
>>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='<4 21'
>> It might be clearer to say "<=3" rather than "<4".
>
> I thought that < is less typing, so it should be the first one to show.
> Non-strict inequalities were next.
> I will change this example and show '<' and '>' in the next two.

It's not a big deal. It just seemed slightly easer to reason about how "<=3", rather than "<4", was the same as "1 2 3" (since "4" was not mentioned anywhere in the preceding example).

Show 104 quoted lines
>>> +To run only tests up to a specific test one could do this:
>> s/specific test/specific test,/
>>
>> Also perhaps:
>>
>>     ...up to a specific test (21), one...
>
> Fixed.
>
>>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='!>=21'
>>> +
>>> +As noted above test set is build going though patterns left to
>> s/above/above,/
>> s/test set/the test set/
>> s/build/built/
>>
>>     As noted above, the test set is built...
>
> Thanks :)
>
>>> +right, so this:
>>> +
>>> +    $ sh ./t9200-git-cvsexport-commit.sh --run='<5 !3'
>>> +
>>> +will run tests 1, 2, and 4.
>>> +
>>> +Some tests in the existing test suite rely on previous test item,
>>> +so you cannot arbitrarily disable one and expect the remainder of
>>> +test to check what the test originally was intended to check.
>>> +--run is mostly useful when you want to focus on a specific test
>>> +and know what you are doing.  Or when you want to run up to a
>>> +certain test.
>>>
>>>
>>>  Naming Tests
>>> diff --git a/t/test-lib.sh b/t/test-lib.sh
>>> index e035f36..63e481a 100644
>>> --- a/t/test-lib.sh
>>> +++ b/t/test-lib.sh
>>> @@ -191,6 +191,14 @@ do
>>>                 immediate=t; shift ;;
>>>         -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
>>>                 GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;;
>>> +       -r)
>>> +               shift; test "$#" -ne 0 || {
>>> +                       echo 'error: -r requires an argument' >&2;
>>> +                       exit 1;
>>> +               }
>>> +               run_list=$1; shift ;;
>>> +       --run=*)
>>> +               run_list=$(expr "z$1" : 'z[^=]*=\(.*\)'); shift ;;
>>>         -h|--h|--he|--hel|--help)
>>>                 help=t; shift ;;
>>>         -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
>>> @@ -366,6 +374,76 @@ match_pattern_list () {
>>>         return 1
>>>  }
>>>
>>> +match_run_pattern_list () {
>>> +       arg="$1"
>>> +       shift
>>> +       test -z "$*" && return 0
>>> +
>>> +       # If the first patern is negative we include by default.
>> s/patern/pattern/
>
> Fixed.
>
>>> +       include=
>>> +       case "$1" in
>>> +               [-!]*) include=t ;;
>>> +       esac
>>> +
>>> +       for pattern_
>>> +       do
>>> +               orig_pattern=$pattern_
>>> +
>>> +               positive=t
>>> +               case "$pattern_" in
>>> +                       [-!]*)
>>> +                               positive=
>>> +                               pattern_=${pattern_##?}
>>> +                               ;;
>>> +               esac
>>> +
>>> +               # Short cut for "obvious" cases
>>> +               [ "x$include" = "x" -a "x$positive" = "x" ] && continue
>> Although there are a few exceptions in this script, 'test' is
>> generally preferred over '['. Also, -a doesn't have great portability,
>> so && may be better.
>>
>>     test -z "$include" && test -z "$positive" && continue
>
> Did not know that.  Changed.
>
>>> +               [ "x$include" = "xt" -a "x$positive" = "xt" ] && continue
>> Since you're inside double quotes, you can drop the 'x' prefix:
>>
>>     test "$include" = t && test "$positive" = t && continue
>
> Did not know that either %)
> Fixed.
> I saw it was used like that in the part that does argument parsing.  So
> I just used style from there =)

A reason for the "x" trick is to avoid the following problem when $foo expands to nothing:

% foo= % test $foo = bar bash: test: =: unary operator expected % test x$foo = xbar %

Quoting "$foo" achieves the same result.

Also, if the value of $foo starts with a hyphen, then 'test' would see it as a command-line option. Prefixing with 'x' (or any letter) avoids such misunderstanding.

It's also common to quote the expression to avoid the following problem when $foo expands to multiple words:

% foo='foo bar' % test $foo = bar bash: test: too many arguments % text "$foo" = bar %

In your case, the values of $include and $positive are well-controlled (only empty or 't'), so quoting alone is fine.

Show 26 quoted lines
>>> +               pattern_op=
>>> +               case "$pattern_" in
>>> +                       \<=*)
>>> +                               pattern_op='-le'
>>> +                               pattern_=${pattern_##??}
>>> +                               ;;
>>> +                       \<*)
>>> +                               pattern_op='-lt'
>>> +                               pattern_=${pattern_##?}
>>> +                               ;;
>>> +                       \>=*)
>>> +                               pattern_op='-ge'
>>> +                               pattern_=${pattern_##??}
>>> +                               ;;
>>> +                       \>*)
>>> +                               pattern_op='-gt'
>>> +                               pattern_=${pattern_##?}
>>> +                               ;;
>>> +               esac
>>> +
>>> +               if test -n "$pattern_op"
>>> +               then
>>> +                       if expr "z$pattern_" : "z[0-9]*[^0-9]" >/dev/null
>> Inside double quotes: you can drop the 'z' prefix.
>
> Thanks.

It might be safer to keep the 'z' (or whatever) prefix on this one since the pattern is coming from the user, thus not under your control, and may start with a hyphen.

Show 62 quoted lines
>>> +                       then
>>> +                               echo "error: --run: test number contains" \
>>> +                                       "non-digits: '$orig_pattern'" >&2
>>> +                               exit 1
>>> +                       fi
>>> +                       if test $arg $pattern_op $pattern_
>>> +                       then
>>> +                               include=$positive
>>> +                       fi
>>> +               else
>>> +                       case "$arg" in
>>> +                               $pattern_)
>>> +                                       include=$positive
>>> +                       esac
>>> +               fi
>>> +       done
>>> +
>>> +       test -n "$include"
>>> +}
>>> +
>>>  maybe_teardown_verbose () {
>>>         test -z "$verbose_only" && return
>>>         exec 4>/dev/null 3>/dev/null
>>> @@ -470,6 +548,13 @@ test_skip () {
>>>                 fi
>>>                 skipped_reason="missing $missing_prereq${of_prereq}"
>>>         fi
>>> +       if test -z "$to_skip" && test -n "$run_list" &&
>>> +               ! match_run_pattern_list $test_count $run_list
>>> +       then
>>> +               to_skip=t
>>> +               skipped_reason="--run"
>> A few pure bike-shedding comments (to be ignore if desired):
>>
>> I still don't understand the need to distinguish between a test
>> skipped due to --run and and one skipped due to GIT_SKIP_TESTS.
>>
>> The skip-reason "GIT_SKIP_TESTS" (in patch 2/3) still seems
>> unnecessarily verbose and loud.
>>
>> The skip-reason "excluded" (suggested in an earlier review) is short
>> and sweet, and equally applicable to a test skipped either via --run
>> or GIT_SKIP_TESTS.
>
> Well, technically, it already says that the test is skipped.  So
> adding "excluded" is actually a bit redundant.  Part that is in
> the parenthesis explains the reason, at least for the case when
> a test is skipped because a prerequisite is missing.
>
> When you are just starting, I think, it is nice when the tool
> tells you exactly why it was skipped - so that you do not have to
> know everything to search in the right direction, if it does not
> work the way you want it to.  When you already know what are you
> doing, you probably ignore the exact text any way.  At least this
> is how it is for me.
>
> I am not sure I understand why "GIT_SKIP_TESTS" is verbose and
> loud while "excluded" is sweet :)  Maybe I do not spend enough
> time in the mail lists to have that association of all caps with
> loud.  But in the land of Unix command line tools all caps means
> "environment variable".  This is what I think when I see
> "GIT_SKIP_TESTS".

It's loud in this sense: You generally want to ignore test output, with the exception of failures which should loudly draw your attention. Most of the output from the tests is lowercase, but the uppercase (GIT_SKIP_TESTS) -- being different -- draws the attention unnecessarily.

(Having actually just run some tests, I note that skipped tests already are colored differently and the typical skip reason is uppercase anyhow, so the above reasoning is likely unsupportable.)

But, as noted, this is pure bike-shedding. I won't bring it up again.
> P.S. Thanks for reviewing it :)
Junio C Hamano· Mar 31, 2014, 17:09 UTC · re: Eric Sunshine · lore

Re: [PATCH 3/3] test-lib: '--run' to run only specific tests

Eric Sunshine <sunshine@sunshineco.com> writes:
Show 5 quoted lines
> Since the relational operators are fairly self-explanatory, you could
> drop the prose explanation, though that might make it too cryptic:
>
>     A number prefixed with '<', '<=', '>', or '>=' matches test
>     numbers meeting the specified relation.

I would have to say that there is already an established pattern to pick ranges that normal people understand well and it would be silly to invent another more verbose way to express the same thing. You tell your Print Dialog which page to print with e.g. "-4,7,9-12,15-", not ">=4 7 ...".

Would the same notation be insufficient for our purpose? You do not even have to worry about negation that way.

David Tran· Mar 31, 2014, 19:35 UTC · re: Junio C Hamano · lore

Re: [PATCH 3/3] test-lib: '--run' to run only specific tests

Show 12 quoted lines
> Junio C Hamano <gitster <at> pobox.com> writes:
>
> 
> I would have to say that there is already an established pattern to
> pick ranges that normal people understand well and it would be silly
> to invent another more verbose way to express the same thing.  You
> tell your Print Dialog which page to print with e.g. "-4,7,9-12,15-",
> not ">=4 7 ...".  
> 
> Would the same notation be insufficient for our purpose?  You do not
> even have to worry about negation that way.
> 

That will do, especially if the numbers are in ascending order. We won't have the odd cases of including a test and removing it later on. I think we won't need a --neg flag to take the negation of the tests in that range?

← back to recent threads