#! /usr/bin/env bash # Copyright (C) Sebastian Pipping # Licensed under the MIT license export PS4='# ' _get_source_dir() { echo "source__${version}" } _get_build_dir() { local libbsd_part= if ${with_libbsd}; then libbsd_part=__libbsd fi local mingw_part= if ${with_mingw}; then mingw_part=__windows fi local char_part= if ${with_unsigned_char}; then char_part=__unsigned_char fi local xml_attr_part= if ${xml_attr_info_enabled}; then xml_attr_part=__attr_info fi echo "build__${version}__unicode_${unicode_enabled}__xml_context_${xml_context}${libbsd_part}${mingw_part}${char_part}${xml_attr_part}" } _get_coverage_dir() { echo "coverage__${version}" } _call_cmake() { local cmake_args=() ${unicode_enabled} \ && cmake_args+=( -DEXPAT_CHAR_TYPE=wchar_t ) ${xml_attr_info_enabled} \ && cmake_args+=( -DEXPAT_ATTR_INFO=ON ) if [[ ${xml_context} -eq 0 ]]; then cmake_args+=( -DEXPAT_CONTEXT_BYTES=OFF ) else cmake_args+=( -DEXPAT_CONTEXT_BYTES=${xml_context} ) fi ${with_libbsd} && cmake_args+=( -DEXPAT_WITH_LIBBSD=ON ) ${with_mingw} && cmake_args+=( -DCMAKE_TOOLCHAIN_FILE="${abs_source_dir}"/cmake/mingw-toolchain.cmake ) ( set -x cmake "${cmake_args[@]}" "$@" . &>> cmake.log ) } _copy_to() { local target_dir="$1" [[ -d "${target_dir}" ]] && return 0 mkdir "${target_dir}" git archive --format=tar "${version}" | ( cd "${target_dir}" && tar x ) } _copy_missing_mingw_libaries() { # These extra files are copied because # * coverage GCC flags make them needed # * With WINEDLLPATH Wine looks for .dll.so in these folders, not .dll local target="$1" local mingw_gcc_dll_dir="$(dirname "$(ls -1 /usr/lib*/gcc/i686-w64-mingw32/*/libgcc_s_sjlj-1.dll | head -n1)")" for dll in libgcc_s_sjlj-1.dll libstdc++-6.dll; do ( set -x ln -s "${mingw_gcc_dll_dir}"/${dll} "${target}"/${dll} ) done local mingw_pthread_dll="$(ls -1 /usr/i686-w64-mingw32/lib*/libwinpthread-1.dll 2>/dev/null | head -n1)" if [[ -n ${mingw_pthread_dll} ]]; then local mingw_pthread_dll_dir="$(dirname "${mingw_pthread_dll}")" for dll in libwinpthread-1.dll; do source="${mingw_pthread_dll_dir}"/${dll} ( set -x ln -s "${source}" "${target}"/${dll} ) done fi for dll in libexpat.dll; do ( set -x ln -s "${abs_build_dir}"/${dll} "${target}"/${dll} ) done } _run() { local source_dir="$1" local build_dir="$2" local abs_source_dir="${PWD}/${source_dir}" local abs_build_dir="${PWD}/${build_dir}" local capture_dir=. local BASE_FLAGS='-pipe -Wall -Wextra -pedantic -Wno-overlength-strings' BASE_FLAGS+=' --coverage --no-inline' ${with_unsigned_char} && BASE_FLAGS="${BASE_FLAGS} -funsigned-char" local CFLAGS="-std=c99 ${BASE_FLAGS}" local CXXFLAGS="-std=c++98 ${BASE_FLAGS}" ( set -e cd "${build_dir}" _call_cmake \ -DCMAKE_C_FLAGS="${CFLAGS}" \ -DCMAKE_CXX_FLAGS="${CXXFLAGS}" ( set -x make &> build.log lcov -c -d "${capture_dir}" -i -o "${coverage_info}-zero" &> run.log ) if ${with_mingw}; then for d in tests xmlwf ; do mkdir -p "${d}" _copy_missing_mingw_libaries "${d}" done fi set -x make CTEST_OUTPUT_ON_FAILURE=1 test run-xmltest lcov -c -d "${capture_dir}" -o "${coverage_info}-test" &>> run.log lcov \ -a "${coverage_info}-zero" \ -a "${coverage_info}-test" \ -o "${coverage_info}-all" \ &>> run.log # Make sure that files overlap in report despite different build folders sed "/SF:/ s,${build_dir}/,${source_dir}/," "${coverage_info}-all" > "${coverage_info}" ) |& sed 's,^, ,' res=${PIPESTATUS[0]} if [[ ${res} -eq 0 ]]; then echo PASSED else echo FAILED >&2 return 1 fi } _merge_coverage_info() { local coverage_dir="$1" shift local build_dirs=( "$@" ) mkdir -p "${coverage_dir}" ( local lcov_merge_args=() for build_dir in "${build_dirs[@]}"; do lcov_merge_args+=( -a "${build_dir}/${coverage_info}" ) done lcov_merge_args+=( -o "${coverage_dir}/${coverage_info}" ) set -x lcov "${lcov_merge_args[@]}" ) &> "${coverage_dir}/merge.log" } _render_html_report() { local coverage_dir="$1" genhtml -o "${coverage_dir}" "${coverage_dir}/${coverage_info}" &> "${coverage_dir}/render.log" } _show_summary() { local coverage_dir="$1" lcov -q -l "${coverage_dir}/${coverage_info}" | grep -v '^\[' } _main() { version="$(git describe --tags)" coverage_info=coverage.info local build_dirs=() local source_dir="$(_get_source_dir)" local coverage_dir="$(_get_coverage_dir)" _copy_to "${source_dir}" _build_case() { local build_dir="$(_get_build_dir)" echo "[${build_dir}]" _copy_to "${build_dir}" # Make sure we don't need to download xmlts.zip over and over again if [[ ${#build_dirs[*]} -gt 0 ]]; then ln -s "$PWD/${build_dirs[0]}/tests/xmlts.zip" "${build_dir}"/tests/ fi _run "${source_dir}" "${build_dir}" build_dirs+=( "${build_dir}" ) } # All combinations: with_unsigned_char=false with_libbsd=false for with_mingw in true false ; do for unicode_enabled in true false ; do if ${unicode_enabled} && ! ${with_mingw} ; then continue fi for xml_attr_info_enabled in true false ; do for xml_context in 0 1024 ; do _build_case done done done done # Single cases: with_libbsd=true _build_case with_unsigned_char=true _build_case echo echo 'Merging coverage files...' _merge_coverage_info "${coverage_dir}" "${build_dirs[@]}" echo 'Rendering HTML report...' _render_html_report "${coverage_dir}" echo "--> ${coverage_dir}/index.html" echo _show_summary "${coverage_dir}" } _main