From 3b0db29d756a535ad7bae3edf79a0f1364fe36b3 Mon Sep 17 00:00:00 2001 From: Tadej Novak Date: Tue, 21 Nov 2023 14:34:16 +0100 Subject: [PATCH] Add code coverage (#68) --- .github/workflows/Linux.yml | 43 ++++++++++++++++++- CMakeLists.txt | 24 ++++++++++- cmake/coverage.cmake | 65 +++++++++++++++++++++++++++++ codecov.yml | 13 ++++++ src/core/CMakeLists.txt | 1 + src/location/CMakeLists.txt | 1 + src/location/plugins/CMakeLists.txt | 2 + src/widgets/CMakeLists.txt | 1 + 8 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 cmake/coverage.cmake create mode 100644 codecov.yml diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index a13670d..5560e57 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -58,6 +58,7 @@ jobs: qt_version: 6.6.0 qt_modules: qtlocation qtpositioning compiler: gcc-13 + gcov: gcov-13 steps: - name: Checkout @@ -89,6 +90,29 @@ jobs: with: compiler: ${{ matrix.compiler }} + - name: Install lcov + if: matrix.compiler != 'default' + run: | + sudo apt-get install \ + libcapture-tiny-perl \ + libdatetime-perl \ + libdatetime-format-dateparse-perl \ + libgd-perl \ + libgd3 \ + libjbig0 \ + libjpeg-turbo8 \ + libjpeg8 \ + libjson-perl \ + libperlio-gzip-perl \ + libtiff5 \ + libwebp7 + + git clone https://github.com/linux-test-project/lcov.git -b v2.0 + pushd lcov + sudo make -j$(nproc) install + popd + rm -rf lcov + - name: Download Qt uses: jurplel/install-qt-action@v3 with: @@ -121,6 +145,7 @@ jobs: env: CC: ${{ steps.install_compiler.outputs.cc }} CXX: ${{ steps.install_compiler.outputs.cxx }} + GCOV: ${{ matrix.gcov }} run: | mkdir build && cd build qt-cmake ../source/ \ @@ -128,7 +153,9 @@ jobs: -DCMAKE_BUILD_TYPE="RelWithDebInfo" \ -DCMAKE_C_COMPILER_LAUNCHER="ccache" \ -DCMAKE_CXX_COMPILER_LAUNCHER="ccache" \ - -DCMAKE_INSTALL_PREFIX="../install" + -DCMAKE_INSTALL_PREFIX="../install" \ + -DMLN_QT_WITH_COVERAGE=ON \ + -DGCOV_PATH="$(which ${GCOV})" ninja ninja install @@ -139,6 +166,13 @@ jobs: run: ctest --output-on-failure working-directory: build + - name: Run code coverage + if: matrix.qt_series == 6 && matrix.compiler != 'default' + uses: coactions/setup-xvfb@v1 + with: + run: ninja coverage + working-directory: build + - name: Build QtQuick Example (Qt6) if: matrix.qt_series == 6 && matrix.compiler != 'default' run: | @@ -179,6 +213,13 @@ jobs: name: QMapLibre_Linux_${{ matrix.qt_version }} path: QMapLibre_Linux.tar.bz2 + - name: Upload coverage reports to Codecov + if: matrix.qt_series == 6 && matrix.compiler != 'default' + uses: codecov/codecov-action@v3 + with: + files: build/coverage.info + verbose: true + release: name: Release QMapLibre if: github.ref_type == 'tag' diff --git a/CMakeLists.txt b/CMakeLists.txt index c9f5d1f..4655cc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,8 +31,9 @@ set(MLN_QT_QML_PLUGIN declarative_locationplugin_maplibre) include(cmake/helpers.cmake) # Options -set(MLN_QT_WITH_LOCATION ON CACHE BOOL "Build QMapLibreLocation") -set(MLN_QT_WITH_WIDGETS ON CACHE BOOL "Build QMapLibreWidgets") +option(MLN_QT_WITH_LOCATION "Build QMapLibreLocation" ON) +option(MLN_QT_WITH_WIDGETS "Build QMapLibreWidgets" ON) +option(MLN_QT_WITH_COVERAGE "Build QMapLibre with code coverage collection" OFF) # Find Qt find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) @@ -73,9 +74,28 @@ elseif(MSVC OR CMAKE_SYSTEM_NAME STREQUAL "Windows") set(CMAKE_DEBUG_POSTFIX "d") endif() +# Common configuration +add_library(CompilerOptions INTERFACE) +target_compile_options( + CompilerOptions + INTERFACE + $<$:--coverage> +) +target_link_libraries( + CompilerOptions + INTERFACE + $<$:--coverage> +) + # Enable testing enable_testing() # Add subdirectories add_subdirectory(src) add_subdirectory(test) + +# Coverage +if(MLN_QT_WITH_COVERAGE) + include(cmake/coverage.cmake) + setup_target_for_coverage(coverage ${CMAKE_CTEST_COMMAND} "${CMAKE_BINARY_DIR}/coverage" "-V") +endif() diff --git a/cmake/coverage.cmake b/cmake/coverage.cmake new file mode 100644 index 0000000..8325dd0 --- /dev/null +++ b/cmake/coverage.cmake @@ -0,0 +1,65 @@ +find_program(GCOV_PATH gcov) +find_program(LCOV_PATH lcov) +find_program(GENHTML_PATH genhtml) + +# Param _targetname The name of new the custom make target +# Param _testrunner The name of the target which runs the tests. +# MUST return ZERO always, even on errors. +# If not, no coverage report will be created! +# Param _outputname lcov output is generated as _outputname.info +# HTML report is generated in _outputname/index.html +# Optional fourth parameter is passed as arguments to _testrunner +# Pass them in list form, e.g.: "-j;2" for -j 2 +function(setup_target_for_coverage _targetname _testrunner _outputname) + if(NOT GCOV_PATH) + message(FATAL_ERROR "gcov not found! Aborting...") + endif() + + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Aborting...") + endif() + + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() + + # Setup target + add_custom_target( + ${_targetname} + # Cleanup and prepare lcov + ${LCOV_PATH} --directory src --zerocounters + COMMAND + ${LCOV_PATH} --directory src --capture --initial + --ignore-errors inconsistent,inconsistent + --output-file ${_outputname}.info.initial + --gcov-tool ${GCOV_PATH} + # Run tests + COMMAND ${_testrunner} ${ARGV3} + # Capturing lcov counters and generating report + COMMAND + ${LCOV_PATH} --directory src --capture + --ignore-errors inconsistent,inconsistent + --output-file ${_outputname}.info.full + --gcov-tool ${GCOV_PATH} + COMMAND + ${LCOV_PATH} --remove ${_outputname}.info.full + '/usr/*' '*/Qt/*' + '*/examples/*' '*/vendor/*' + '${CMAKE_BINARY_DIR}*' + --ignore-errors inconsistent,inconsistent,unused + --output-file ${_outputname}.info + --gcov-tool ${GCOV_PATH} + COMMAND + ${GENHTML_PATH} -t "${PROJECT_NAME}" -o ${_outputname} + ${_outputname}.info -p "${CMAKE_SOURCE_DIR}" + --ignore-errors inconsistent,inconsistent + COMMAND + ${LCOV_PATH} --summary ${_outputname}.info --ignore-errors inconsistent,inconsistent > ${_outputname}.summary + COMMAND + ${CMAKE_COMMAND} -E remove ${_outputname}.info.initial ${_outputname}.info.full + WORKING_DIRECTORY + ${CMAKE_BINARY_DIR} + COMMENT + "Resetting code coverage counters to zero. \nProcessing code coverage counters and generating report." + ) +endfunction() diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..ab8ece3 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,13 @@ +ignore: + - "examples/" + - "test/" + - "vendor/" + +coverage: + status: + project: + default: + threshold: 1% + +fixes: + - "source/::" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 538accb..c030639 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -104,6 +104,7 @@ target_link_libraries( $ $ $ + $ ) if (NOT MLN_QT_WITH_INTERNAL_SQLITE) target_link_libraries( diff --git a/src/location/CMakeLists.txt b/src/location/CMakeLists.txt index 7aac144..28409e5 100644 --- a/src/location/CMakeLists.txt +++ b/src/location/CMakeLists.txt @@ -57,6 +57,7 @@ target_link_libraries( Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::LocationPrivate $ + $ ) # Apple specifics diff --git a/src/location/plugins/CMakeLists.txt b/src/location/plugins/CMakeLists.txt index 2c20bab..650ca4c 100644 --- a/src/location/plugins/CMakeLists.txt +++ b/src/location/plugins/CMakeLists.txt @@ -36,6 +36,7 @@ target_link_libraries( Qt${QT_VERSION_MAJOR}::Location Qt${QT_VERSION_MAJOR}::LocationPrivate $ + $ ) # QtLocation plugin installation @@ -92,6 +93,7 @@ target_link_libraries( Location Qt${QT_VERSION_MAJOR}::LocationPrivate $ + $ ) # QtLocation QML extension plugin installation diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index bd65f87..17e8f44 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -71,6 +71,7 @@ target_link_libraries( Core PRIVATE $ + $ ) if (Qt6_FOUND) target_link_libraries(