diff options
author | 2024-11-08 20:29:34 +0300 | |
---|---|---|
committer | 2024-11-17 13:27:13 +0300 | |
commit | 27e67df0c4f93e207dd1d06aa393fb32acda6321 (patch) | |
tree | a779f76ac55810658d4a3febc13c2e09b39b7322 | |
parent | 1ea89e860553634e37daf1cc6de2e00a379d6378 (diff) | |
download | newsboat-27e67df0c4f93e207dd1d06aa393fb32acda6321.tar.gz newsboat-27e67df0c4f93e207dd1d06aa393fb32acda6321.tar.zst newsboat-27e67df0c4f93e207dd1d06aa393fb32acda6321.zip |
Migrate to source-based code coverage
We used to rely on `-Zprofile`, but it was recently removed from Rust
Nightly: https://github.com/rust-lang/rust/pull/131829 This commit
switches to a stable alternative; cf.
https://github.com/mozilla/grcov/issues/1240
This change is accompanied by a change in the build environment: instead
of using Clang 18 with Rust Nightly, we now use Clang 18 with Rust 1.81.
That's the last Rust version based on LLVM 18. Previously we tried to
match LLVM versions between C++ and Rust to avoid weird coverage
results. Now, it's *required* to match them, otherwise no coverage is
gathered at all.
Fixes #2912.
-rw-r--r-- | .github/workflows/coveralls.yaml | 31 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rwxr-xr-x | test/generate_coverage_report.sh | 69 |
4 files changed, 54 insertions, 48 deletions
diff --git a/.github/workflows/coveralls.yaml b/.github/workflows/coveralls.yaml index 74359a7a..77e1a8fc 100644 --- a/.github/workflows/coveralls.yaml +++ b/.github/workflows/coveralls.yaml @@ -8,24 +8,22 @@ jobs: runs-on: ubuntu-24.04 env: - # We use Rust Nightly, which builds upon LLVM 18. To ensure best - # compatibility, we use a matching C++ compiler. + # We use Rust 1.81, which builds upon LLVM 18. We have to use a matching + # C++ compiler, otherwise grcov won't be able to produce the coverage + # report. CC: clang-18 CXX: clang++-18 # Enable test coverage. PROFILE: 1 - # These flags are necessary for grcov to correctly calculate coverage. - CARGO_INCREMENTAL: 0 - # We add `-A warnings` because we aren't interested in warnings from Rust - # Nightly -- GitHub turns them into annotations, which is annoying. - RUSTFLAGS: '-A warnings -Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort' - RUSTDOCFLAGS: '-Cpanic=abort' + CXXFLAGS: '-O0 -fprofile-instr-generate -fcoverage-mapping' + RUSTFLAGS: '-Clink-dead-code -Cinstrument-coverage' # Some of our tests use ncurses, which require a terminal of some sort. # We pretend ours is a simple one. TERM: 'dumb' # This prevents our tests from hogging too much of the CPU and failing # due to races. RUST_TEST_THREADS: 2 + LLVM_PROFILE_FILE: '%h_%m.profraw' steps: - name: Install dependencies @@ -42,7 +40,12 @@ jobs: sudo locale-gen - name: Install Rust - uses: dtolnay/rust-toolchain@nightly + # The last version based on LLVM 18. We have to match LLVM versions + # used to compile Rust and C++, otherwise they might generate + # incompatible coverage reports + uses: dtolnay/rust-toolchain@1.81 + with: + components: llvm-tools-preview - uses: actions/checkout@v4 @@ -63,16 +66,8 @@ jobs: - name: Run tests run: make --jobs=3 NEWSBOAT_RUN_IGNORED_TESTS=1 ci-check - # gcov tool from gcc doesn't understand profiling info that LLVM - # produces, so we trick grcov into using llvm-cov instead. We can't - # simply point grcov at llvm-cov, because the latter only behaves like - # gcc's gcov when invoked by that name. - - name: Prepare to use llvm-cov-18 as gcov - run: ln -s $(which llvm-cov-18) gcov - - name: Calculate test coverage - # Note that we override the path to gcov tool. - run: GCOV=$(pwd)/gcov grcov . --ignore-not-existing --ignore='/*' --ignore='3rd-party/*' --ignore='doc/*' --ignore='test/*' --ignore='target/*' --ignore='newsboat.cpp' --ignore='podboat.cpp' -t lcov -o coverage.lcov + run: grcov . --source-dir . --binary-path . --ignore-not-existing --ignore='/*' --ignore='3rd-party/*' --ignore='doc/*' --ignore='test/*' --ignore='target/*' --ignore='newsboat.cpp' --ignore='podboat.cpp' -t lcov -o coverage.lcov - name: Submit coverage to Coveralls uses: coverallsapp/github-action@v2 @@ -35,3 +35,4 @@ doc/podboat-cmds-linked.asciidoc *.dSYM /.deps/ /compile_flags.txt +*.profraw @@ -234,6 +234,7 @@ clean: clean-newsboat clean-podboat clean-libboat clean-libfilter clean-doc clea profclean: find . -name '*.gc*' -type f -print0 | xargs -0 $(RM) -- + find . -name '*.profraw' -type f -print0 | xargs -0 $(RM) -- $(RM) app*.info distclean: clean profclean diff --git a/test/generate_coverage_report.sh b/test/generate_coverage_report.sh index 66cfe83c..1d73a96e 100755 --- a/test/generate_coverage_report.sh +++ b/test/generate_coverage_report.sh @@ -1,37 +1,46 @@ #!/bin/sh +# Run this script on a machine with Clang 18 and Rust 1.81. These versions both +# use LLVM 18; matching LLVM versions are required for grcov to produce +# a report across the entire codebase. +# +# One can prepare such environment with Docker: +# +# docker build \ +# --build-arg rust_version=1.81 \ +# --build-arg cxx_package='clang-18 libclang-rt-18-dev' \ +# --build-arg cxx=clang++-18 \ +# --build-arg cc=clang-18 \ +# --tag=newsboat-clang-18-rust-1.82:24.04 \ +# --file=docker/ubuntu_24.04-build-tools.dockerfile \ +# docker +# +# docker run \ +# -it --rm \ +# --mount type=bind,source=$(pwd),target=/workspace -w /workspace \ +# --user $(id -u):$(id -g) \ +# newsboat-clang-18-rust-1.81:24.04 \ +# bash -c 'rustup component add llvm-tools-preview && cargo install grcov && test/generate_coverage_report.sh' + set -e -APPBASE_INFO=appbase.info -APPTEST_INFO=apptest.info -APPTOTAL_INFO=apptotal.info +export CC=clang-18 +export CXX=clang++-18 +export CXXFLAGS='-O0 -fprofile-instr-generate -fcoverage-mapping' +export RUSTFLAGS='-Clink-dead-code -Cinstrument-coverage' +export LLVM_PROFILE_FILE='%h_%m.profraw' +export PROFILE=1 + +OUTDIR=html/coverage -rm -rf $APPBASE_INFO $APPTEST_INFO html -find -name '*.gcda' -print0 | xargs -0 rm --force -make -j 5 PROFILE=1 all test -lcov --capture --initial --base-directory . --directory . --output-file $APPBASE_INFO -( cd test && ./test "$@" ) -lcov --capture --base-directory . --directory . --output-file $APPTEST_INFO -lcov --base-directory . --directory . --output-file $APPTOTAL_INFO \ - --add-tracefile $APPBASE_INFO --add-tracefile $APPTEST_INFO +make --jobs=9 NEWSBOAT_RUN_IGNORED_TESTS=1 ci-check -# Removing info about shared libraries -lcov --remove $APPTOTAL_INFO '/usr/*' --output-file $APPTOTAL_INFO -# Removing info about shared libraries (on NixOS) -lcov --remove $APPTOTAL_INFO '/nix/store/*' --output-file $APPTOTAL_INFO -# Removing info about compiler internals -lcov --remove $APPTOTAL_INFO '?.?.?/*' --output-file $APPTOTAL_INFO -lcov --remove $APPTOTAL_INFO '?.?.??/*' --output-file $APPTOTAL_INFO -lcov --remove $APPTOTAL_INFO '?.??.?/*' --output-file $APPTOTAL_INFO -lcov --remove $APPTOTAL_INFO '?.??.??/*' --output-file $APPTOTAL_INFO -# Removing info about Newsboat's tests -lcov --remove $APPTOTAL_INFO 'newsboat/test/*' --output-file $APPTOTAL_INFO -lcov --remove $APPTOTAL_INFO '*/newsboat/test/*' --output-file $APPTOTAL_INFO -# Removing info about Newsboat's docs -lcov --remove $APPTOTAL_INFO 'newsboat/doc/*' --output-file $APPTOTAL_INFO -lcov --remove $APPTOTAL_INFO '*/newsboat/doc/*' --output-file $APPTOTAL_INFO -# Removing info about third-party libraries -lcov --remove $APPTOTAL_INFO '*/newsboat/3rd-party/*' --output-file $APPTOTAL_INFO +rm -rf html +grcov . --source-dir . --binary-path . \ + --ignore-not-existing \ + --ignore='/*' --ignore='3rd-party/*' --ignore='doc/*' --ignore='test/*' \ + --ignore='target/*' --ignore='newsboat.cpp' --ignore='podboat.cpp' \ + -t html -o ./$OUTDIR -genhtml -o html $APPTOTAL_INFO -echo "The coverage report can be found at file://`pwd`/html/index.html" +echo "Coverage reports:" +find $OUTDIR -name 'index.html' |