# Library of functions to format test scripts' output in JUnit XML # format, to support Git's test suite result to be presented in an # easily digestible way on Azure Pipelines. # # Copyright (c) 2022 Johannes Schindelin # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . # # The idea is for `test-lib.sh` to source this file when the user asks # for JUnit XML; these functions will then override (empty) functions # that are are called at the appropriate times during the test runs. start_test_output () { junit_xml_dir="$TEST_OUTPUT_DIRECTORY/out" mkdir -p "$junit_xml_dir" junit_xml_base=${1##*/} 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 "" " " junit_suite_start=$(test-tool date getnanos) if test -n "$GIT_TEST_TEE_OUTPUT_FILE" then GIT_TEST_TEE_OFFSET=0 fi } start_test_case_output () { junit_start=$(test-tool date getnanos) } finalize_test_case_output () { test_case_result=$1 shift case "$test_case_result" in ok) set -- "$*" ;; failure) junit_insert="" 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" if test -n "$GIT_TEST_TEE_OUTPUT_FILE" then junit_insert="$junit_insert$(xml_attr_encode \ "$(cat "$GIT_TEST_TEE_OUTPUT_FILE")")" fi set -- "$1" " $junit_insert" ;; fixed) set -- "$* (breakage fixed)" ;; broken) set -- "$* (known breakage)" ;; skip) message="$(xml_attr_encode --no-lf "$skipped_reason")" set -- "$1" " " ;; esac junit_attrs="name=\"$(xml_attr_encode --no-lf "$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' \ " " "$@" " ")" junit_have_testcase=t } finalize_test_output () { if 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 -e "s/\(]*/& time=\"$junit_time\"/" \ -e '/^ *<\/testsuite/d' \ <"$junit_xml_path" >"$junit_xml_path.new" mv "$junit_xml_path.new" "$junit_xml_path" write_junit_xml " " "" write_junit_xml= fi } write_junit_xml () { case "$1" in --truncate) >"$junit_xml_path" junit_have_testcase= shift ;; esac printf '%s\n' "$@" >>"$junit_xml_path" } xml_attr_encode () { if test "x$1" = "x--no-lf" then shift printf '%s' "$*" | test-tool xml-encode else printf '%s\n' "$@" | test-tool xml-encode fi }