completion: fix multiple command removals
[gitweb.git] / t / test-lib.sh
index 4e7cb52b57a59b76404f701a542fc58ce06ec685..4e79e140c90ba5aa8cdbe7daeafba45765cecd8e 100644 (file)
@@ -111,6 +111,8 @@ do
                test -z "$HARNESS_ACTIVE" && quiet=t ;;
        --with-dashes)
                with_dashes=t ;;
+       --no-bin-wrappers)
+               no_bin_wrappers=t ;;
        --no-color)
                color= ;;
        --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
@@ -139,6 +141,9 @@ do
                verbose_log=t
                tee=t
                ;;
+       --write-junit-xml)
+               write_junit_xml=t
+               ;;
        --stress)
                stress=t ;;
        --stress=*)
@@ -636,11 +641,35 @@ trap 'exit $?' INT TERM HUP
 # the test_expect_* functions instead.
 
 test_ok_ () {
+       if test -n "$write_junit_xml"
+       then
+               write_junit_xml_testcase "$*"
+       fi
        test_success=$(($test_success + 1))
        say_color "" "ok $test_count - $@"
 }
 
 test_failure_ () {
+       if test -n "$write_junit_xml"
+       then
+               junit_insert="<failure message=\"not ok $test_count -"
+               junit_insert="$junit_insert $(xml_attr_encode "$1")\">"
+               junit_insert="$junit_insert $(xml_attr_encode \
+                       "$(if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
+                          then
+                               test-tool path-utils skip-n-bytes \
+                                       "$GIT_TEST_TEE_OUTPUT_FILE" $GIT_TEST_TEE_OFFSET
+                          else
+                               printf '%s\n' "$@" | sed 1d
+                          fi)")"
+               junit_insert="$junit_insert</failure>"
+               if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
+               then
+                       junit_insert="$junit_insert<system-err>$(xml_attr_encode \
+                               "$(cat "$GIT_TEST_TEE_OUTPUT_FILE")")</system-err>"
+               fi
+               write_junit_xml_testcase "$1" "      $junit_insert"
+       fi
        test_failure=$(($test_failure + 1))
        say_color error "not ok $test_count - $1"
        shift
@@ -649,11 +678,19 @@ test_failure_ () {
 }
 
 test_known_broken_ok_ () {
+       if test -n "$write_junit_xml"
+       then
+               write_junit_xml_testcase "$* (breakage fixed)"
+       fi
        test_fixed=$(($test_fixed+1))
        say_color error "ok $test_count - $@ # TODO known breakage vanished"
 }
 
 test_known_broken_failure_ () {
+       if test -n "$write_junit_xml"
+       then
+               write_junit_xml_testcase "$* (known breakage)"
+       fi
        test_broken=$(($test_broken+1))
        say_color warn "not ok $test_count - $@ # TODO known breakage"
 }
@@ -911,12 +948,21 @@ test_start_ () {
        test_count=$(($test_count+1))
        maybe_setup_verbose
        maybe_setup_valgrind
+       if test -n "$write_junit_xml"
+       then
+               junit_start=$(test-tool date getnanos)
+       fi
 }
 
 test_finish_ () {
        echo >&3 ""
        maybe_teardown_valgrind
        maybe_teardown_verbose
+       if test -n "$GIT_TEST_TEE_OFFSET"
+       then
+               GIT_TEST_TEE_OFFSET=$(test-tool path-utils file-size \
+                       "$GIT_TEST_TEE_OUTPUT_FILE")
+       fi
 }
 
 test_skip () {
@@ -948,6 +994,13 @@ test_skip () {
 
        case "$to_skip" in
        t)
+               if test -n "$write_junit_xml"
+               then
+                       message="$(xml_attr_encode "$skipped_reason")"
+                       write_junit_xml_testcase "$1" \
+                               "      <skipped message=\"$message\" />"
+               fi
+
                say_color skip >&3 "skipping test: $@"
                say_color skip "ok $test_count # skip $1 ($skipped_reason)"
                : true
@@ -963,9 +1016,51 @@ test_at_end_hook_ () {
        :
 }
 
+write_junit_xml () {
+       case "$1" in
+       --truncate)
+               >"$junit_xml_path"
+               junit_have_testcase=
+               shift
+               ;;
+       esac
+       printf '%s\n' "$@" >>"$junit_xml_path"
+}
+
+xml_attr_encode () {
+       printf '%s\n' "$@" | test-tool xml-encode
+}
+
+write_junit_xml_testcase () {
+       junit_attrs="name=\"$(xml_attr_encode "$this_test.$test_count $1")\""
+       shift
+       junit_attrs="$junit_attrs classname=\"$this_test\""
+       junit_attrs="$junit_attrs time=\"$(test-tool \
+               date getnanos $junit_start)\""
+       write_junit_xml "$(printf '%s\n' \
+               "    <testcase $junit_attrs>" "$@" "    </testcase>")"
+       junit_have_testcase=t
+}
+
 test_done () {
        GIT_EXIT_OK=t
 
+       if test -n "$write_junit_xml" && test -n "$junit_xml_path"
+       then
+               test -n "$junit_have_testcase" || {
+                       junit_start=$(test-tool date getnanos)
+                       write_junit_xml_testcase "all tests skipped"
+               }
+
+               # adjust the overall time
+               junit_time=$(test-tool date getnanos $junit_suite_start)
+               sed "s/<testsuite [^>]*/& time=\"$junit_time\"/" \
+                       <"$junit_xml_path" >"$junit_xml_path.new"
+               mv "$junit_xml_path.new" "$junit_xml_path"
+
+               write_junit_xml "  </testsuite>" "</testsuites>"
+       fi
+
        if test -z "$HARNESS_ACTIVE"
        then
                mkdir -p "$TEST_RESULTS_DIR"
@@ -1025,7 +1120,11 @@ test_done () {
                        error "Tests passed but trash directory already removed before test cleanup; aborting"
 
                        cd "$TRASH_DIRECTORY/.." &&
-                       rm -fr "$TRASH_DIRECTORY" ||
+                       rm -fr "$TRASH_DIRECTORY" || {
+                               # try again in a bit
+                               sleep 5;
+                               rm -fr "$TRASH_DIRECTORY"
+                       } ||
                        error "Tests passed but test cleanup failed; aborting"
                fi
                test_at_end_hook_
@@ -1131,20 +1230,25 @@ then
        PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR/t/helper:$PATH
        GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
 else # normal case, use ../bin-wrappers only unless $with_dashes:
-       git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
-       if ! test -x "$git_bin_dir/git"
+       if test -n "$no_bin_wrappers"
        then
-               if test -z "$with_dashes"
+               with_dashes=t
+       else
+               git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
+               if ! test -x "$git_bin_dir/git"
                then
-                       say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
+                       if test -z "$with_dashes"
+                       then
+                               say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
+                       fi
+                       with_dashes=t
                fi
-               with_dashes=t
+               PATH="$git_bin_dir:$PATH"
        fi
-       PATH="$git_bin_dir:$PATH"
        GIT_EXEC_PATH=$GIT_BUILD_DIR
        if test -n "$with_dashes"
        then
-               PATH="$GIT_BUILD_DIR:$PATH"
+               PATH="$GIT_BUILD_DIR:$GIT_BUILD_DIR/t/helper:$PATH"
        fi
 fi
 GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
@@ -1168,7 +1272,7 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
        error "You haven't built things yet, have you?"
 }
 
-if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool
+if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool$X
 then
        echo >&2 'You need to build test-tool:'
        echo >&2 'Run "make t/helper/test-tool" in the source (toplevel) directory'
@@ -1192,6 +1296,7 @@ then
 else
        mkdir -p "$TRASH_DIRECTORY"
 fi
+
 # Use -P to resolve symlinks in our working directory so that the cwd
 # in subprocesses like git equals our $PWD (for pathname comparisons).
 cd -P "$TRASH_DIRECTORY" || exit 1
@@ -1205,7 +1310,28 @@ then
        test_done
 fi
 
-# Provide an implementation of the 'yes' utility
+if test -n "$write_junit_xml"
+then
+       junit_xml_dir="$TEST_OUTPUT_DIRECTORY/out"
+       mkdir -p "$junit_xml_dir"
+       junit_xml_base=${0##*/}
+       junit_xml_path="$junit_xml_dir/TEST-${junit_xml_base%.sh}.xml"
+       junit_attrs="name=\"${junit_xml_base%.sh}\""
+       junit_attrs="$junit_attrs timestamp=\"$(TZ=UTC \
+               date +%Y-%m-%dT%H:%M:%S)\""
+       write_junit_xml --truncate "<testsuites>" "  <testsuite $junit_attrs>"
+       junit_suite_start=$(test-tool date getnanos)
+       if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
+       then
+               GIT_TEST_TEE_OFFSET=0
+       fi
+fi
+
+# Provide an implementation of the 'yes' utility; the upper bound
+# limit is there to help Windows that cannot stop this loop from
+# wasting cycles when the downstream stops reading, so do not be
+# tempted to turn it into an infinite loop. cf. 6129c930 ("test-lib:
+# limit the output of the yes utility", 2016-02-02)
 yes () {
        if test $# = 0
        then