From 803b626574fe9228f6459337ea294e39c8286252 Mon Sep 17 00:00:00 2001 From: Gonzalo Diaz Date: Tue, 13 Oct 2026 01:26:16 -0300 Subject: [PATCH 1/2] [CONFIG] [REFACTOR] Coverage: lcov replaced by gcovr --- .github/workflows/cpp-coverage.yml | 5 ++--- .github/workflows/make-coverage-html.yml | 5 ++--- .github/workflows/sonarcloud.yml | 13 +++---------- Makefile | 18 +++++++++--------- 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.github/workflows/cpp-coverage.yml b/.github/workflows/cpp-coverage.yml index 16ad002..acaacc7 100644 --- a/.github/workflows/cpp-coverage.yml +++ b/.github/workflows/cpp-coverage.yml @@ -28,8 +28,7 @@ jobs: - name: Install Tools run: | - sudo apt-get update - sudo apt-get install lcov + pip install --only-binary :all: gcovr==8.6 - name: Check Tools run: | @@ -42,7 +41,7 @@ jobs: echo "-----------" vcpkg --version echo "-----------" - lcov --version + gcovr --version - name: Install dependencies run: | diff --git a/.github/workflows/make-coverage-html.yml b/.github/workflows/make-coverage-html.yml index 34b23ba..c1b7635 100644 --- a/.github/workflows/make-coverage-html.yml +++ b/.github/workflows/make-coverage-html.yml @@ -30,8 +30,7 @@ jobs: - name: Install Tools run: | - sudo apt-get update - sudo apt-get install lcov + pip install --only-binary :all: gcovr==8.6 - name: Check Tools run: | @@ -42,7 +41,7 @@ jobs: echo "-----------" vcpkg --version echo "-----------" - lcov --version + gcovr --version echo "-----------" - name: Run coverage HTML target diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 954ff26..3818790 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -27,8 +27,6 @@ jobs: fetch-depth: 0 - name: Install Tools run: | - sudo apt-get install lcov - sudo rm /usr/lib/python3.*/EXTERNALLY-MANAGED pip install --only-binary :all: gcovr==8.6 - name: Check Tools @@ -42,8 +40,6 @@ jobs: echo "-----------" vcpkg --version echo "-----------" - lcov --version - echo "-----------" gcovr --version - name: Install dependencies @@ -57,13 +53,10 @@ jobs: run: | export VCPKG_ROOT=/usr/local/share/vcpkg build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make build - - name: Run tests to generate coverage statistics - run: | - make coverage - - name: Collect coverage into one XML report + - name: Make coverage report run: | - gcovr -e "src/tests/*" --sonarqube > coverage.xml + make coverage - name: Analyze with SonarQube / SonarCloud uses: SonarSource/sonarqube-scan-action@d209202bc7d53ff1cc128f7f907dac145c9d6ae9 @@ -73,4 +66,4 @@ jobs: # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options args: > --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json - --define sonar.coverageReportPaths=coverage.xml + --define sonar.coverageReportPaths=coverage/coverage.xml diff --git a/Makefile b/Makefile index f938ad7..aeca4d1 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ BUILDKIT_PROGRESS=plain DOCKER_COMPOSE=docker compose # TOOLS -COVERAGE_TOOL_OPTS=--config-file .lcovrc --ignore-errors empty --ignore-errors inconsistent +COVERAGE_TOOL_OPTS=--root . --filter 'src/lib/*' --exclude "tests/*" --exclude 'build/*' --txt --txt-metric line --txt-metric branch --print-summary # C++ specific SRC_DIR = src @@ -125,14 +125,14 @@ test-no-deps: cd build && make test coverage: test - lcov ${COVERAGE_TOOL_OPTS} -o coverage/lcov.info \ - --no-external --capture \ - --exclude "build/vcpkg_installed" \ - --exclude "tests/*" \ - --directory . - -coverage/html: coverage - genhtml ${COVERAGE_TOOL_OPTS} -o coverage/ --show-details --legend coverage/lcov.info + gcovr ${COVERAGE_TOOL_OPTS} \ + --lcov coverage/coverage.lcov \ + --sonarqube coverage/coverage.xml + +coverage/html: test + gcovr ${COVERAGE_TOOL_OPTS} \ + --html-details coverage/index.html + @if [ "$$(uname)" = "Darwin" ]; then \ open coverage/index.html; \ elif [ "$$(uname | tr '[:upper:]' '[:lower:]')" = "mingw32" ] || [ "$$(uname | tr '[:upper:]' '[:lower:]')" = "mingw64" ] || [ "$$(uname | tr '[:upper:]' '[:lower:]')" = "cygwin" ]; then \ From 0f008900dbad4f30138abfdd00a4a3854d4504a8 Mon Sep 17 00:00:00 2001 From: Gonzalo Diaz Date: Tue, 13 Oct 2026 21:06:52 -0300 Subject: [PATCH 2/2] fix: coverage GCOVR Exclude Markers applied to known behavior (avoid "C++ internal branches"). --- .../src/hackerrank/projecteuler/euler003.cpp | 2 ++ .../src/hackerrank/warmup/compare_triplets.cpp | 4 ++-- .../src/hackerrank/warmup/mini_max_sum.cpp | 12 +++++++++--- .../src/hackerrank/warmup/plus_minus.cpp | 15 ++++++++------- .../exercises/src/hackerrank/warmup/staircase.cpp | 12 ++++++------ .../src/hackerrank/warmup/time_conversion.cpp | 12 +++++++++--- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp b/src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp index f83c1dc..930074f 100644 --- a/src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp +++ b/src/lib/exercises/src/hackerrank/projecteuler/euler003.cpp @@ -11,7 +11,9 @@ namespace hackerrank::projecteuler { long prime_factor(long n) { if (n < 2) { + // GCOVR_EXCL_START throw std::invalid_argument("n must be greater than 2"); + // GCOVR_EXCL_STOP } long divisor = n; diff --git a/src/lib/exercises/src/hackerrank/warmup/compare_triplets.cpp b/src/lib/exercises/src/hackerrank/warmup/compare_triplets.cpp index 45358bd..0506fb0 100644 --- a/src/lib/exercises/src/hackerrank/warmup/compare_triplets.cpp +++ b/src/lib/exercises/src/hackerrank/warmup/compare_triplets.cpp @@ -10,7 +10,7 @@ namespace hackerrank::warmup { std::vector compareTriplets(const std::vector &a, const std::vector &b) { - std::vector awards = {0, 0}; + std::vector awards = {0, 0}; int i = 0; for (const int &value : a) { @@ -24,6 +24,6 @@ std::vector compareTriplets(const std::vector &a, i += 1; } return awards; -} +} // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } // namespace hackerrank::warmup diff --git a/src/lib/exercises/src/hackerrank/warmup/mini_max_sum.cpp b/src/lib/exercises/src/hackerrank/warmup/mini_max_sum.cpp index 42b15c6..54fcf5a 100644 --- a/src/lib/exercises/src/hackerrank/warmup/mini_max_sum.cpp +++ b/src/lib/exercises/src/hackerrank/warmup/mini_max_sum.cpp @@ -14,7 +14,9 @@ namespace hackerrank::warmup { std::string miniMaxSumCalculate(const std::vector &arr) { if (arr.size() < 2) { + // GCOVR_EXCL_START throw std::invalid_argument("List too short. Pass at least 2 elements."); + // GCOVR_EXCL_STOP } long long tsum = 0; @@ -29,13 +31,17 @@ std::string miniMaxSumCalculate(const std::vector &arr) { } std::stringstream result; - result << tsum - tmax << " " << tsum - tmin; - return result.str(); + result << tsum - tmax << " " << tsum - tmin; // GCOVR_EXCL_BR_WITHOUT_HIT: 3/6 + + return result.str(); // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } void miniMaxSum(const std::vector &arr) { - std::cout << miniMaxSumCalculate(arr) << std::endl; + const auto result = miniMaxSumCalculate(arr); + // GCOVR_EXCL_START + std::cout << result << std::endl; + // GCOVR_EXCL_STOP } } // namespace hackerrank::warmup diff --git a/src/lib/exercises/src/hackerrank/warmup/plus_minus.cpp b/src/lib/exercises/src/hackerrank/warmup/plus_minus.cpp index 4e60fe7..987d3ec 100644 --- a/src/lib/exercises/src/hackerrank/warmup/plus_minus.cpp +++ b/src/lib/exercises/src/hackerrank/warmup/plus_minus.cpp @@ -12,11 +12,11 @@ const int BUFFER_MAX_SIZE = 10; std::string format_result(double number) { std::string str; - str.reserve(BUFFER_MAX_SIZE); + str.reserve(BUFFER_MAX_SIZE); // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 char *buffer = str.data(); snprintf(buffer, BUFFER_MAX_SIZE, "%0.6lf", number); - return buffer; + return buffer; // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } namespace hackerrank::warmup { @@ -37,7 +37,7 @@ std::vector plusMinusCalculate(const std::vector &arr) { } } - std::vector results = { + std::vector results = { static_cast(positives) / static_cast(arr.size()), static_cast(negatives) / static_cast(arr.size()), static_cast(zeros) / static_cast(arr.size())}; @@ -45,18 +45,19 @@ std::vector plusMinusCalculate(const std::vector &arr) { std::vector answer = {}; for (double tmp : results) { - std::string formatted = format_result(tmp); - answer.emplace_back(formatted); + std::string formatted = + format_result(tmp); // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 + answer.emplace_back(formatted); // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } return answer; -} +} // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 void plusMinus(const std::vector &arr) { std::vector output = plusMinusCalculate(arr); for (const std::string &line : output) { - std::cout << line << std::endl; + std::cout << line << std::endl; // GCOVR_EXCL_BR_WITHOUT_HIT: 2/4 } } } // namespace hackerrank::warmup diff --git a/src/lib/exercises/src/hackerrank/warmup/staircase.cpp b/src/lib/exercises/src/hackerrank/warmup/staircase.cpp index e6ee05a..81aaf8e 100644 --- a/src/lib/exercises/src/hackerrank/warmup/staircase.cpp +++ b/src/lib/exercises/src/hackerrank/warmup/staircase.cpp @@ -9,26 +9,26 @@ std::vector staircaseCalculate(int n) { std::vector answer; for (int i = 0; i < n; i++) { - std::string line = ""; + std::string line = ""; // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 for (int j = 0; j < n; j++) { if (j < n - i - 1) { - line += " "; + line += " "; // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } else { - line += "#"; + line += "#"; // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } } - answer.emplace_back(line); + answer.emplace_back(line); // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } return answer; -} +} // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 void staircase(int n) { std::vector output = staircaseCalculate(n); for (const std::string &line : output) { - std::cout << line << std::endl; + std::cout << line << std::endl; // GCOVR_EXCL_BR_WITHOUT_HIT: 2/4 } } } // namespace hackerrank::warmup diff --git a/src/lib/exercises/src/hackerrank/warmup/time_conversion.cpp b/src/lib/exercises/src/hackerrank/warmup/time_conversion.cpp index 09f6fef..367889d 100644 --- a/src/lib/exercises/src/hackerrank/warmup/time_conversion.cpp +++ b/src/lib/exercises/src/hackerrank/warmup/time_conversion.cpp @@ -27,6 +27,7 @@ std::string timeConversion(const std::string &s) { char TIME_SEPARATOR = ':'; std::string meridian = lastN(s, 2); + // GCOVR_EXCL_START auto time_str = std::stringstream(firstN(s, s.size() - 2)); std::string segment; std::vector time; @@ -40,9 +41,12 @@ std::string timeConversion(const std::string &s) { int hour; hour_str >> hour; + // GCOVR_EXCL_STOP if (hour < 0 || hour > 23) { + // GCOVR_EXCL_START throw std::invalid_argument("Invalid hour value: " + std::to_string(hour)); + // GCOVR_EXCL_STOP } if (hour >= 12) { @@ -53,23 +57,25 @@ std::string timeConversion(const std::string &s) { hour += 12; } + // GCOVR_EXCL_START hour_str.str(""); hour_str.clear(); hour_str << std::setfill('0') << std::setw(2) << (hour % 24); time[0] = hour_str.str(); + // GCOVR_EXCL_STOP std::string conversion; unsigned long tsize = time.size(); for (int i = 0; i < tsize; i++) { - conversion += time[i]; + conversion += time[i]; // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 if (i < tsize - 1) { - conversion += ":"; + conversion += ":"; // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } } return conversion; -} +} // GCOVR_EXCL_BR_WITHOUT_HIT: 1/2 } // namespace hackerrank::warmup