diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml new file mode 100644 index 000000000..0b9037c4d --- /dev/null +++ b/.github/workflows/code-coverage.yml @@ -0,0 +1,53 @@ +name: Code Coverage + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + coverage: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # List compiler version + - name: List compiler and gcov version + run: | + gcc --version + gcov --version + + # Install gcovr for coverage report generation + - name: Install gcovr + run: | + sudo apt-get update + sudo apt-get install -y gcovr + + # Checkout wolfssl + - name: Checkout wolfssl + uses: actions/checkout@v4 + with: + repository: wolfssl/wolfssl + path: wolfssl + + # Run coverage + - name: Build and run tests with coverage + run: cd test && make coverage WOLFSSL_DIR=../wolfssl + + # Display coverage summary in the action log + - name: Display coverage summary + run: | + echo "=== Coverage Summary ===" + cd test + gcovr Build --root .. --filter '\.\./src/.*' --filter '\.\./wolfhsm/.*' --print-summary + + # Upload coverage report as artifact + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage/ + retention-days: 30 + diff --git a/.gitignore b/.gitignore index 6b0bb108c..37f572851 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,8 @@ compile_commands.json tools/static-analysis/reports/ *.xml *.html + +# Code coverage +*.gcda +*.gcno +coverage/ diff --git a/test/Makefile b/test/Makefile index 051212dcb..25b40cf88 100644 --- a/test/Makefile +++ b/test/Makefile @@ -77,6 +77,12 @@ ifeq ($(ASAN),1) LDFLAGS += -fsanitize=address endif +# Add code coverage option +ifeq ($(COVERAGE),1) + CFLAGS += --coverage + LDFLAGS += --coverage +endif + ## wolfSSL defines ifeq ($(DEBUG_WOLFSSL),1) DEF += -DDEBUG_WOLFSSL @@ -190,7 +196,7 @@ vpath %.s $(dir $(SRC_ASM)) ## Makefile Targets -.PHONY: build_app build_hex build_static clean run +.PHONY: build_app build_hex build_static clean run coverage build_app: $(BUILD_DIR) $(BUILD_DIR)/$(BIN).elf @echo Build complete. @@ -238,7 +244,9 @@ clean: $(BUILD_DIR)/*.o \ $(BUILD_DIR)/*.a \ $(BUILD_DIR)/*.sym \ - $(BUILD_DIR)/*.disasm + $(BUILD_DIR)/*.disasm \ + $(BUILD_DIR)/*.gcda \ + $(BUILD_DIR)/*.gcno # No prereq's here to stop from rebuilding with different options run: @@ -247,3 +255,29 @@ ifeq (,$(wildcard $(BUILD_DIR)/$(BIN).elf)) else $(BUILD_DIR)/$(BIN).elf endif + +# Coverage target: build with coverage, run tests, and generate report +coverage: + @echo "Building with coverage enabled..." + $(MAKE) clean + $(eval COVERAGE_TARGETS := $(filter-out coverage,$(MAKECMDGOALS))) + $(MAKE) COVERAGE=1 $(if $(COVERAGE_TARGETS),$(COVERAGE_TARGETS),build_app) + @echo "Running tests..." + @if [ ! -f $(BUILD_DIR)/$(BIN).elf ]; then \ + echo "Error: $(BUILD_DIR)/$(BIN).elf not found. Build failed."; \ + exit 1; \ + fi + $(BUILD_DIR)/$(BIN).elf + @echo "Generating coverage report..." + mkdir -p ../coverage && gcovr Build \ + --root .. \ + --gcov-executable gcov \ + --filter '\.\./src/.*' \ + --filter '\.\./wolfhsm/.*' \ + --html-details ../coverage/index.html \ + --print-summary + @echo "Coverage report generated at ../coverage/index.html" + +# Prevent make from trying to build these as targets +%: + @: diff --git a/test/README.md b/test/README.md index 4d1e56a6d..4fea8b979 100644 --- a/test/README.md +++ b/test/README.md @@ -97,3 +97,67 @@ IMG_MGR ECC P256 Test completed successfully! IMG_MGR AES128 CMAC Test completed successfully! IMG_MGR RSA2048 Test completed successfully! ``` + +## Code Coverage + +The test suite supports code coverage analysis using gcovr. To generate coverage reports: + +**Note**: The coverage directory must exist before generating reports. The `make coverage` target creates this automatically, but if running gcovr manually, create it first with: +```bash +mkdir -p ../coverage +``` + +### Running Coverage + +Use the convenient coverage target: +```bash +make coverage +``` + +This will: +1. Clean previous build artifacts +2. Rebuild with coverage instrumentation enabled +3. Run the test suite +4. Generate an HTML coverage report + +The coverage report will be generated at `../coverage/index.html`. + +### Manual Coverage Workflow + +Alternatively, you can run coverage manually: + +```bash +# Build with coverage enabled +make clean +make COVERAGE=1 DEBUG=1 + +# Run tests +make run + +# Create coverage directory and generate report (from repository root) +cd .. +mkdir -p coverage +gcovr --root . \ + --filter 'src/.*' \ + --filter 'wolfhsm/.*' \ + --html-details coverage/index.html \ + --print-summary +``` + +### Coverage Options + +You can customize the coverage report generation: + +```bash +# Generate XML format (for CI/CD) +gcovr --root . --filter 'src/.*' --filter 'wolfhsm/.*' --xml coverage.xml + +# Generate JSON format +gcovr --root . --filter 'src/.*' --filter 'wolfhsm/.*' --json coverage.json + +# Include branch coverage +gcovr --root . --filter 'src/.*' --filter 'wolfhsm/.*' --branches --print-summary + +# Set minimum coverage threshold (fails if below 80%) +gcovr --root . --filter 'src/.*' --filter 'wolfhsm/.*' --fail-under-line 80 +``` diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index 786f15732..f8b3897a2 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -1047,9 +1047,9 @@ int wh_Client_KeyUnwrapAndCacheRequest(whClientContext* ctx, * key. * @return int Returns 0 on success, or a negative error code on failure. */ -int wh_Client_UnrapKeyAndCacheResponse(whClientContext* ctx, - enum wc_CipherType cipherType, - uint16_t* keyIdOut); +int wh_Client_KeyUnwrapAndCacheResponse(whClientContext* ctx, + enum wc_CipherType cipherType, + uint16_t* keyIdOut); /* Counter functions */ int wh_Client_CounterInitRequest(whClientContext* c, whNvmId counterId,