Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6401b95
Merge pull request #363 from TEAMuP-dev/develop
cwitkowitz Apr 3, 2026
8f6318a
Update CMakeLists.txt
AydinIqbalNU Jun 24, 2026
b95d381
Create CMakeLists.txt
AydinIqbalNU Jun 24, 2026
f6b72c7
Create test_main.cpp
AydinIqbalNU Jun 24, 2026
751bbec
Create test_smoke.cpp
AydinIqbalNU Jun 24, 2026
1b54ce3
Create pr-build-test.yml - Add CI workflow for unit tests and coverage
AydinIqbalNU Jun 24, 2026
39db70b
Update pr-build-test.yml
AydinIqbalNU Jun 24, 2026
ac79844
Update pr-build-test.yml
AydinIqbalNU Jun 24, 2026
c78f0ea
Update pr-build-test.yml
AydinIqbalNU Jun 24, 2026
2dc28a1
Update pr-build-test.yml
AydinIqbalNU Jun 24, 2026
0195c7c
Update pr-build-test.yml
AydinIqbalNU Jun 25, 2026
8a0ef8d
Update pr-build-test.yml
AydinIqbalNU Jun 25, 2026
b9e3283
Add new test files to harp_tests executable
AydinIqbalNU Jul 20, 2026
dd4bad7
Create README.md for HARP Unit Testing Framework
AydinIqbalNU Jul 20, 2026
cf144a2
Add HARPLogger singleton implementation
AydinIqbalNU Jul 20, 2026
1a5379d
Add HARP Unit Test Matrix documentation
AydinIqbalNU Jul 20, 2026
b398ea1
Add unit tests for Client class functionality
AydinIqbalNU Jul 20, 2026
954e0c4
Add unit tests for GradioClient functionality
AydinIqbalNU Jul 20, 2026
0e7be5e
Add unit tests for controls parsing and behavior
AydinIqbalNU Jul 20, 2026
e45ed21
Add unit tests for Settings class behavior
AydinIqbalNU Jul 20, 2026
a8ea557
Link harp_tests with gtest instead of gtest_main
AydinIqbalNU Jul 20, 2026
6f871ee
Update CMakeLists.txt
AydinIqbalNU Jul 20, 2026
cf4789c
Add option to enable coverage instrumentation
AydinIqbalNU Jul 20, 2026
d5b1eed
Enable code coverage for harp_tests
AydinIqbalNU Jul 20, 2026
15f3ada
Update CMake configuration for coverage and generator
AydinIqbalNU Jul 20, 2026
5d8590e
Refactor PR build and test workflow for coverage
AydinIqbalNU Jul 20, 2026
ab499a5
Add compile definitions for harp_tests
AydinIqbalNU Jul 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 241 additions & 0 deletions .github/workflows/pr-build-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
name: PR - Build / Test

# triggers the workflow to run on pull request or manually.
# DESIGN CHOICES: could add daily auto trigger,
# trigger on github release, trigger on issue open, etc.
on:
pull_request:
branches:
- main
workflow_dispatch:

# do not give actions write permissions
permissions:
actions: read
contents: read

jobs:
build:
runs-on: ubuntu-22.04 # run job on ubuntu linux compiler

steps:

# pulls repo to be built by workflow
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

# install compilers, build system, coverage tool, and python
- name: Install dependencies
run: |
sudo apt-get update

sudo apt-get install -y \
build-essential \
cmake \
lcov \
python3 \
ninja-build \
libasound2-dev \
libx11-dev \
libxinerama-dev \
libxext-dev \
libfreetype6-dev \
libwebkit2gtk-4.0-dev \
libglu1-mesa-dev \
libcurl4-openssl-dev

# configure project into a build directory,
# set to debug mode, and set coverage flags
- name: Configure CMake (with coverage)
run: cmake -S . -B build -G Ninja -DHARP_BUILD_TESTS=ON -DHARP_ENABLE_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug

# compile library and tests
- name: Build HARP application
run: cmake --build build --target HARP --parallel 2

- name: Build unit tests
run: cmake --build build --target harp_tests --parallel 2

- name: Capture coverage baseline
shell: bash
run: |
lcov \
--capture \
--initial \
--directory build \
--output-file coverage-base.info \
--rc geninfo_unexecuted_blocks=1

# runs all tests registered by add_test()
- name: Run tests
id: tests
shell: bash
run: |
set -o pipefail
ctest --test-dir build --output-on-failure 2>&1 | tee test-results.txt

