git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v5 1/5] test-lib: Adjust output to be valid TAP format

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
Jun 24, 2010, 21:52 UTC
Message-ID
<1277416332-12072-1-git-send-email-avarab@gmail.com>
In-Reply-To
<AANLkTinVp6kivNzbdUj-7EXjKrolBqvtsNROo-dCSydn@mail.gmail.com>

TAP, the Test Anything Protocol, is a simple text-based interface between testing modules in a test harness. test-lib.sh's output was already very close to being valid TAP. This change brings it all the way there. Before:

    $ ./t0005-signals.sh
    *   ok 1: sigchain works
    * passed all 1 test(s)
And after:
    $ ./t0005-signals.sh
    ok 1 - sigchain works
    # passed all 1 test(s)
    1..1

The advantage of using TAP is that any program that reads the format (a "test harness") can run the tests. The most popular of these is the prove(1) utility that comes with Perl. It can run tests in parallel, display colored output, format the output to console, file, HTML etc., and much more. An example:

    $ prove ./t0005-signals.sh
    ./t0005-signals.sh .. ok
    All tests successful.
    Files=1, Tests=1,  0 wallclock secs ( 0.03 usr  0.00 sys +  0.01 cusr  0.02 csys =  0.06 CPU)
    Result: PASS

prove(1) gives you human readable output without being too verbose. Running the test suite in parallel with `make test -j15` produces a flood of text. Running them with `prove -j 15 ./t[0-9]*.sh` makes it easy to follow what's going on.

All this patch does is re-arrange the output a bit so that it conforms with the TAP spec, everything that the test suite did before continues to work. That includes aggregating results in t/test-results/, the --verbose, --debug and other options for tests, and the test color output.

TAP harnesses ignore everything that they don't know about, so running the tests with --verbose works:

    $ prove ./t0005-signals.sh :: --verbose --debug
    ./t0005-signals.sh .. Terminated
    ./t0005-signals.sh .. ok
    All tests successful.
    Files=1, Tests=1,  0 wallclock secs ( 0.02 usr  0.01 sys +  0.01 cusr  0.01 csys =  0.05 CPU)
    Result: PASS

Just supply the -v option to prove itself to get all the verbose output that it suppresses:

    $ prove -v ./t0005-signals.sh :: --verbose --debug
    ./t0005-signals.sh ..
    Initialized empty Git repository in /home/avar/g/git/t/trash directory.t0005-signals/.git/
    expecting success:
            test-sigchain >actual
            case "$?" in
            143) true ;; # POSIX w/ SIGTERM=15
              3) true ;; # Windows
              *) false ;;
            esac &&
            test_cmp expect actual
    Terminated
    ok 1 - sigchain works
    # passed all 1 test(s)
    1..1
    ok
    All tests successful.
    Files=1, Tests=1,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.01 cusr  0.01 csys =  0.04 CPU)
    Result: PASS

As a further example, consider this test script that uses a lot of test-lib.sh features by Jakub Narebski:

    #!/bin/sh
    test_description='this is a sample test.
    This test is here to see various test outputs.'
    . ./test-lib.sh
    say 'diagnostic message'
    test_expect_success 'true  test' 'true'
    test_expect_success 'false test' 'false'
    test_expect_failure 'true  test (todo)' 'true'
    test_expect_failure 'false test (todo)' 'false'
    test_debug 'echo "debug message"'
    test_done
The output of that was previously:
    * diagnostic message                      # yellow
    *   ok 1: true  test
    * FAIL 2: false test                      # bold red
            false
    *   FIXED 3: true  test (todo)
    *   still broken 4: false test (todo)     # bold green
    * fixed 1 known breakage(s)               # green
    * still have 1 known breakage(s)          # bold red
    * failed 1 among remaining 3 test(s)      # bold red
But is now:
    diagnostic message                                    # yellow
    ok 1 - true  test
    not ok - 2 false test                                 # bold red
    #       false
    ok 3 - true  test (todo) # TODO known breakage
    not ok 4 - false test (todo) # TODO known breakage    # bold green
    # fixed 1 known breakage(s)                           # green
    # still have 1 known breakage(s)                      # bold red
    # failed 1 among remaining 3 test(s)                  # bold red
    1..4

