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.bo...@gmail.com>
---
 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 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

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to