# report which tests failed and what lines
- name: Add test failure details
if: failure() && steps.tests.outcome == 'failure'
shell: bash
run: |
{
echo "## ❌ Failed Tests"
echo
echo '```text'
grep -E "FAILED|Failure|error:|Errors while running CTest" test-results.txt || cat test-results.txt
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

# uploads ctest result as an artifact to be downloaded.
# runs even on test failure.
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: ctest-results
path: |
build/Testing
test-results.txt
if-no-files-found: warn

# write test results into summary UI
- name: Add test results to summary
if: always()
shell: bash
run: |
{
echo "## 🧪 Test Results"
echo
echo '```text'
cat test-results.txt 2>/dev/null || echo "Tests did not run."
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

# capture coverage, filter noise, generate html report
- name: Generate coverage report
if: always()
shell: bash
run: |
mkdir -p coverage

lcov \
--capture \
--directory build \
--output-file coverage-tests.info \
--rc geninfo_unexecuted_blocks=1

lcov \
--add-tracefile coverage-base.info \
--add-tracefile coverage-tests.info \
--output-file coverage-all.info

lcov \
--extract coverage-all.info \
"$GITHUB_WORKSPACE/src/*" \
--output-file coverage.info

lcov \
--remove coverage.info \
"$GITHUB_WORKSPACE/tests/*" \
"$GITHUB_WORKSPACE/JUCE/*" \
"*/_deps/*" \
"/usr/*" \
--output-file coverage.info

if grep -q '^SF:' coverage.info; then
lcov --list coverage.info

genhtml coverage.info \
--output-directory coverage \
--title "HARP Unit Test Coverage" \
--legend
else
echo "No HARP source files were found in the coverage data."

cat > coverage/index.html <<'EOF'
<!doctype html>
<html>
<body>
<h1>HARP coverage unavailable</h1>
<p>No instrumented HARP source files appeared in the coverage data.</p>
</body>
</html>
EOF
fi

# update html coverage dashboard
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: |
coverage
coverage.info
if-no-files-found: warn

# AI-generated markdown test summary

# parse coverage.info to compute coverage %.
# writes .md file containing percentage & progress bars
- name: Generate Markdown Coverage Dashboard
if: always()
shell: bash
env:
TEST_OUTCOME: ${{ steps.tests.outcome }}
run: |
python3 <<'EOF'
import os

covered = 0
total = 0

if os.path.exists("coverage.info"):
with open("coverage.info", encoding="utf-8") as report:
for raw_line in report:
line = raw_line.strip()

if line.startswith("LF:"):
total += int(line.split(":", 1)[1])
elif line.startswith("LH:"):
covered += int(line.split(":", 1)[1])

percentage = round((covered / total) * 100, 1) if total else 0.0
bar_length = 40
filled = round(bar_length * percentage / 100)
bar = "█" * filled + "░" * (bar_length - filled)

test_outcome = os.environ.get("TEST_OUTCOME", "unknown")

status = {
"success": "🟢 Passed",
"failure": "🔴 Failed",
"cancelled": "⚪ Cancelled",
"skipped": "⚪ Skipped",
}.get(test_outcome, "⚪ Not available")

with open("coverage-dashboard.md", "w", encoding="utf-8") as output:
output.write("# 📈 Build Quality Dashboard\n\n")
output.write("## 🧪 Tests\n\n")
output.write(f"- Status: {status}\n\n")
output.write("## 📊 HARP Source Coverage\n\n")
output.write(f"- Covered lines: **{covered} / {total}**\n")
output.write(f"- Line coverage: **{percentage:.1f}%**\n\n")
output.write(f"`{bar}`\n\n")

if total == 0:
output.write(
"> No HARP source coverage data was generated. "
"Check whether the tests exercised instrumented code.\n\n"
)

output.write("_Dashboard generated automatically._\n")
EOF

# put .md dashboard into actions summary
- name: Add Dashboard to Summary
if: always()
run: cat coverage-dashboard.md >> $GITHUB_STEP_SUMMARY
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,15 @@ if (APPLE)

set(CMAKE_SKIP_RPATH "NO" CACHE INTERNAL "")
endif(APPLE)

# --------------------------------------------------
# Unit Testing
# --------------------------------------------------

option(HARP_BUILD_TESTS "Build HARP unit tests" OFF)
option(HARP_ENABLE_COVERAGE "Enable coverage instrumentation" OFF)

if(HARP_BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
51 changes: 51 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
include(FetchContent)

FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)

FetchContent_MakeAvailable(googletest)

add_executable(harp_tests
test_main.cpp
test_harp_logger.cpp
utils/controls_tests.cpp
utils/settings_tests.cpp
clients/client_tests.cpp
clients/gradio_client_tests.cpp
)

target_link_libraries(harp_tests PRIVATE
GTest::gtest
juce::juce_core
juce::juce_data_structures
juce::juce_events
juce::juce_gui_basics
)

target_compile_definitions(harp_tests PRIVATE
JUCE_WEB_BROWSER=0
JUCE_USE_CURL=1
JUCE_LOAD_CURL_SYMBOLS_LAZILY=1
)

if(HARP_ENABLE_COVERAGE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(harp_tests PRIVATE
-O0
-g
--coverage
)

target_link_options(harp_tests PRIVATE
--coverage
)
else()
message(WARNING
"HARP_ENABLE_COVERAGE is enabled, but coverage is only configured for GCC and Clang."
)
endif()
endif()

add_test(NAME harp_tests COMMAND harp_tests)
Loading