diff --git a/.github/workflows/build_binary.yml b/.github/workflows/build_binary.yml index 85392a0..33d2339 100644 --- a/.github/workflows/build_binary.yml +++ b/.github/workflows/build_binary.yml @@ -37,12 +37,12 @@ jobs: CXX: g++ run: | - cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release + cmake --preset linux-gcc-release - name: 'Build' id: 'build' run: | - cmake --build build --config Release + cmake --build --preset linux-gcc-release --target cpp_bindings_linux . build/env.sh echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_OUTPUT @@ -50,8 +50,9 @@ jobs: - name: 'Upload artifacts' uses: actions/upload-artifact@v4 with: - name: libcpp_bindings_linux_x86_64 - path: build/libcpp_bindings_linux.so* + if-no-files-found: error + name: libcpp_bindings_linux + path: build/libcpp_bindings_linux.so - name: 'Check tag' id: 'check-tag' @@ -71,14 +72,25 @@ jobs: package_version: ${{ steps.build.outputs.PACKAGE_VERSION }} is_valid_package_version: ${{ steps.check-tag.outputs.IS_VALID_PACKAGE_VERSION }} - trigger-publish: - name: 'Trigger Publish' + test-unit-cpp: + name: 'Run: Test Unit C++' needs: ['build-binary'] - uses: ./.github/workflows/publish_jsr.yml + uses: './.github/workflows/test_unit_cpp.yml' + with: + artifact-name: cpp_bindings_linux_tests + + permissions: + contents: read + checks: write + + publish-jsr: + name: 'Run: Publish JSR' + needs: ['build-binary', 'test-unit-cpp'] + uses: './.github/workflows/publish_jsr.yml' with: publish: ${{ needs.build-binary.outputs.is_valid_package_version == 'true' }} version: ${{ needs.build-binary.outputs.package_version }} - artifact-name: libcpp_bindings_linux_x86_64 + artifact-name: libcpp_bindings_linux permissions: contents: read diff --git a/.github/workflows/code_coverage_cpp.yml b/.github/workflows/code_coverage_cpp.yml new file mode 100644 index 0000000..0765262 --- /dev/null +++ b/.github/workflows/code_coverage_cpp.yml @@ -0,0 +1,88 @@ +name: 'Code Coverage C++' +description: | + This workflow checks and displays code coverage. + +on: + push: + branches: [ 'main' ] + tags: [ '*' ] + + pull_request: + branches: [ '*' ] + +jobs: + code-coverage-cpp: + name: 'Code Coverage C++' + runs-on: ubuntu-latest + env: + SERIAL_TEST_PORT_IN: /tmp/ttyCI_IN + SERIAL_TEST_PORT_OUT: /tmp/ttyCI_OUT + + permissions: + contents: read + checks: write + + steps: + - name: 'Checkout repository' + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: 'Install Clang and compiler-rt (profile)' + run: | + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/llvm-apt.gpg + echo "deb [signed-by=/usr/share/keyrings/llvm-apt.gpg] https://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-21 main" | sudo tee /etc/apt/sources.list.d/llvm-21.list + sudo apt-get update + sudo apt-get install -y clang-21 libclang-rt-21-dev llvm-21 + + - name: 'Setup CMake' + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.31.x' + + - name: 'Configure CMake (coverage preset)' + run: | + cmake --preset coverage \ + -DCMAKE_C_COMPILER=clang-21 \ + -DCMAKE_CXX_COMPILER=clang++-21 + + - name: 'Build' + run: cmake --build --preset coverage + + - name: 'Install test dependencies' + run: sudo apt-get install -y socat + + - name: 'Start virtual serial echo (socat)' + run: | + socat -d -d pty,raw,echo=0,link=$SERIAL_TEST_PORT_IN,mode=666 pty,raw,echo=0,link=$SERIAL_TEST_PORT_OUT,mode=666 & + sleep 2 + stdbuf -i0 -o0 cat < $SERIAL_TEST_PORT_OUT > $SERIAL_TEST_PORT_OUT & + sleep 1 + + - name: 'Run tests with coverage' + working-directory: build + env: + LD_LIBRARY_PATH: '${{ github.workspace }}/build' + SERIAL_TEST_PORT: '${{ env.SERIAL_TEST_PORT_IN }}' + LLVM_PROFILE_FILE: 'default.profraw' + run: ./cpp_bindings_linux_tests --gtest_color=yes + + - name: 'Merge profile and export lcov' + working-directory: build + run: | + llvm-profdata-21 merge -o default.profdata default.profraw + llvm-cov-21 export -instr-profile=default.profdata \ + ./cpp_bindings_linux_tests \ + -object=./libcpp_bindings_linux.so \ + -format=lcov \ + -ignore-filename-regex='.*/GTest.*' \ + -ignore-filename-regex='.*/googletest.*' \ + -ignore-filename-regex='.*/cpp_core.*' \ + > lcov.info + + - name: 'Code Coverage Annotation' + uses: ggilder/codecoverage@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERAGE_FILE_PATH: './build/lcov.info' + COVERAGE_FORMAT: 'lcov' diff --git a/.github/workflows/cpp_tests.yml b/.github/workflows/cpp_tests.yml deleted file mode 100644 index cefe01e..0000000 --- a/.github/workflows/cpp_tests.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: C++ Tests - -on: - push: - branches: [ main, master ] - pull_request: - -jobs: - cpp-tests: - name: C++ tests (gcc) - runs-on: ubuntu-latest - - container: - image: fedora:43 - - env: - SERIAL_TEST_PORT: /tmp/ttyCI_A - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Install build dependencies (gcc) - run: | - dnf -y update - dnf -y install cmake ninja-build gcc-c++ socat git - - - name: Configure CMake - env: - CXX: g++ - run: | - cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release - - - name: Build - run: | - cmake --build build --config Release - - - name: Start virtual serial echo (socat) - run: | - socat -d -d pty,raw,echo=0,link=/tmp/ttyCI_A,mode=666 pty,raw,echo=0,link=/tmp/ttyCI_B,mode=666 & - sleep 2 - stdbuf -i0 -o0 cat < /tmp/ttyCI_B > /tmp/ttyCI_B & - sleep 1 - - - name: Run C++ unit/integration tests - working-directory: build - env: - SERIAL_TEST_PORT: /tmp/ttyCI_A - run: | - ./cpp_bindings_linux_tests --gtest_color=yes - - diff --git a/.github/workflows/publish_jsr.yml b/.github/workflows/publish_jsr.yml index b950b12..ae9d457 100644 --- a/.github/workflows/publish_jsr.yml +++ b/.github/workflows/publish_jsr.yml @@ -27,8 +27,8 @@ permissions: jobs: publish-jsr: + name: 'Publish JSR' runs-on: ubuntu-latest - steps: - name: 'Checkout repository' uses: actions/checkout@v4 diff --git a/.github/workflows/test_unit_cpp.yml b/.github/workflows/test_unit_cpp.yml new file mode 100644 index 0000000..18d187c --- /dev/null +++ b/.github/workflows/test_unit_cpp.yml @@ -0,0 +1,96 @@ +name: 'Test Unit C++' +description: | + This workflow builds the library and runs the unit tests. + +on: + workflow_call: + inputs: + artifact-name: + description: 'Name of the artifact' + required: true + type: string + +jobs: + test-unit-cpp: + name: 'Test Unit C++' + runs-on: ubuntu-latest + env: + SERIAL_TEST_PORT_IN: /tmp/ttyCI_IN + SERIAL_TEST_PORT_OUT: /tmp/ttyCI_OUT + TEST_REPORT_NAME: 'test_report.xml' + + steps: + - name: 'Checkout repository' + uses: actions/checkout@v4 + + - name: 'Download artifact' + uses: actions/download-artifact@v4 + with: + name: ${{ github.event.inputs.artifact-name }} + path: 'artifacts' + + - name: 'Setup GCC' + uses: egor-tensin/setup-gcc@v2 + with: + version: '14' + platform: 'x64' + + - name: 'Setup CMake' + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.31.x' + + - name: 'Configure CMake' + run: | + cmake --preset linux-gcc-release + + - name: 'Build' + id: 'build' + run: | + cmake --build --preset linux-gcc-release --target cpp_bindings_linux_tests + + - name: 'Install test dependencies' + run: | + sudo apt-get install -y socat + + - name: Start virtual serial echo (socat) + run: | + socat -d -d pty,raw,echo=0,link=$SERIAL_TEST_PORT_IN,mode=666 pty,raw,echo=0,link=$SERIAL_TEST_PORT_OUT,mode=666 & + sleep 2 + stdbuf -i0 -o0 cat < $SERIAL_TEST_PORT_OUT > $SERIAL_TEST_PORT_OUT & + sleep 1 + + - name: 'Run tests' + working-directory: 'build' + env: + LD_LIBRARY_PATH: '${{ github.workspace }}/artifacts' + SERIAL_TEST_PORT: '${{ env.SERIAL_TEST_PORT_IN }}' + + run: | + chmod +x ./cpp_bindings_linux_tests + + ./cpp_bindings_linux_tests \ + --gtest_color=yes \ + --gtest_output=xml:$TEST_REPORT_NAME + + - name: 'Upload test report' + if: always() + uses: actions/upload-artifact@v4 + with: + name: 'test_reports' + path: 'build/${{ env.TEST_REPORT_NAME }}' + + - name: 'Publish test report' + if: always() + uses: mikepenz/action-junit-report@v5 + with: + report_paths: 'build/${{ env.TEST_REPORT_NAME }}' + detailed_summary: true + group_suite: true + include_passed: true + annotate_notice: true + transformers: '[{"searchValue": "${{ github.workspace }}", "replaceValue": ""}]' + check_title_template: '{{FILE_NAME}} | {{TEST_NAME}}' + + + diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..4d82a39 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,46 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "linux-gcc-release", + "displayName": "Linux GCC Release", + "inherits": "default", + "cacheVariables": { + "CMAKE_C_COMPILER": "gcc", + "CMAKE_CXX_COMPILER": "g++" + } + }, + { + "name": "coverage", + "displayName": "Clang Code Coverage", + "inherits": "default", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++", + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_FLAGS": "-fprofile-instr-generate -fcoverage-mapping", + "CMAKE_EXE_LINKER_FLAGS": "-fprofile-instr-generate -fcoverage-mapping", + "CMAKE_SHARED_LINKER_FLAGS": "-fprofile-instr-generate -fcoverage-mapping" + } + } + ], + "buildPresets": [ + { + "name": "linux-gcc-release", + "configurePreset": "linux-gcc-release" + }, + { + "name": "coverage", + "configurePreset": "coverage" + } + ] +}