All the coloring is preserved when the test is run manually. Under prove(1) the test performs as expected, even with --debug and --verbose options:

    $ prove ./example.sh :: --debug --verbose
    ./example.sh .. Dubious, test returned 1 (wstat 256, 0x100)
    Failed 1/4 subtests
            (1 TODO test unexpectedly succeeded)
    Test Summary Report
    -------------------
    ./example.sh (Wstat: 256 Tests: 4 Failed: 1)
      Failed test:  2
      TODO passed:   3
      Non-zero exit status: 1
    Files=1, Tests=4,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.00 cusr  0.01 csys =  0.03 CPU)
    Result: FAIL

The TAP harness itself doesn't get confused by the color output, they aren't used by test-lib.sh stdout isn't open to a terminal (test -t 1).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
> To all of the above: I could be more verbose in the commit message in
> needed.

Here's v5 of this patch which does that. I used the example Jakub provided and explained how it works with regards to colors and interaction with a TAP harness.

 t/README      |   55 +++++++++++++++++++++++++++++++++++++++----------------
 t/test-lib.sh |   30 ++++++++++++++++++------------
 2 files changed, 57 insertions(+), 28 deletions(-)
diff --git a/t/README b/t/README
index 0e4e8d8..aa4ed28 100644
--- a/t/README
+++ b/t/README
@@ -18,25 +18,48 @@ The easiest way to run tests is to say "make".  This runs all
 the tests.
 
     *** t0000-basic.sh ***
-    *   ok 1: .git/objects should be empty after git-init in an empty repo.
-    *   ok 2: .git/objects should have 256 subdirectories.
-    *   ok 3: git-update-index without --add should fail adding.
+    ok 1 - .git/objects should be empty after git init in an empty repo.
+    ok 2 - .git/objects should have 3 subdirectories.
+    ok 3 - success is reported like this
     ...
-    *   ok 23: no diff after checkout and git-update-index --refresh.
-    * passed all 23 test(s)
-    *** t0100-environment-names.sh ***
-    *   ok 1: using old names should issue warnings.
-    *   ok 2: using old names but having new names should not issue warnings.
-    ...
-
-Or you can run each test individually from command line, like
-this:
-
-    $ sh ./t3001-ls-files-killed.sh
-    *   ok 1: git-update-index --add to add various paths.
-    *   ok 2: git-ls-files -k to show killed files.
-    *   ok 3: validate git-ls-files -k output.
-    * passed all 3 test(s)
+    ok 43 - very long name in the index handled sanely
+    # fixed 1 known breakage(s)
+    # still have 1 known breakage(s)
+    # passed all remaining 42 test(s)
+    1..43
+    *** t0001-init.sh ***
+    ok 1 - plain
+    ok 2 - plain with GIT_WORK_TREE
+    ok 3 - plain bare
+
+Since the tests all output TAP (see http://testanything.org) they can
+be run with any TAP harness. Here's an example of paralell testing
+powered by a recent version of prove(1):
+
+    $ prove --timer --jobs 15 ./t[0-9]*.sh
+    [19:17:33] ./t0005-signals.sh ................................... ok       36 ms
+    [19:17:33] ./t0022-crlf-rename.sh ............................... ok       69 ms
+    [19:17:33] ./t0024-crlf-archive.sh .............................. ok      154 ms
+    [19:17:33] ./t0004-unwritable.sh ................................ ok      289 ms
+    [19:17:33] ./t0002-gitfile.sh ................................... ok      480 ms
+    ===(     102;0  25/?  6/?  5/?  16/?  1/?  4/?  2/?  1/?  3/?  1... )===
+
+prove and other harnesses come with a lot of useful options. The
+--state option in particular is very useful:
+
+    # Repeat until no more failures
+    $ prove -j 15 --state=failed,save ./t[0-9]*.sh
+
+You can also run each test individually from command line, like this:
+
+    $ sh ./t3010-ls-files-killed-modified.sh
+    ok 1 - git update-index --add to add various paths.
+    ok 2 - git ls-files -k to show killed files.
+    ok 3 - validate git ls-files -k output.
+    ok 4 - git ls-files -m to show modified files.
+    ok 5 - validate git ls-files -m output.
+    # passed all 5 test(s)
+    1..5
 
 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
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 367f053..e97645c 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -160,7 +160,7 @@ if test -n "$color"; then
 			*) test -n "$quiet" && return;;
 		esac
 		shift
-		printf "* %s" "$*"
+		printf "%s" "$*"
 		tput sgr0
 		echo
 		)
@@ -169,7 +169,7 @@ else
 	say_color() {
 		test -z "$1" && test -n "$quiet" && return
 		shift
-		echo "* $*"
+		echo "$*"
 	}
 fi
 
