From c8ffff6428927c22327bfb1ace109417602a5626 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 16 Feb 2024 16:39:07 +0200 Subject: [PATCH] Test coverage with gcov. --- .cirrus.yml | 33 ++++++++++++-------- qbs/imports/VDynamicLib.qbs | 7 ++++- qbs/imports/VLib.qbs | 2 ++ qbs/imports/VTestApp.qbs | 2 ++ qbs/modules/buildconfig/buildconfig.qbs | 3 ++ qbs/modules/coverage/coverage.qbs | 40 +++++++++++++++++++++++++ scripts/sonar-scanner.sh | 29 ++++++++++++++---- 7 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 qbs/modules/coverage/coverage.qbs diff --git a/.cirrus.yml b/.cirrus.yml index da97517ef..3f6d9240b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -62,8 +62,17 @@ linux_qt6_sonar_task_template: &LINUX_QT6_TASK_SONAR_TEMPLATE - qbs setup-qt /usr/bin/qmake6 qt6 - qbs config profiles.qt6.baseProfile ${COMPILER} - qbs config defaultProfile qt6 - - build-wrapper-linux-x86-64 --out-dir bw-output qbs build --no-install -f valentina.qbs -d build --jobs $(nproc) profile:qt6 config:release modules.buildconfig.enableCcache:false modules.cpp.linkerVariant:mold - - sonar-scanner -Dsonar.scm.revision=${CIRRUS_CHANGE_IN_REPO} -Dsonar.links.ci=https://cirrus-ci.com/task/${CIRRUS_TASK_ID} -Dsonar.branch.name=${CIRRUS_BRANCH} + - build-wrapper-linux-x86-64 --out-dir ${CIRRUS_WORKING_DIR}/bw-output qbs build --no-install -f valentina.qbs -d ${CIRRUS_WORKING_DIR}/build --jobs $(nproc) profile:qt6 config:debug modules.buildconfig.enableCcache:false modules.cpp.linkerVariant:mold modules.buildconfig.enableTestCoverage:true + # Execute the tests to generate the coverage statistics + - qbs -p autotest-runner -d build profile:qt6 config:debug + # Run gcov to translate `.gcda` files into `.gcov` readable by humans and SonarCloud + - mkdir ${CIRRUS_WORKING_DIR}/build/coverage-dir + - cd ${CIRRUS_WORKING_DIR}/build/coverage-dir + # --preserve-paths helps us avoid name clash for `.gcov` files corresponding to source files + # with the same name but in different directories. + - find .. -name '*.o' | xargs gcov --preserve-paths + - cd $CIRRUS_WORKING_DIR + - sonar-scanner -Dsonar.scm.revision=${CIRRUS_CHANGE_IN_REPO} -Dsonar.links.ci=https://cirrus-ci.com/task/${CIRRUS_TASK_ID} -Dsonar.branch.name=${CIRRUS_BRANCH} -Dsonar.cfamily.gcov.reportsPath="${CIRRUS_WORKING_DIR}/build/coverage-dir" linux_qt5_qmake_task_template: &LINUX_QT5_QMAKE_TASK_TEMPLATE install_script: @@ -182,16 +191,6 @@ linux_task: container: cpu: 8 memory: 8G # Set to 8GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-container - - name: 'Sonar, latest Clang [Qt6]' - << : *LINUX_QT6_TASK_SONAR_TEMPLATE - env: - QT_SELECT: "qt6" - SONAR_TOKEN: ENCRYPTED[!715ab983713a5035d505d2c601c9bb78a9475b9a04db62cdda9c674affd58ac956e563ce6d38228b48e05c4dbea2f52d!] - container: - cpu: 8 - memory: 10G # Set to 10GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-container - sonar_cache: - folder: "${HOME}/.sonar/cache" - container: image: dismine/gcc-ubuntu:13 env: @@ -254,6 +253,16 @@ linux_task: container: cpu: 4 memory: 16G # Set to 16GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-container + - name: 'Sonar, latest GCC [Qt6]' + << : *LINUX_QT6_TASK_SONAR_TEMPLATE + env: + QT_SELECT: "qt6" + SONAR_TOKEN: ENCRYPTED[!715ab983713a5035d505d2c601c9bb78a9475b9a04db62cdda9c674affd58ac956e563ce6d38228b48e05c4dbea2f52d!] + container: + cpu: 8 + memory: 10G # Set to 10GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-container + sonar_cache: + folder: "${HOME}/.sonar/cache" macos_task_template: &MACOS_TASK_TEMPLATE << : *REGULER_TASK_TEMPLATE diff --git a/qbs/imports/VDynamicLib.qbs b/qbs/imports/VDynamicLib.qbs index a1502f283..405ce581b 100644 --- a/qbs/imports/VDynamicLib.qbs +++ b/qbs/imports/VDynamicLib.qbs @@ -4,7 +4,12 @@ VLib { Depends { name: "windeployqt"; condition: qbs.targetOS.contains("windows") } Depends { name: "i18nconfig"; } - buildconfig.staticBuild: false + buildconfig.staticBuild: { + if (product.buildconfig.enableUnitTests && product.buildconfig.enableTestCoverage) + return true; + else + return false; + } Properties { condition: qbs.targetOS.contains("windows") && Utilities.versionCompare(Qt.core.version, "6.5") < 0 diff --git a/qbs/imports/VLib.qbs b/qbs/imports/VLib.qbs index 851bcb3fa..f1f14ca11 100644 --- a/qbs/imports/VLib.qbs +++ b/qbs/imports/VLib.qbs @@ -4,6 +4,7 @@ Library { Depends { name: "buildconfig" } Depends { name: "bundle"; condition: qbs.targetOS.contains("macos") } Depends { name: "cpp" } + Depends { name: "coverage" } type: buildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary" @@ -63,5 +64,6 @@ Library { Export { Depends { name: "buildconfig" } + Depends { name: "coverage" } } } diff --git a/qbs/imports/VTestApp.qbs b/qbs/imports/VTestApp.qbs index 481eba4e0..d671af116 100644 --- a/qbs/imports/VTestApp.qbs +++ b/qbs/imports/VTestApp.qbs @@ -3,6 +3,8 @@ VApp { install: false condition: buildconfig.enableUnitTests + Depends { name: "coverage" } + Properties { condition: qbs.targetOS.contains("macos") bundle.isBundle: false diff --git a/qbs/modules/buildconfig/buildconfig.qbs b/qbs/modules/buildconfig/buildconfig.qbs index 86e3136a6..6ff90ee29 100644 --- a/qbs/modules/buildconfig/buildconfig.qbs +++ b/qbs/modules/buildconfig/buildconfig.qbs @@ -14,6 +14,9 @@ Module { // Use this property to disable building unit tests. property bool enableUnitTests: true + // Use this property to enable code coverage. + property bool enableTestCoverage: false + // Use this property to disable the use of rpath. This can be used when packaging Valentina for distributions which // do not permit the use of rpath, such as Fedora. property bool enableRPath: true diff --git a/qbs/modules/coverage/coverage.qbs b/qbs/modules/coverage/coverage.qbs new file mode 100644 index 000000000..5b91489b0 --- /dev/null +++ b/qbs/modules/coverage/coverage.qbs @@ -0,0 +1,40 @@ +import qbs.FileInfo +import qbs.Utilities + +Module { + condition: (qbs.debugInformation && qbs.toolchain.contains("gcc") && !qbs.toolchain.contains("clang")) || + qbs.toolchain.contains("clang") + Depends { name: "cpp" } + additionalProductTypes: ["gcno"] + + cpp.driverFlags: { + var flags = []; + + if (product.buildconfig.enableUnitTests && product.buildconfig.enableTestCoverage) { + if (qbs.toolchain.contains("clang")) + flags.push("-fprofile-instr-generate", "-fcoverage-mapping"); + else + flags.push("--coverage"); + } + + return flags; + } + + Rule { // Fake rule for '*.gcno' generation. + condition: qbs.debugInformation && qbs.toolchain.contains("gcc") && !qbs.toolchain.contains("clang") + inputs: ["cpp", "c"] + outputFileTags: ["gcno"] + outputArtifacts: { + return [{ + fileTags: ["gcno"], + filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir), + input.fileName + ".gcno") + }]; + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "generating " + output.fileName; + return [cmd]; + } + } +} diff --git a/scripts/sonar-scanner.sh b/scripts/sonar-scanner.sh index 0b00adbff..be388c537 100755 --- a/scripts/sonar-scanner.sh +++ b/scripts/sonar-scanner.sh @@ -1,6 +1,6 @@ #!/bin/sh # Analyze project with Sonar cloud on Linux. -# Please, run this script from folder /scripts. +# Please, run this script from . set -x @@ -12,7 +12,8 @@ mkdir ../${BUILD_FOLDER} QMAKE_PATH=${HOME}/Qt6.6/6.6.0/gcc_64/bin/qmake PROFILE=qt6Sonar -COMPILER=clang +COMPILER=gcc-12 +GCOV=gcov-12 qbs setup-toolchains /usr/bin/${COMPILER} ${COMPILER} qbs setup-qt ${QMAKE_PATH} ${PROFILE} @@ -28,15 +29,31 @@ build-wrapper-linux-x86-64 \ -f valentina.qbs \ --jobs $(nproc) \ profile:${PROFILE} \ - config:release \ - modules.buildconfig.enableCcache:false + config:debug \ + modules.buildconfig.enableCcache:false \ + modules.buildconfig.enableTestCoverage:true # modules.cpp.linkerVariant:mold +# Run tests to generate coverage information +qbs -p autotest-runner -d ../${BUILD_FOLDER} profile:qt6 config:release + +# Run gcov to translate `.gcda` files into `.gcov` readable by humans and SonarCloud +mkdir ../${BUILD_FOLDER}/coverage-dir + +current_dir=$(pwd) +cd ../${BUILD_FOLDER}/coverage-dir + +# --preserve-paths helps us avoid name clash for `.gcov` files corresponding to source files +# with the same name but in different directories. +find .. -name '*.o' | xargs ${GCOV} --preserve-paths + +cd "$current_dir" + current_branch=$(git rev-parse --abbrev-ref HEAD) current_revision=$(git rev-parse HEAD) sonar-scanner \ - -Dsonar.cfamily.threads=$(nproc) \ -Dsonar.branch.name=$current_branch \ - -Dsonar.scm.revision=$current_revision + -Dsonar.scm.revision=$current_revision \ + -Dsonar.cfamily.gcov.reportsPath="../${BUILD_FOLDER}/coverage-dir"