diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml
new file mode 100644
index 000000000..b2cd6e63b
--- /dev/null
+++ b/.github/workflows/code-coverage.yml
@@ -0,0 +1,195 @@
+name: Code Coverage
+
+on:
+ push:
+ branches: [ main, master, develop, yash/impr/NVR_Release_Mem_Leak_FIx_CacheUpdate ]
+ pull_request:
+ branches: [ main, master, develop ]
+ workflow_dispatch:
+
+jobs:
+ coverage:
+ runs-on: ubuntu-latest
+ env:
+ CMAKE_TC_FILE: '../vcpkg/scripts/buildsystems/vcpkg.cmake'
+ ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
+
+ steps:
+ - name: Install dependencies
+ run: |
+ sudo apt-get update -qq
+ sudo apt-get -y install \
+ ca-certificates curl zip unzip tar autoconf automake autopoint \
+ build-essential flex git-core libass-dev libfreetype6-dev \
+ libgnutls28-dev libmp3lame-dev libsdl2-dev libtool \
+ libsoup-gnome2.4-dev libva-dev libvdpau-dev libvorbis-dev \
+ libxdamage-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev \
+ libncurses5-dev libncursesw5-dev ninja-build pkg-config texinfo \
+ wget yasm zlib1g-dev nasm gperf bison python3 python3-pip \
+ dos2unix libx11-dev libgles2-mesa-dev libxinerama-dev \
+ libxcursor-dev xorg-dev libglu1-mesa-dev python3-jinja2 \
+ lcov gcovr
+ pip3 install meson
+ pip3 install Jinja2
+ # Install CMake 3.29.6
+ pip3 install cmake==3.29.6 || echo 'CMake update skipped'
+
+ - name: Verify tools
+ run: |
+ cmake --version
+ ninja --version
+ gcc --version
+ git --version
+ lcov --version
+ gcovr --version
+
+ - name: Checkout code
+ uses: actions/checkout@v3
+ with:
+ submodules: 'recursive'
+ fetch-depth: 0
+
+ - name: List Submodules
+ run: |
+ git config --global --add safe.directory "*"
+ git submodule status > submodule_ver.txt
+ cat submodule_ver.txt
+ git rev-list --all --count
+
+ - name: Run VCPKG bootstrap
+ run: ./vcpkg/bootstrap-vcpkg.sh
+
+ - name: Remove CUDA from vcpkg (running without CUDA for coverage)
+ working-directory: ${{github.workspace}}/base
+ run: ./fix-vcpkg-json.ps1 -removeCUDA
+ shell: pwsh
+ continue-on-error: true
+
+ - name: Create build directory
+ run: mkdir -p build
+
+ - name: Configure CMake with Coverage
+ working-directory: ${{github.workspace}}/build
+ run: |
+ cmake -B . \
+ -DENABLE_WINDOWS=OFF \
+ -DENABLE_LINUX=ON \
+ -DENABLE_CUDA=OFF \
+ -DCODE_COVERAGE=ON \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DCMAKE_TOOLCHAIN_FILE=${{env.CMAKE_TC_FILE}} \
+ ../base
+
+ - name: Build with Coverage
+ working-directory: ${{github.workspace}}/build
+ run: cmake --build . --config Debug -j 4
+
+ - name: Run Tests and Generate Coverage
+ working-directory: ${{github.workspace}}/build
+ run: |
+ # Run the coverage target which will:
+ # 1. Reset coverage counters
+ # 2. Run tests
+ # 3. Generate lcov report
+ # 4. Generate HTML report
+ make coverage || echo 'Coverage generation completed with warnings'
+ timeout-minutes: 30
+ continue-on-error: true
+
+ - name: Generate Coverage Summary
+ working-directory: ${{github.workspace}}/build
+ run: |
+ # Generate a text summary
+ lcov --summary coverage.info > coverage_summary.txt 2>&1 || true
+ cat coverage_summary.txt
+
+ # Extract coverage percentage for badge
+ COVERAGE=$(lcov --summary coverage.info 2>&1 | grep "lines" | awk '{print $2}')
+ echo "COVERAGE_PERCENTAGE=$COVERAGE" >> $GITHUB_ENV
+ echo "Coverage: $COVERAGE"
+ continue-on-error: true
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ files: ./build/coverage.info
+ flags: unittests
+ name: codecov-aprapipes
+ fail_ci_if_error: false
+ verbose: true
+ token: ${{ secrets.CODECOV_TOKEN }}
+ continue-on-error: true
+
+ - name: Upload coverage reports as artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverage-report
+ path: |
+ build/coverage/
+ build/coverage.info
+ build/coverage_summary.txt
+ retention-days: 30
+ continue-on-error: true
+
+ - name: Comment PR with Coverage
+ if: github.event_name == 'pull_request'
+ uses: actions/github-script@v6
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ const fs = require('fs');
+ let summary = 'Coverage report generation failed';
+ try {
+ summary = fs.readFileSync('build/coverage_summary.txt', 'utf8');
+ } catch (e) {
+ console.log('Could not read coverage summary');
+ }
+
+ const output = `#### Code Coverage Report π
+
+ Coverage Summary
+
+ \`\`\`
+ ${summary}
+ \`\`\`
+
+
+
+ π Full coverage report available in workflow artifacts.
+ π View detailed report: [Codecov Dashboard](https://codecov.io/gh/${{github.repository}})
+
+ *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
+
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: output
+ });
+ continue-on-error: true
+
+ - name: Generate Coverage Badge
+ working-directory: ${{github.workspace}}/build
+ run: |
+ # Generate a simple coverage badge JSON
+ COVERAGE_NUM=$(echo $COVERAGE_PERCENTAGE | sed 's/%//')
+ COLOR="red"
+ if (( $(echo "$COVERAGE_NUM > 80" | bc -l) )); then
+ COLOR="brightgreen"
+ elif (( $(echo "$COVERAGE_NUM > 60" | bc -l) )); then
+ COLOR="yellow"
+ elif (( $(echo "$COVERAGE_NUM > 40" | bc -l) )); then
+ COLOR="orange"
+ fi
+
+ echo "{\"schemaVersion\": 1, \"label\": \"coverage\", \"message\": \"$COVERAGE_PERCENTAGE\", \"color\": \"$COLOR\"}" > coverage-badge.json
+ cat coverage-badge.json
+ continue-on-error: true
+
+ - name: Upload badge data
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverage-badge
+ path: build/coverage-badge.json
+ retention-days: 90
+ continue-on-error: true
diff --git a/COVERAGE_SETUP.md b/COVERAGE_SETUP.md
new file mode 100644
index 000000000..931e6067c
--- /dev/null
+++ b/COVERAGE_SETUP.md
@@ -0,0 +1,275 @@
+# Code Coverage Setup - Quick Reference
+
+This document provides a quick reference for the code coverage setup that has been added to ApraPipes.
+
+## What Was Added
+
+### 1. CMake Coverage Support
+- **File**: `cmake/CodeCoverage.cmake`
+ - Complete CMake module for code coverage
+ - Supports gcov/lcov toolchain
+ - Provides `setup_target_for_coverage_lcov()` function
+
+- **Modified**: `base/CMakeLists.txt`
+ - Added `CODE_COVERAGE` option (default: OFF)
+ - Integrated CodeCoverage.cmake module
+ - Created `coverage` make target
+ - Configured exclusion patterns
+
+### 2. CI/CD Integration
+- **File**: `.github/workflows/code-coverage.yml`
+ - Automated coverage generation on push/PR
+ - Runs on: main, master, develop branches
+ - Uploads to Codecov
+ - Creates artifacts (HTML reports, coverage.info)
+ - Posts PR comments with coverage summary
+
+### 3. Local Development Tools
+- **Script**: `generate_coverage.sh`
+ - One-command coverage generation
+ - Automatic dependency checking
+ - Clean build support
+ - HTML report generation
+
+### 4. Configuration Files
+- **File**: `codecov.yml`
+ - Codecov service configuration
+ - Coverage thresholds and targets
+ - Exclusion patterns
+ - PR comment formatting
+
+### 5. Documentation
+- **File**: `docs/CODE_COVERAGE.md`
+ - Complete user guide
+ - Prerequisites and setup
+ - Troubleshooting section
+ - Best practices
+ - Advanced usage examples
+
+- **Modified**: `README.md`
+ - Added coverage badges
+ - Quick links to coverage reports
+ - Link to detailed documentation
+
+## Quick Start
+
+### For Developers (Local)
+
+```bash
+# Generate coverage report locally
+./generate_coverage.sh
+
+# View the report
+xdg-open build_coverage/coverage/index.html
+```
+
+### For CI/CD
+
+Coverage is automatically generated and published on every push/PR. No manual action needed!
+
+**View Coverage:**
+- [Codecov Dashboard](https://codecov.io/gh/Apra-Labs/ApraPipes)
+- GitHub Actions β Coverage Workflow β Artifacts
+
+### For Manual CMake Build
+
+```bash
+mkdir -p build_coverage && cd build_coverage
+
+cmake -B . \
+ -DENABLE_LINUX=ON \
+ -DENABLE_CUDA=OFF \
+ -DCODE_COVERAGE=ON \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake \
+ ../base
+
+cmake --build . --config Debug -j $(nproc)
+make coverage
+```
+
+## File Structure
+
+```
+ApraPipes/
+βββ cmake/
+β βββ CodeCoverage.cmake # CMake coverage module
+βββ .github/workflows/
+β βββ code-coverage.yml # GitHub Actions workflow
+βββ docs/
+β βββ CODE_COVERAGE.md # Detailed documentation
+βββ base/
+β βββ CMakeLists.txt # Modified for coverage
+βββ codecov.yml # Codecov configuration
+βββ generate_coverage.sh # Local coverage script
+βββ COVERAGE_SETUP.md # This file
+βββ README.md # Updated with badges
+```
+
+## Prerequisites
+
+### Ubuntu/Debian
+```bash
+sudo apt-get install lcov gcov gcovr
+```
+
+### Build Dependencies
+Standard ApraPipes build dependencies (see main README.md)
+
+## Coverage Exclusions
+
+The following are automatically excluded from coverage:
+- Test files (`base/test/*`)
+- Third-party libraries (`thirdparty/*`)
+- VCPKG packages (`vcpkg/*`)
+- Build artifacts (`build/*`)
+- System headers (`/usr/*`)
+- Boost headers
+- OpenCV headers
+
+## Integration Points
+
+### Codecov Setup (Optional but Recommended)
+
+1. Visit https://codecov.io
+2. Sign in with GitHub
+3. Add the ApraPipes repository
+4. Get the upload token
+5. Add to GitHub Secrets as `CODECOV_TOKEN`
+
+Once configured, every PR will show:
+- Coverage percentage
+- Coverage diff
+- Line-by-line coverage in PR view
+
+### IDE Integration
+
+#### VS Code
+1. Install "Coverage Gutters" extension
+2. Generate coverage: `./generate_coverage.sh`
+3. Extension auto-detects `coverage.info`
+
+#### CLion
+1. Build with coverage enabled
+2. Run β Show Coverage Data
+3. Load `build_coverage/coverage.info`
+
+## Usage Scenarios
+
+### Scenario 1: Pre-Commit Check
+```bash
+# Before committing, check coverage
+./generate_coverage.sh
+# Review uncovered lines in HTML report
+xdg-open build_coverage/coverage/index.html
+```
+
+### Scenario 2: PR Review
+- CI automatically generates coverage
+- View coverage diff in PR comments
+- Check Codecov link for detailed analysis
+
+### Scenario 3: Coverage Investigation
+```bash
+# Generate coverage
+./generate_coverage.sh
+
+# Check summary
+lcov --summary build_coverage/coverage.info
+
+# View specific file
+xdg-open build_coverage/coverage/base/src/Module.cpp.gcov.html
+```
+
+### Scenario 4: Module-Specific Coverage
+```bash
+# Filter for specific modules
+cd build_coverage
+lcov --capture --directory . \
+ --output-file coverage_mp4.info \
+ --include "*/Mp4*.cpp"
+
+genhtml coverage_mp4.info --output-directory coverage_mp4
+xdg-open coverage_mp4/index.html
+```
+
+## Troubleshooting
+
+### Issue: Zero coverage reported
+**Solution**: Ensure you built with `-DCODE_COVERAGE=ON` and `-DCMAKE_BUILD_TYPE=Debug`
+
+### Issue: Tests not running
+**Solution**: Check test executable: `./build_coverage/aprapipesut --log_level=all`
+
+### Issue: Old coverage data
+**Solution**: Clean and rebuild:
+```bash
+rm -rf build_coverage
+./generate_coverage.sh
+```
+
+### Issue: Missing dependencies
+**Solution**: Install coverage tools:
+```bash
+sudo apt-get install lcov gcov
+```
+
+## Next Steps
+
+1. **Enable Codecov**
+ - Add `CODECOV_TOKEN` to GitHub secrets
+ - First run will establish baseline
+
+2. **Review Initial Coverage**
+ - Check which modules have low coverage
+ - Prioritize critical components
+
+3. **Improve Coverage**
+ - Add tests for uncovered code
+ - Focus on core functionality first
+ - Target 70%+ line coverage
+
+4. **Monitor Trends**
+ - Review Codecov graphs weekly
+ - Watch for coverage drops in PRs
+ - Celebrate coverage improvements!
+
+## Support
+
+- **Full Documentation**: `docs/CODE_COVERAGE.md`
+- **Issues**: GitHub Issues
+- **Questions**: Contact maintainers
+
+## Coverage Targets
+
+| Metric | Target | Good | Excellent |
+|--------|--------|------|-----------|
+| Line Coverage | > 60% | > 70% | > 80% |
+| Function Coverage | > 50% | > 65% | > 75% |
+| Branch Coverage | > 40% | > 55% | > 70% |
+
+**Note**: Focus on critical paths. 100% coverage is rarely necessary.
+
+## Maintenance
+
+### Regular Tasks
+- Review coverage reports monthly
+- Update exclusion patterns as needed
+- Keep documentation current
+- Monitor CI performance
+
+### When to Update
+- Adding new modules: Update exclusions if needed
+- New dependencies: May need new exclude patterns
+- CMake changes: Verify coverage build still works
+
+## Credits
+
+- Coverage module based on [codecov/example-cpp](https://github.com/codecov/example-cpp)
+- CMake integration inspired by [larsbilke/CMake-codecov](https://github.com/bilke/cmake-modules)
+
+---
+
+**Setup Date**: 2025-11-26
+**Last Updated**: 2025-11-26
+**Maintainer**: ApraPipes Development Team
diff --git a/README.md b/README.md
index 34d36d94b..ea643d538 100755
--- a/README.md
+++ b/README.md
@@ -18,6 +18,14 @@ Aprapipes is automatically built and tested on Ubuntu (18.04 and 20.04), Jetson
|Ubuntu x64_86-WSL|20.04|Yes|[](https://gist.githubusercontent.com/kumaakh/f80af234a4aabedc69af3ee197f66944/raw/badge_WSL.svg)|[](https://github.com/Apra-Labs/ApraPipes/actions/workflows/CI-Linux-CUDA-wsl.yml)|
|Ubuntu x64_86-docker|18.04|Yes|No|[](https://github.com/Apra-Labs/ApraPipes/actions/workflows/CI-Linux-CUDA-Docker.yml)|
+## Code Coverage
+[](https://codecov.io/gh/Apra-Labs/ApraPipes)
+[](https://github.com/Apra-Labs/ApraPipes/actions/workflows/code-coverage.yml)
+
+Code coverage is automatically generated and published on every commit. View detailed coverage reports on [Codecov](https://codecov.io/gh/Apra-Labs/ApraPipes) or download artifacts from the [Coverage Workflow](https://github.com/Apra-Labs/ApraPipes/actions/workflows/code-coverage.yml).
+
+For local coverage generation, see [Code Coverage Documentation](docs/CODE_COVERAGE.md).
+
## Getting Started with ApraPipes
diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt
index 1c964a2b7..333f3704a 100755
--- a/base/CMakeLists.txt
+++ b/base/CMakeLists.txt
@@ -36,6 +36,25 @@ set(CMAKE_CXX_STANDARD 17)
project(APRAPIPES)
+# Code Coverage Configuration
+OPTION(CODE_COVERAGE "Enable coverage reporting" OFF)
+if(CODE_COVERAGE AND ENABLE_LINUX)
+ message(STATUS "Code coverage enabled")
+ include(../cmake/CodeCoverage.cmake)
+ append_coverage_compiler_flags()
+
+ # Exclude patterns for coverage
+ set(COVERAGE_EXCLUDES
+ '*/test/*'
+ '*/thirdparty/*'
+ '*/vcpkg/*'
+ '*/build/*'
+ '/usr/*'
+ '*/boost/*'
+ '*/opencv*'
+ )
+endif()
+
message(STATUS $ENV{PKG_CONFIG_PATH}">>>>>> PKG_CONFIG_PATH")
find_package(PkgConfig REQUIRED)
@@ -670,8 +689,8 @@ IF(ENABLE_LINUX)
)
ENDIF(ENABLE_LINUX)
-target_link_libraries(aprapipesut
- aprapipes
+target_link_libraries(aprapipesut
+ aprapipes
${GLEW_LIBRARIES}
${JPEG_LIBRARIES}
${LIBMP4_LIB}
@@ -685,7 +704,7 @@ target_link_libraries(aprapipesut
${NVJPEGLIB_L4T}
${CURSES_LIBRARIES}
ZXing::Core
- ZXing::ZXing
+ ZXing::ZXing
BZip2::BZip2
ZLIB::ZLIB
LibLZMA::LibLZMA
@@ -694,6 +713,21 @@ target_link_libraries(aprapipesut
whisper::whisper
)
+# Setup code coverage target
+if(CODE_COVERAGE AND ENABLE_LINUX)
+ setup_target_for_coverage_lcov(
+ NAME coverage
+ EXECUTABLE aprapipesut
+ EXECUTABLE_ARGS --log_level=all
+ DEPENDENCIES aprapipesut aprapipes
+ EXCLUDE ${COVERAGE_EXCLUDES}
+ LCOV_ARGS --no-external
+ GENHTML_ARGS --legend --title "ApraPipes Code Coverage"
+ )
+
+ message(STATUS "Code coverage target 'coverage' created. Run 'make coverage' to generate coverage report.")
+endif()
+
IF(ENABLE_WINDOWS)
file(COPY ${RUNTIME_DLLS} DESTINATION Debug/)
file(COPY ${RUNTIME_DLLS} DESTINATION Release/)
diff --git a/cmake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake
new file mode 100644
index 000000000..b09bd5766
--- /dev/null
+++ b/cmake/CodeCoverage.cmake
@@ -0,0 +1,258 @@
+# Copyright (c) 2012 - 2017, Lars Bilke
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# CHANGES:
+#
+# 2012-01-31, Lars Bilke
+# - Enable Code Coverage
+#
+# 2013-09-17, Joakim SΓΆderberg
+# - Added support for Clang.
+# - Some additional usage instructions.
+#
+# 2016-02-03, Lars Bilke
+# - Refactored functions to use named parameters
+#
+# 2017-06-02, Lars Bilke
+# - Merged with modified version from github.com/ufz/ogs
+#
+# 2019-05-06, Anatolii Kurotych
+# - Remove unnecessary --coverage flag
+#
+# 2019-12-13, FeRD (Frank Dana)
+# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
+# of tool-agnostic COVERAGE_EXCLUDES variable
+#
+# 2020-01-19, Mike Purvis
+# - Add genhtml options to customise HTML output
+#
+# 2020-03-10, Martin Grap
+# - Add option to create XML coverage reports
+#
+# USAGE:
+#
+# 1. Copy this file into your cmake modules path.
+#
+# 2. Add the following line to your CMakeLists.txt (best before any add_executable()
+# or add_library() calls):
+# include(CodeCoverage)
+#
+# 3. Append necessary compiler flags for code coverage:
+# append_coverage_compiler_flags()
+#
+# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
+#
+# 4. If you need to exclude additional directories from the report, specify them
+# using full paths in the COVERAGE_EXCLUDES variable before calling
+# setup_target_for_coverage_*().
+# Example:
+# set(COVERAGE_EXCLUDES
+# '${PROJECT_SOURCE_DIR}/tests/*'
+# '/path/to/my/directory/*')
+# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
+# Example:
+# setup_target_for_coverage_lcov(
+# NAME coverage
+# EXECUTABLE testrunner
+# EXCLUDE "${PROJECT_SOURCE_DIR}/tests/*")
+#
+# 5. Use the functions described below to create a custom make target which
+# runs your test executable and produces a code coverage report.
+#
+# 6. Build a Debug build:
+# cmake -DCMAKE_BUILD_TYPE=Debug ..
+# make
+# make my_coverage_target
+#
+
+include(CMakeParseArguments)
+
+option(CODE_COVERAGE "Enable coverage reporting" OFF)
+
+if(CODE_COVERAGE AND NOT CODE_COVERAGE_ADDED)
+ set(CODE_COVERAGE_ADDED 1)
+
+ # Check prereqs
+ find_program(GCOV_PATH gcov)
+ find_program(LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
+ find_program(GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat)
+ find_program(GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
+
+ if(NOT GCOV_PATH)
+ message(FATAL_ERROR "gcov not found! Aborting...")
+ endif()
+
+ if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
+ if(CMAKE_C_COMPILER_VERSION VERSION_LESS 3)
+ message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
+ endif()
+ elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
+ if(NOT CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
+ message(FATAL_ERROR "Compiler is not GNU gcc or Clang! Aborting...")
+ endif()
+ endif()
+
+ set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
+ CACHE INTERNAL "")
+
+ set(CMAKE_C_FLAGS_COVERAGE
+ ${COVERAGE_COMPILER_FLAGS}
+ CACHE STRING "Flags used by the C compiler during coverage builds."
+ FORCE)
+ set(CMAKE_CXX_FLAGS_COVERAGE
+ ${COVERAGE_COMPILER_FLAGS}
+ CACHE STRING "Flags used by the C++ compiler during coverage builds."
+ FORCE)
+ set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used for linking binaries during coverage builds."
+ FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used by the shared libraries linker during coverage builds."
+ FORCE)
+ mark_as_advanced(
+ CMAKE_C_FLAGS_COVERAGE
+ CMAKE_CXX_FLAGS_COVERAGE
+ CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ CMAKE_SHARED_LINKER_FLAGS_COVERAGE)
+
+ if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
+ set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} -fprofile-instr-generate -fcoverage-mapping")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -fprofile-instr-generate -fcoverage-mapping")
+ endif()
+
+ if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
+ endif()
+
+ if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ link_libraries(gcov)
+ endif()
+
+ # Defines a target for running and collection code coverage information
+ # Builds dependencies, runs the given executable and outputs reports.
+ # NOTE! The executable should always have a ZERO as exit code otherwise
+ # the coverage generation will not complete.
+ #
+ # setup_target_for_coverage_lcov(
+ # NAME testrunner_coverage # New target name
+ # EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
+ # DEPENDENCIES testrunner # Dependencies to build first
+ # EXCLUDE "tests/*" # Patterns to exclude (can be relative to BASE_DIRECTORY)
+ # BASE_DIRECTORY "../" # Base directory for report
+ # NO_DEMANGLE # Don't demangle C++ symbols
+ # LCOV_ARGS "--no-external" # Extra arguments for lcov
+ # GENHTML_ARGS "--legend" # Extra arguments for genhtml
+ # )
+ function(setup_target_for_coverage_lcov)
+ set(options NO_DEMANGLE)
+ set(oneValueArgs BASE_DIRECTORY NAME)
+ set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
+ cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT LCOV_PATH)
+ message(FATAL_ERROR "lcov not found! Aborting...")
+ endif()
+
+ if(NOT GENHTML_PATH)
+ message(FATAL_ERROR "genhtml not found! Aborting...")
+ endif()
+
+ # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
+ if(${Coverage_BASE_DIRECTORY})
+ get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
+ else()
+ set(BASEDIR ${PROJECT_SOURCE_DIR})
+ endif()
+
+ # Collect excludes (CMake 3.4+: Also compute absolute paths)
+ set(LCOV_EXCLUDES "")
+ foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
+ if(CMAKE_VERSION VERSION_GREATER "3.4")
+ get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
+ endif()
+ list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
+ endforeach()
+ list(REMOVE_DUPLICATES LCOV_EXCLUDES)
+
+ # Conditional arguments
+ if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
+ set(GENHTML_EXTRA_ARGS "--demangle-cpp")
+ endif()
+
+ # Setup target
+ add_custom_target(${Coverage_NAME}
+ # Cleanup lcov
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . --zerocounters
+ # Create baseline to make sure untouched files show up in the report
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . --capture --initial --output-file ${Coverage_NAME}.base
+ # Run tests
+ COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
+ # Capturing lcov counters and generating report
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.capture
+ # add baseline counters
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --add-tracefile ${Coverage_NAME}.base --add-tracefile ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
+ # filter collected data to final coverage report
+ COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
+ # Generate HTML output
+ COMMAND ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${Coverage_NAME}.info
+ # Cleanup
+ COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.capture ${Coverage_NAME}.total
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
+ DEPENDS ${Coverage_DEPENDENCIES}
+ COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
+ )
+
+ # Show where to find the lcov info report
+ add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
+ COMMAND ;
+ COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
+ )
+
+ # Show info where to find the report
+ add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
+ COMMAND ;
+ COMMENT "Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report."
+ )
+
+ endfunction()
+
+ function(append_coverage_compiler_flags)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
+ message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
+ endfunction()
+
+ function(append_coverage_compiler_flags_to_target name)
+ separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}")
+ target_compile_options(${name} PRIVATE ${_flag_list})
+ target_link_libraries(${name} PRIVATE gcov)
+ endfunction()
+
+endif()
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 000000000..6841f03f4
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,54 @@
+# Codecov Configuration for ApraPipes
+# Documentation: https://docs.codecov.com/docs/codecov-yaml
+
+codecov:
+ require_ci_to_pass: yes
+ notify:
+ wait_for_ci: yes
+
+coverage:
+ precision: 2
+ round: down
+ range: "60...90"
+
+ status:
+ project:
+ default:
+ target: auto
+ threshold: 1%
+ base: auto
+ if_ci_failed: error
+
+ patch:
+ default:
+ target: 70%
+ threshold: 5%
+ if_ci_failed: error
+
+ changes: no
+
+comment:
+ layout: "header, diff, files, footer"
+ behavior: default
+ require_changes: no
+ require_base: no
+ require_head: yes
+
+ignore:
+ - "base/test/**/*"
+ - "thirdparty/**/*"
+ - "vcpkg/**/*"
+ - "build/**/*"
+ - "**/*.md"
+ - "docs/**/*"
+
+flags:
+ unittests:
+ paths:
+ - base/src/
+ carryforward: true
+
+github_checks:
+ annotations: true
+
+slack_app: off
diff --git a/docs/CODE_COVERAGE.md b/docs/CODE_COVERAGE.md
new file mode 100644
index 000000000..1ff4a24d3
--- /dev/null
+++ b/docs/CODE_COVERAGE.md
@@ -0,0 +1,400 @@
+# ApraPipes Code Coverage
+
+This document describes how to generate and view code coverage reports for the ApraPipes project.
+
+## Table of Contents
+
+- [Overview](#overview)
+- [Prerequisites](#prerequisites)
+- [Quick Start](#quick-start)
+- [Manual Coverage Generation](#manual-coverage-generation)
+- [CI/CD Integration](#cicd-integration)
+- [Viewing Coverage Reports](#viewing-coverage-reports)
+- [Understanding Coverage Metrics](#understanding-coverage-metrics)
+- [Troubleshooting](#troubleshooting)
+
+## Overview
+
+Code coverage measures how much of the codebase is executed during testing. The ApraPipes project uses:
+
+- **gcov**: GNU coverage tool for instrumenting code
+- **lcov**: Test coverage program that uses gcov
+- **genhtml**: Generates HTML coverage reports from lcov data
+
+Coverage reports help identify:
+- Untested code paths
+- Areas needing more tests
+- Overall test quality
+
+## Prerequisites
+
+### Linux (Ubuntu/Debian)
+
+```bash
+sudo apt-get update
+sudo apt-get install -y lcov gcov gcovr
+```
+
+### Required Build Tools
+
+Ensure you have the standard ApraPipes build dependencies installed:
+
+```bash
+sudo apt-get install -y \
+ build-essential cmake ninja-build \
+ git pkg-config python3 python3-pip
+```
+
+## Quick Start
+
+### Using the Helper Script
+
+The easiest way to generate coverage is using the provided script:
+
+```bash
+# From the project root directory
+./generate_coverage.sh
+```
+
+For a clean build:
+
+```bash
+./generate_coverage.sh clean
+```
+
+This script will:
+1. Configure CMake with coverage enabled
+2. Build the project with instrumentation
+3. Run all tests
+4. Generate coverage reports (both .info and HTML)
+5. Display a summary
+
+### Opening the Report
+
+After generation, open the HTML report:
+
+```bash
+# Linux
+xdg-open build_coverage/coverage/index.html
+
+# Or with Firefox
+firefox build_coverage/coverage/index.html
+```
+
+## Manual Coverage Generation
+
+If you prefer manual control:
+
+### Step 1: Configure Build
+
+```bash
+mkdir -p build_coverage
+cd build_coverage
+
+cmake -B . \
+ -DENABLE_LINUX=ON \
+ -DENABLE_CUDA=OFF \
+ -DCODE_COVERAGE=ON \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake \
+ ../base
+```
+
+### Step 2: Build with Coverage
+
+```bash
+cmake --build . --config Debug -j $(nproc)
+```
+
+### Step 3: Run Tests and Generate Report
+
+```bash
+make coverage
+```
+
+This target automatically:
+- Resets coverage counters
+- Runs the test suite (`aprapipesut`)
+- Collects coverage data
+- Filters out system/third-party libraries
+- Generates HTML report in `coverage/` directory
+
+### Step 4: View Coverage Summary
+
+```bash
+lcov --summary coverage.info
+```
+
+## CI/CD Integration
+
+### GitHub Actions
+
+Coverage is automatically generated on:
+- Push to `main`, `master`, `develop` branches
+- Pull requests to these branches
+- Manual workflow dispatch
+
+### Workflow File
+
+`.github/workflows/code-coverage.yml`
+
+### Artifacts
+
+Coverage reports are uploaded as workflow artifacts:
+- HTML coverage report
+- `coverage.info` lcov file
+- Coverage summary text
+- Coverage badge JSON
+
+Download from: GitHub Actions β Workflow Run β Artifacts
+
+### Codecov Integration
+
+Coverage data is automatically uploaded to [Codecov](https://codecov.io) for trend tracking and PR comments.
+
+**Setup Codecov:**
+
+1. Sign up at https://codecov.io with your GitHub account
+2. Add your repository
+3. Get the upload token
+4. Add as GitHub secret: `CODECOV_TOKEN`
+
+## Viewing Coverage Reports
+
+### HTML Report Structure
+
+```
+coverage/
+βββ index.html # Main page with overall summary
+βββ base/
+β βββ src/ # Source file coverage
+β β βββ Module.cpp.gcov.html
+β β βββ ...
+β βββ include/ # Header file coverage
+βββ ...
+```
+
+### Report Features
+
+- **Line Coverage**: Which lines were executed
+- **Function Coverage**: Which functions were called
+- **Branch Coverage**: Which conditional branches were taken
+- **Color Coding**:
+ - π’ Green: Covered lines
+ - π΄ Red: Uncovered lines
+ - π‘ Yellow: Partially covered branches
+
+### Key Files to Review
+
+Focus coverage improvements on:
+- Core pipeline modules (`src/Module.cpp`, `src/Pipeline.cpp`)
+- Critical components (`src/Mp4ReaderSource.cpp`, `src/Mp4WriterSink.cpp`)
+- Cache management (`src/OrderedCacheOfFiles.cpp`)
+- Frame processing modules
+
+## Understanding Coverage Metrics
+
+### Line Coverage
+
+```
+Lines......: 75.2% (8543 of 11352 lines)
+```
+
+Percentage of code lines executed during tests.
+
+### Function Coverage
+
+```
+Functions..: 68.4% (1234 of 1804 functions)
+```
+
+Percentage of functions called during tests.
+
+### Branch Coverage
+
+```
+Branches...: 52.1% (3421 of 6567 branches)
+```
+
+Percentage of conditional branches (if/else, switch) taken.
+
+### Coverage Goals
+
+- **Good**: > 70% line coverage
+- **Excellent**: > 80% line coverage
+- **Outstanding**: > 90% line coverage
+
+**Note**: 100% coverage is often impractical. Focus on critical paths.
+
+## Excluding Code from Coverage
+
+### In CMakeLists.txt
+
+Excluded patterns are defined in `base/CMakeLists.txt`:
+
+```cmake
+set(COVERAGE_EXCLUDES
+ '*/test/*' # Test files themselves
+ '*/thirdparty/*' # Third-party libraries
+ '*/vcpkg/*' # Package manager files
+ '*/build/*' # Build artifacts
+ '/usr/*' # System libraries
+ '*/boost/*' # Boost headers
+ '*/opencv*' # OpenCV headers
+)
+```
+
+### In Code
+
+Use `LCOV_EXCL` markers to exclude specific lines:
+
+```cpp
+// LCOV_EXCL_START
+void debugOnlyFunction() {
+ // This won't be counted in coverage
+}
+// LCOV_EXCL_STOP
+
+// Or single line:
+unreachablecode(); // LCOV_EXCL_LINE
+```
+
+## Troubleshooting
+
+### Issue: "gcov not found"
+
+```bash
+sudo apt-get install gcc gcov
+```
+
+### Issue: "lcov not found"
+
+```bash
+sudo apt-get install lcov
+```
+
+### Issue: Zero coverage reported
+
+**Causes:**
+1. Tests didn't run successfully
+2. Wrong build type (must be Debug)
+3. CODE_COVERAGE flag not set
+
+**Solution:**
+
+```bash
+# Check test execution
+./build_coverage/aprapipesut --log_level=all
+
+# Verify build flags
+cmake -L build_coverage/ | grep COVERAGE
+# Should show: CODE_COVERAGE:BOOL=ON
+```
+
+### Issue: Coverage data from old runs
+
+```bash
+# Clean coverage data
+cd build_coverage
+lcov --directory . --zerocounters
+
+# Or rebuild from scratch
+cd ..
+rm -rf build_coverage
+./generate_coverage.sh
+```
+
+### Issue: HTML report not generated
+
+```bash
+# Check for genhtml
+which genhtml
+
+# Manually generate HTML
+cd build_coverage
+genhtml coverage.info --output-directory coverage
+```
+
+### Issue: CUDA code showing in coverage
+
+CUDA code is excluded by building with `ENABLE_CUDA=OFF` for coverage. This is intentional as:
+- CUDA code coverage requires different tools
+- Most CUDA code is vendor-specific
+- Focus on host-side logic first
+
+## Advanced Usage
+
+### Filtering Coverage by Pattern
+
+```bash
+# Generate coverage only for specific modules
+lcov --capture --directory . \
+ --output-file coverage_filtered.info \
+ --include "*/src/Module.cpp" \
+ --include "*/src/Pipeline.cpp"
+
+genhtml coverage_filtered.info --output-directory coverage_modules
+```
+
+### Coverage Diff Between Branches
+
+```bash
+# Generate baseline coverage (main branch)
+git checkout main
+./generate_coverage.sh
+cp build_coverage/coverage.info coverage_main.info
+
+# Generate feature coverage
+git checkout feature-branch
+./generate_coverage.sh clean
+
+# Compare
+lcov --diff coverage_main.info build_coverage/coverage.info \
+ --output-file coverage_diff.info
+
+genhtml coverage_diff.info --output-directory coverage_diff
+```
+
+### Integration with IDEs
+
+#### Visual Studio Code
+
+Install extension: "Coverage Gutters"
+
+1. Generate `coverage.info`
+2. Open VS Code in project root
+3. Extension automatically shows coverage in editor
+
+#### CLion / IntelliJ
+
+1. Build with coverage: `make coverage`
+2. Run β Show Coverage Data
+3. Load `build_coverage/coverage.info`
+
+## Best Practices
+
+1. **Run coverage locally before PR**: Catch untested code early
+2. **Focus on critical paths**: 100% coverage isn't always necessary
+3. **Review uncovered lines**: Understand why they're not tested
+4. **Add tests incrementally**: Don't aim for perfection immediately
+5. **Check coverage trends**: Monitor coverage over time
+6. **Exclude intentionally**: Mark debug/unreachable code explicitly
+
+## Additional Resources
+
+- [gcov Documentation](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html)
+- [lcov README](http://ltp.sourceforge.net/coverage/lcov.php)
+- [Codecov Documentation](https://docs.codecov.com/)
+- [Code Coverage Best Practices](https://testing.googleblog.com/2020/08/code-coverage-best-practices.html)
+
+## Support
+
+For issues or questions:
+- Open an issue on GitHub
+- Check existing coverage-related issues
+- Contact the development team
+
+---
+
+**Last Updated**: 2025-11-26
+**Maintainer**: ApraPipes Development Team
diff --git a/generate_coverage.sh b/generate_coverage.sh
new file mode 100755
index 000000000..91c7c9a2e
--- /dev/null
+++ b/generate_coverage.sh
@@ -0,0 +1,92 @@
+#!/bin/bash
+#
+# ApraPipes Code Coverage Generation Script
+# This script builds the project with coverage enabled and generates an HTML coverage report
+#
+# Usage:
+# ./generate_coverage.sh [clean]
+#
+# Options:
+# clean - Perform a clean build (removes existing build directory)
+#
+
+set -e
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# Script directory
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+BUILD_DIR="${SCRIPT_DIR}/build_coverage"
+
+echo -e "${BLUE}========================================${NC}"
+echo -e "${BLUE} ApraPipes Code Coverage Generator${NC}"
+echo -e "${BLUE}========================================${NC}"
+
+# Check if clean build is requested
+if [ "$1" == "clean" ]; then
+ echo -e "${YELLOW}Performing clean build...${NC}"
+ if [ -d "$BUILD_DIR" ]; then
+ rm -rf "$BUILD_DIR"
+ echo -e "${GREEN}Build directory cleaned.${NC}"
+ fi
+fi
+
+# Check for required tools
+echo -e "\n${BLUE}Checking for required tools...${NC}"
+
+command -v cmake >/dev/null 2>&1 || { echo -e "${RED}Error: cmake is required but not installed.${NC}" >&2; exit 1; }
+command -v lcov >/dev/null 2>&1 || { echo -e "${RED}Error: lcov is required but not installed. Install with: sudo apt-get install lcov${NC}" >&2; exit 1; }
+command -v genhtml >/dev/null 2>&1 || { echo -e "${RED}Error: genhtml is required but not installed. Install with: sudo apt-get install lcov${NC}" >&2; exit 1; }
+command -v gcov >/dev/null 2>&1 || { echo -e "${RED}Error: gcov is required but not installed.${NC}" >&2; exit 1; }
+
+echo -e "${GREEN}All required tools found.${NC}"
+
+# Create build directory
+mkdir -p "$BUILD_DIR"
+cd "$BUILD_DIR"
+
+# Configure CMake with coverage
+echo -e "\n${BLUE}Configuring CMake with code coverage enabled...${NC}"
+cmake -B . \
+ -DENABLE_WINDOWS=OFF \
+ -DENABLE_LINUX=ON \
+ -DENABLE_CUDA=OFF \
+ -DCODE_COVERAGE=ON \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake \
+ ../base
+
+# Build the project
+echo -e "\n${BLUE}Building project with coverage instrumentation...${NC}"
+cmake --build . --config Debug -j $(nproc)
+
+# Run coverage target
+echo -e "\n${BLUE}Running tests and generating coverage report...${NC}"
+make coverage
+
+# Display summary
+echo -e "\n${GREEN}========================================${NC}"
+echo -e "${GREEN} Coverage Report Generated!${NC}"
+echo -e "${GREEN}========================================${NC}"
+
+if [ -f "coverage.info" ]; then
+ echo -e "\n${BLUE}Coverage Summary:${NC}"
+ lcov --summary coverage.info
+fi
+
+if [ -d "coverage" ]; then
+ REPORT_PATH="${BUILD_DIR}/coverage/index.html"
+ echo -e "\n${GREEN}HTML Report Location:${NC}"
+ echo -e " ${REPORT_PATH}"
+ echo -e "\n${YELLOW}Open the report with:${NC}"
+ echo -e " xdg-open ${REPORT_PATH}"
+ echo -e " or"
+ echo -e " firefox ${REPORT_PATH}"
+fi
+
+echo -e "\n${GREEN}Done!${NC}\n"