ci: Add minimal code coverage workflow (#3876)

Signed-off-by: Julien Jerphanion <git@jjerphan.xyz>
This commit is contained in:
Julien Jerphanion 2025-04-08 10:44:20 +02:00 committed by GitHub
parent 60ad28aa11
commit f4c7a3d559
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 150 additions and 44 deletions

100
.github/workflows/coverage.yml vendored Normal file
View File

@ -0,0 +1,100 @@
name: Code Coverage
on:
push:
branches:
- main
- feat/*
pull_request:
branches:
- main
- feat/*
paths-ignore:
- "docs/**"
- "**.md"
merge_group:
types: [checks_requested]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
# micromamba activation
shell: bash -l -eo pipefail {0}
jobs:
coverage:
name: Code Coverage
runs-on: ubuntu-latest
steps:
- name: Checkout mamba repository
uses: actions/checkout@v4
- name: Create build environment
uses: mamba-org/setup-micromamba@v2
with:
environment-file: ./dev/environment-dev.yml
environment-name: build_env
cache-environment: true
- name: Install dev-extra environment
run: micromamba install -n build_env -y -f ./dev/environment-dev-extra.yml
- name: Install micromamba-static environment
run: micromamba install -n build_env -y -f ./dev/environment-micromamba-static.yml
- uses: hendrikmuhs/ccache-action@main
with:
variant: sccache
key: ${{ github.job }}-${{ github.runner.os }}
restore-keys: |
ccache-libmamba-${{ github.runner.os }}
- name: Build mamba with coverage
run: |
cmake -B build/ -G Ninja \
--preset mamba-unix-shared-debug \
-D CMAKE_CXX_COMPILER_LAUNCHER=sccache \
-D CMAKE_C_COMPILER_LAUNCHER=sccache \
-D MAMBA_WARNING_AS_ERROR=ON \
-D BUILD_LIBMAMBAPY=ON \
-D BUILD_MICROMAMBA=ON \
-D ENABLE_MAMBA_ROOT_PREFIX_FALLBACK=OFF \
-D CMAKE_BUILD_TYPE=Debug \
-D CMAKE_CXX_FLAGS_DEBUG="-g -O0 -fno-omit-frame-pointer --coverage" \
-D CMAKE_C_FLAGS_DEBUG="-g -O0 -fno-omit-frame-pointer --coverage"
cmake --build build/ --parallel
- name: Show build cache statistics
run: sccache --show-stats
- name: Run C++ tests with coverage
continue-on-error: true
run: |
unset CONDARC # Interferes with tests
./build/libmamba/ext/solv-cpp/tests/test_solv_cpp
./build/libmamba/tests/test_libmamba
- name: Install lcov
run: |
sudo apt-get update
sudo apt-get install -y lcov
- name: Generate C++ coverage report
run: |
lcov --directory . --capture --output-file cpp_coverage.info
lcov --remove cpp_coverage.info '/usr/*' '*/tests/*' '*/build/*' --output-file cpp_coverage.info --ignore-errors unused
lcov --summary cpp_coverage.info --ignore-errors mismatch
- name: Install libmambapy
run: |
cmake --install build/ --prefix "${CONDA_PREFIX}"
python -m pip install --no-deps --no-build-isolation ./libmambapy
- name: Run Python tests with coverage
continue-on-error: true
run: |
# Run libmambapy tests with coverage
python -m pytest libmambapy/tests/ --cov=libmambapy --cov-report=xml --cov-report=term-missing
# Run micromamba tests with coverage
export TEST_MAMBA_EXE=$(pwd)/build/micromamba/mamba
python -m pytest micromamba/tests/ --cov=micromamba --cov-report=xml --cov-report=term-missing
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: |
./cpp_coverage.info
./coverage.xml
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -32,6 +32,7 @@ dependencies:
- pytest-timeout
- pytest-xprocess
- pytest-rerunfailures
- pytest-cov
- memory_profiler
- requests
- sel(win): pywin32

View File

@ -14,41 +14,11 @@
using namespace mamba::util;
using WidenTypes = std::tuple<
// integers
std::pair<char, int>,
std::pair<unsigned char, int>,
std::pair<unsigned char, unsigned int>,
std::pair<int, long long int>,
std::pair<unsigned int, long long int>,
std::pair<unsigned int, unsigned long long int>,
// floats
std::pair<float, double>,
// Mixed
std::pair<char, float>,
std::pair<unsigned char, float>,
std::pair<int, double>,
std::pair<unsigned int, double>>;
using OverflowLowestTypes = std::tuple<
// integers
std::pair<char, unsigned char>,
std::pair<char, unsigned int>,
std::pair<int, char>,
std::pair<int, unsigned long long int>,
// floats
std::pair<double, float>,
// mixed
std::pair<double, int>,
std::pair<float, char>>;
namespace
{
template <typename T>
template <typename From, typename To>
void check_exact_num_cast_widen()
{
using From = typename T::first_type;
using To = typename T::second_type;
static constexpr auto from_lowest = std::numeric_limits<From>::lowest();
static constexpr auto from_max = std::numeric_limits<From>::max();
@ -58,38 +28,73 @@ namespace
REQUIRE(safe_num_cast<To>(from_max) == static_cast<To>(from_max));
}
TEMPLATE_LIST_TEST_CASE("Exact num cast widen", "", WidenTypes)
TEST_CASE("Exact num cast widen - integers")
{
check_exact_num_cast_widen<TestType>();
check_exact_num_cast_widen<char, int>();
check_exact_num_cast_widen<unsigned char, int>();
check_exact_num_cast_widen<unsigned char, unsigned int>();
check_exact_num_cast_widen<int, long long int>();
check_exact_num_cast_widen<unsigned int, long long int>();
check_exact_num_cast_widen<unsigned int, unsigned long long int>();
}
template <typename T>
TEST_CASE("Exact num cast widen - floats")
{
check_exact_num_cast_widen<float, double>();
}
TEST_CASE("Exact num cast widen - mixed")
{
check_exact_num_cast_widen<char, float>();
check_exact_num_cast_widen<unsigned char, float>();
check_exact_num_cast_widen<int, double>();
check_exact_num_cast_widen<unsigned int, double>();
}
template <typename From, typename To>
void check_exact_num_cast_narrow()
{
using From = typename T::second_type; // inversed
using To = typename T::first_type; // inversed
REQUIRE(safe_num_cast<To>(From(0)) == To(0));
REQUIRE(safe_num_cast<To>(From(1)) == To(1));
}
TEMPLATE_LIST_TEST_CASE("Exact num cast narrow", "", WidenTypes)
TEST_CASE("Exact num cast narrow - integers")
{
check_exact_num_cast_narrow<TestType>();
check_exact_num_cast_narrow<int, char>();
check_exact_num_cast_narrow<unsigned int, unsigned char>();
check_exact_num_cast_narrow<long long int, int>();
check_exact_num_cast_narrow<unsigned long long int, unsigned int>();
}
template <typename T>
TEST_CASE("Exact num cast narrow - floats")
{
check_exact_num_cast_narrow<double, float>();
}
template <typename From, typename To>
void check_exact_num_cast_overflow()
{
using From = typename T::first_type;
using To = typename T::second_type;
static constexpr auto from_lowest = std::numeric_limits<From>::lowest();
REQUIRE_THROWS_AS(safe_num_cast<To>(from_lowest), std::overflow_error);
}
TEMPLATE_LIST_TEST_CASE("Exact num cast overflow", "", OverflowLowestTypes)
TEST_CASE("Exact num cast overflow - integers")
{
check_exact_num_cast_overflow<TestType>();
check_exact_num_cast_overflow<char, unsigned char>();
check_exact_num_cast_overflow<char, unsigned int>();
check_exact_num_cast_overflow<int, char>();
check_exact_num_cast_overflow<int, unsigned long long int>();
}
TEST_CASE("Exact num cast overflow - floats")
{
check_exact_num_cast_overflow<double, float>();
}
TEST_CASE("Exact num cast overflow - mixed")
{
check_exact_num_cast_overflow<double, int>();
check_exact_num_cast_overflow<float, char>();
}
TEST_CASE("precision")