@@ -339,25 +339,25 @@ test_have_prereq () {
 
 test_ok_ () {
 	test_success=$(($test_success + 1))
-	say_color "" "  ok $test_count: $@"
+	say_color "" "ok $test_count - $@"
 }
 
 test_failure_ () {
 	test_failure=$(($test_failure + 1))
-	say_color error "FAIL $test_count: $1"
+	say_color error "not ok - $test_count $1"
 	shift
-	echo "$@" | sed -e 's/^/	/'
+	echo "$@" | sed -e 's/^/#	/'
 	test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
 }
 
 test_known_broken_ok_ () {
 	test_fixed=$(($test_fixed+1))
-	say_color "" "  FIXED $test_count: $@"
+	say_color "" "ok $test_count - $@ # TODO known breakage"
 }
 
 test_known_broken_failure_ () {
 	test_broken=$(($test_broken+1))
-	say_color skip "  still broken $test_count: $@"
+	say_color skip "not ok $test_count - $@ # TODO known breakage"
 }
 
 test_debug () {
@@ -390,7 +390,7 @@ test_skip () {
 	case "$to_skip" in
 	t)
 		say_color skip >&3 "skipping test: $@"
-		say_color skip "skip $test_count: $1"
+		say_color skip "ok $test_count: # skip $1"
 		: true
 		;;
 	*)
@@ -620,18 +620,22 @@ test_done () {
 
 	if test "$test_fixed" != 0
 	then
-		say_color pass "fixed $test_fixed known breakage(s)"
+		say_color pass "# fixed $test_fixed known breakage(s)"
 	fi
 	if test "$test_broken" != 0
 	then
-		say_color error "still have $test_broken known breakage(s)"
+		say_color error "# still have $test_broken known breakage(s)"
 		msg="remaining $(($test_count-$test_broken)) test(s)"
 	else
 		msg="$test_count test(s)"
 	fi
 	case "$test_failure" in
 	0)
-		say_color pass "passed all $msg"
+		# Maybe print SKIP message
+		[ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
+
+		say_color pass "# passed all $msg"
+		say "1..$test_count$skip_all"
 
 		test -d "$remove_trash" &&
 		cd "$(dirname "$remove_trash")" &&
@@ -640,7 +644,9 @@ test_done () {
 		exit 0 ;;
 
 	*)
-		say_color error "failed $test_failure among $msg"
+		say_color error "# failed $test_failure among $msg"
+		say "1..$test_count"
+
 		exit 1 ;;
 
 	esac
-- 
1.7.1.251.g92a7
Previous: Ævar Arnfjörð BjarmasonNext: Junio C Hamano
Message 5 of 16 in “TAP support for Git”
  1. 0/5 TAP support for GitÆvar Arnfjörð Bjarmason, Jun 24, 2010
  2. 1/5 test-lib: Adjust output to be valid TAP formatÆvar Arnfjörð Bjarmason, Jun 24, 2010
  3. Jakub NarebskiJun 24, 2010
  4. Ævar Arnfjörð BjarmasonJun 24, 2010
  5. 1/5 test-lib: Adjust output to be valid TAP formatÆvar Arnfjörð Bjarmason, Jun 24, 2010
  6. Junio C HamanoJun 25, 2010
  7. Ævar Arnfjörð BjarmasonJun 25, 2010
  8. Junio C HamanoJun 25, 2010
  9. Ævar Arnfjörð BjarmasonJun 25, 2010
  10. 2/5 test-lib: Make the test_external_* functions TAP-awareÆvar Arnfjörð Bjarmason, Jun 24, 2010
  11. 3/5 test-lib: output a newline before "ok" under a TAP harnessÆvar Arnfjörð Bjarmason, Jun 24, 2010
  12. 4/5 tests: Skip tests in a way that makes sense under TAPÆvar Arnfjörð Bjarmason, Jun 24, 2010
  13. 5/5 tests: Say "pass" rather than "ok" on empty lines for TAPÆvar Arnfjörð Bjarmason, Jun 24, 2010
  14. t9700: Use Test::More->builder, not $Test::Builder::TestÆvar Arnfjörð Bjarmason, Jun 26, 2010
  15. t9700: Use Test::More->builder, not $Test::Builder::TestÆvar Arnfjörð Bjarmason, Jun 26, 2010
  16. Junio C HamanoJun 27, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.