diff --git a/.config/nextest.toml b/.config/nextest.toml index 3ba8bb393..473c46140 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -4,3 +4,10 @@ status-level = "all" final-status-level = "skip" failure-output = "immediate-final" fail-fast = false + +[profile.coverage] +retries = 0 +status-level = "all" +final-status-level = "skip" +failure-output = "immediate-final" +fail-fast = false diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 30de77fac..e12891453 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -2,7 +2,7 @@ name: CICD # spell-checker:ignore (abbrev/names) CICD CodeCOV MacOS MinGW MSVC musl taiki # spell-checker:ignore (env/flags) Awarnings Ccodegen Coverflow Cpanic Dwarnings RUSTDOCFLAGS RUSTFLAGS Zpanic CARGOFLAGS -# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain fuzzers dedupe devel +# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain fuzzers dedupe devel profdata # spell-checker:ignore (people) Peltoche rivy dtolnay Anson dawidd # spell-checker:ignore (shell/tools) binutils choco clippy dmake dpkg esac fakeroot fdesc fdescfs gmake grcov halium lcov libclang libfuse libssl limactl mkdir nextest nocross pacman popd printf pushd redoxer rsync rustc rustfmt rustup shopt sccache utmpdump xargs # spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils defconfig DESTDIR gecos getenforce gnueabihf issuecomment maint manpages msys multisize noconfirm nullglob onexitbegin onexitend pell runtest Swatinem tempfile testsuite toybox uutils @@ -1001,6 +1001,123 @@ jobs: name: toybox-result.json path: ${{ steps.vars.outputs.TEST_SUMMARY_FILE }} + coverage: + name: Code Coverage + runs-on: ${{ matrix.job.os }} + timeout-minutes: 90 + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" + strategy: + fail-fast: false + matrix: + job: + - { os: ubuntu-latest , features: unix, toolchain: nightly } + # FIXME: Re-enable macos code coverage + # - { os: macos-latest , features: macos, toolchain: nightly } + # FIXME: Re-enable Code Coverage on windows, which currently fails due to "profiler_builtins". See #6686. + # - { os: windows-latest , features: windows, toolchain: nightly-x86_64-pc-windows-gnu } + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.job.toolchain }} + components: rustfmt + - uses: taiki-e/install-action@v2 + with: + tool: nextest,grcov@0.8.24 + - uses: Swatinem/rust-cache@v2 + + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.6 + + # - name: Reattach HEAD ## may be needed for accurate code coverage info + # run: git checkout ${{ github.head_ref }} + + - name: Initialize workflow variables + id: vars + shell: bash + run: | + ## VARs setup + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + + # toolchain + TOOLCHAIN="nightly" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support + + # * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files + case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac; + + # * use requested TOOLCHAIN if specified + if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi + outputs TOOLCHAIN + + # target-specific options + + # * CARGO_FEATURES_OPTION + CARGO_FEATURES_OPTION='--all-features' ; ## default to '--all-features' for code coverage + if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features=${{ matrix.job.features }}' ; fi + outputs CARGO_FEATURES_OPTION + + # * CODECOV_FLAGS + CODECOV_FLAGS=$( echo "${{ matrix.job.os }}" | sed 's/[^[:alnum:]]/_/g' ) + outputs CODECOV_FLAGS + + - name: Install/setup prerequisites + shell: bash + run: | + ## Install/setup prerequisites + case '${{ matrix.job.os }}' in + macos-latest) brew install coreutils ;; # needed for testing + esac + + case '${{ matrix.job.os }}' in + ubuntu-latest) + # pinky is a tool to show logged-in users from utmp, and gecos fields from /etc/passwd. + # In GitHub Action *nix VMs, no accounts log in, even the "runner" account that runs the commands. The account also has empty gecos fields. + # To work around this for pinky tests, we create a fake login entry for the GH runner account... + FAKE_UTMP='[7] [999999] [tty2] [runner] [tty2] [] [0.0.0.0] [2022-02-22T22:22:22,222222+00:00]' + # ... by dumping the login records, adding our fake line, then reverse dumping ... + (utmpdump /var/run/utmp ; echo $FAKE_UTMP) | sudo utmpdump -r -o /var/run/utmp + # ... and add a full name to each account with a gecos field but no full name. + sudo sed -i 's/:,/:runner name,/' /etc/passwd + # We also create a couple optional files pinky looks for + touch /home/runner/.project + echo "foo" > /home/runner/.plan + ;; + esac + + case '${{ matrix.job.os }}' in + # Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368 + windows-latest) C:/msys64/usr/bin/pacman.exe -Sy --needed mingw-w64-x86_64-gcc --noconfirm ; echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH ;; + esac + + ## Install the llvm-tools component to get access to `llvm-profdata` + rustup component add llvm-tools + + - name: Run test and coverage + id: run_test_cov + run: | + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + + # Run the coverage script + ./util/build-run-test-coverage-linux.sh + + outputs REPORT_FILE + env: + COVERAGE_DIR: ${{ github.workspace }}/coverage + FEATURES_OPTION: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} + # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} + + - name: Upload coverage results (to Codecov.io) + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ${{ steps.run_test_cov.outputs.report }} + ## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }} + flags: ${{ steps.vars.outputs.CODECOV_FLAGS }} + name: codecov-umbrella + fail_ci_if_error: false + test_separately: name: Separate Builds runs-on: ${{ matrix.os }} diff --git a/.gitignore b/.gitignore index d8db0ac2c..7528e5f53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # spell-checker:ignore (misc) direnv target/ +coverage/ /src/*/gen_table /build/ /tmp/ diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 85432aed4..c20d5acb7 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,4 +1,4 @@ - + # Setting up your local development environment @@ -253,13 +253,11 @@ pkg install coreutils gsed Code coverage report can be generated using [grcov](https://github.com/mozilla/grcov). -### Using Nightly Rust - To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project) coverage report ```shell export CARGO_INCREMENTAL=0 -export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export RUSTFLAGS="-Cinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" export RUSTDOCFLAGS="-Cpanic=abort" cargo build # e.g., --features feat_os_unix cargo test # e.g., --features feat_os_unix test_pathchk @@ -269,11 +267,6 @@ grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existin if changes are not reflected in the report then run `cargo clean` and run the above commands. -### Using Stable Rust - -If you are using stable version of Rust that doesn't enable code coverage instrumentation by default -then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above. - ## Tips for setting up on Mac ### C Compiler and linker diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index 18b6b67c1..be9ab19cd 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -525,14 +525,20 @@ fn test_gnu_e20() { let scene = TestScenario::new(util_name!()); let env_bin = String::from(uutests::util::get_tests_binary()) + " " + util_name!(); + let input = [ + String::from("-i"), + String::from(r#"-SA="B\_C=D" "#) + env_bin.escape_default().to_string().as_str() + "", + ]; - let (input, output) = ( - [ - String::from("-i"), - String::from(r#"-SA="B\_C=D" "#) + env_bin.escape_default().to_string().as_str() + "", - ], - "A=B C=D\n", - ); + let mut output = "A=B C=D\n".to_string(); + + // Workaround for the test to pass when coverage is being run. + // If enabled, the binary called by env_bin will most probably be + // instrumented for coverage, and thus will set the + // __LLVM_PROFILE_RT_INIT_ONCE + if env::var("__LLVM_PROFILE_RT_INIT_ONCE").is_ok() { + output.push_str("__LLVM_PROFILE_RT_INIT_ONCE=__LLVM_PROFILE_RT_INIT_ONCE\n"); + } let out = scene.ucmd().args(&input).succeeds(); assert_eq!(out.stdout_str(), output); diff --git a/tests/uutests/src/lib/util.rs b/tests/uutests/src/lib/util.rs index 4579b564d..a90c69180 100644 --- a/tests/uutests/src/lib/util.rs +++ b/tests/uutests/src/lib/util.rs @@ -1762,6 +1762,11 @@ impl UCommand { } } + // Forward the LLVM_PROFILE_FILE variable to the call, for coverage purposes. + if let Some(ld_preload) = env::var_os("LLVM_PROFILE_FILE") { + command.env("LLVM_PROFILE_FILE", ld_preload); + } + command .envs(DEFAULT_ENV) .envs(self.env_vars.iter().cloned()); diff --git a/util/build-code_coverage.BAT b/util/build-code_coverage.BAT deleted file mode 100644 index 25d3f618b..000000000 --- a/util/build-code_coverage.BAT +++ /dev/null @@ -1,59 +0,0 @@ -@setLocal -@echo off -set "ERRORLEVEL=" - -@rem ::# spell-checker:ignore (abbrevs/acronyms) gcno -@rem ::# spell-checker:ignore (CMD) COMSPEC ERRORLEVEL -@rem ::# spell-checker:ignore (jargon) toolchain -@rem ::# spell-checker:ignore (rust) Ccodegen Cinline Coverflow Cpanic RUSTC RUSTDOCFLAGS RUSTFLAGS RUSTUP Zpanic -@rem ::# spell-checker:ignore (utils) genhtml grcov lcov sccache uutils - -@rem ::# ref: https://github.com/uutils/coreutils/pull/1476 - -set "FEATURES_OPTION=--features feat_os_windows" - -cd "%~dp0.." -call echo [ "%CD%" ] - -for /f "tokens=*" %%G in ('%~dp0\show-utils.BAT %FEATURES_OPTION%') do set UTIL_LIST=%%G -REM echo UTIL_LIST=%UTIL_LIST% -set "CARGO_INDIVIDUAL_PACKAGE_OPTIONS=" -for %%H in (%UTIL_LIST%) do ( - if DEFINED CARGO_INDIVIDUAL_PACKAGE_OPTIONS call set "CARGO_INDIVIDUAL_PACKAGE_OPTIONS=%%CARGO_INDIVIDUAL_PACKAGE_OPTIONS%% " - call set "CARGO_INDIVIDUAL_PACKAGE_OPTIONS=%%CARGO_INDIVIDUAL_PACKAGE_OPTIONS%%-puu_%%H" -) -REM echo CARGO_INDIVIDUAL_PACKAGE_OPTIONS=%CARGO_INDIVIDUAL_PACKAGE_OPTIONS% - -REM call cargo clean - -set "CARGO_INCREMENTAL=0" -set "RUSTC_WRAPPER=" &@REM ## NOTE: RUSTC_WRAPPER=='sccache' breaks code coverage calculations (uu_*.gcno files are not created during build) -@REM set "RUSTFLAGS=-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads" -set "RUSTFLAGS=-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" -set "RUSTDOCFLAGS=-Cpanic=abort" -set "RUSTUP_TOOLCHAIN=nightly-gnu" -call cargo build %FEATURES_OPTION% -call cargo test --no-run %FEATURES_OPTION% -call cargo test --quiet %FEATURES_OPTION% -call cargo test --quiet %FEATURES_OPTION% %CARGO_INDIVIDUAL_PACKAGE_OPTIONS% - -if NOT DEFINED COVERAGE_REPORT_DIR set COVERAGE_REPORT_DIR=target\debug\coverage-win -call rm -r "%COVERAGE_REPORT_DIR%" 2>NUL - -set GRCOV_IGNORE_OPTION=--ignore build.rs --ignore "/*" --ignore "[A-Za-z]:/*" --ignore "C:/Users/*" -set GRCOV_EXCLUDE_OPTION=--excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" -@rem ::# * build LCOV coverage file -REM echo call grcov . --output-type lcov --output-path "%COVERAGE_REPORT_DIR%/../lcov.info" --branch %GRCOV_IGNORE_OPTION% %GRCOV_EXCLUDE_OPTION% -call grcov . --output-type lcov --output-path "%COVERAGE_REPORT_DIR%/../lcov.info" --branch %GRCOV_IGNORE_OPTION% %GRCOV_EXCLUDE_OPTION% -@rem ::# * build HTML -@rem ::# -- use `genhtml` if available for display of additional branch coverage information -set "ERRORLEVEL=" -call genhtml --version 2>NUL 1>&2 -if NOT ERRORLEVEL 1 ( - echo call genhtml target/debug/lcov.info --prefix "%CD%" --output-directory "%COVERAGE_REPORT_DIR%" --branch-coverage --function-coverage ^| grep ": [0-9]" - call genhtml target/debug/lcov.info --prefix "%CD%" --output-directory "%COVERAGE_REPORT_DIR%" --branch-coverage --function-coverage | grep ": [0-9]" -) else ( - echo call grcov . --output-type html --output-path "%COVERAGE_REPORT_DIR%" --branch %GRCOV_IGNORE_OPTION% - call grcov . --output-type html --output-path "%COVERAGE_REPORT_DIR%" --branch %GRCOV_IGNORE_OPTION% -) -if ERRORLEVEL 1 goto _undefined_ 2>NUL || @for %%G in ("%COMSPEC%") do @title %%nG & @"%COMSPEC%" /d/c exit %ERRORLEVEL% diff --git a/util/build-code_coverage.sh b/util/build-code_coverage.sh deleted file mode 100755 index bbe4abaab..000000000 --- a/util/build-code_coverage.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash - -# spell-checker:ignore (abbrevs/acronyms) HTML gcno llvm -# spell-checker:ignore (jargon) toolchain -# spell-checker:ignore (rust) Ccodegen Cinline Coverflow Cpanic RUSTC RUSTDOCFLAGS RUSTFLAGS RUSTUP Zpanic -# spell-checker:ignore (shell) OSID OSTYPE esac -# spell-checker:ignore (utils) genhtml grcov lcov greadlink readlink sccache shellcheck uutils - -FEATURES_OPTION="--features feat_os_unix" - -# Use GNU coreutils for readlink on *BSD -case "$OSTYPE" in - *bsd*) - READLINK="greadlink" - ;; - *) - READLINK="readlink" - ;; -esac - -ME="${0}" -ME_dir="$(dirname -- "$("${READLINK}" -fm -- "${ME}")")" -REPO_main_dir="$(dirname -- "${ME_dir}")" - -cd "${REPO_main_dir}" && - echo "[ \"$PWD\" ]" - -#shellcheck disable=SC2086 -UTIL_LIST=$("${ME_dir}"/show-utils.sh ${FEATURES_OPTION}) -CARGO_INDIVIDUAL_PACKAGE_OPTIONS="" -for UTIL in ${UTIL_LIST}; do - if [ -n "${CARGO_INDIVIDUAL_PACKAGE_OPTIONS}" ]; then CARGO_INDIVIDUAL_PACKAGE_OPTIONS="${CARGO_INDIVIDUAL_PACKAGE_OPTIONS} "; fi - CARGO_INDIVIDUAL_PACKAGE_OPTIONS="${CARGO_INDIVIDUAL_PACKAGE_OPTIONS}-puu_${UTIL}" -done -# echo "CARGO_INDIVIDUAL_PACKAGE_OPTIONS=${CARGO_INDIVIDUAL_PACKAGE_OPTIONS}" - -# cargo clean - -export CARGO_INCREMENTAL=0 -export RUSTC_WRAPPER="" ## NOTE: RUSTC_WRAPPER=='sccache' breaks code coverage calculations (uu_*.gcno files are not created during build) -# export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads" -export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" -export RUSTDOCFLAGS="-Cpanic=abort" -export RUSTUP_TOOLCHAIN="nightly-gnu" -#shellcheck disable=SC2086 -{ - cargo build ${FEATURES_OPTION} - cargo test --no-run ${FEATURES_OPTION} - cargo test --quiet ${FEATURES_OPTION} - cargo test --quiet ${FEATURES_OPTION} ${CARGO_INDIVIDUAL_PACKAGE_OPTIONS} -} - -export COVERAGE_REPORT_DIR -if [ -z "${COVERAGE_REPORT_DIR}" ]; then COVERAGE_REPORT_DIR="${REPO_main_dir}/target/debug/coverage-nix"; fi -rm -r "${COVERAGE_REPORT_DIR}" 2>/dev/null -mkdir -p "${COVERAGE_REPORT_DIR}" - -## NOTE: `grcov` is not accepting environment variable contents as options for `--ignore` or `--excl_br_line` -# export GRCOV_IGNORE_OPTION="--ignore build.rs --ignore '/*' --ignore '[A-Za-z]:/*' --ignore 'C:/Users/*'" -# export GRCOV_EXCLUDE_OPTION="--excl-br-line '^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()'" -# * build LCOV coverage file -grcov . --output-type lcov --output-path "${COVERAGE_REPORT_DIR}/../lcov.info" --branch --ignore build.rs --ignore '/*' --ignore '[A-Za-z]:/*' --ignore 'C:/Users/*' --excl-br-line '^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()' -# * build HTML -# -- use `genhtml` if available for display of additional branch coverage information -if genhtml --version 2>/dev/null 1>&2; then - genhtml "${COVERAGE_REPORT_DIR}/../lcov.info" --output-directory "${COVERAGE_REPORT_DIR}" --branch-coverage --function-coverage | grep ": [0-9]" -else - grcov . --output-type html --output-path "${COVERAGE_REPORT_DIR}" --branch --ignore build.rs --ignore '/*' --ignore '[A-Za-z]:/*' --ignore 'C:/Users/*' --excl-br-line '^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()' -fi -# shellcheck disable=SC2181 -if [ $? -ne 0 ]; then exit 1; fi diff --git a/util/build-run-test-coverage-linux.sh b/util/build-run-test-coverage-linux.sh new file mode 100755 index 000000000..3eec0dda3 --- /dev/null +++ b/util/build-run-test-coverage-linux.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash + +# spell-checker:ignore (env/flags) Ccodegen Cinstrument Coverflow Cpanic Zpanic +# spell-checker:ignore PROFDATA PROFRAW coreutil librairies nextest profdata profraw rustlib + +# This script will build, run and generate coverage reports for the whole +# testsuite. +# The biggest challenge of this process is managing the overwhelming generation +# of trace files that are generated after EACH SINGLE invocation of a coreutil +# in the testsuite. Moreover, because we run the testsuite against the multicall +# binary, each trace file contains coverage information about the WHOLE +# multicall binary, dependencies included, which results in a 5-6 MB file. +# Running the testsuite easily creates +80 GB of trace files, which is +# unmanageable in a CI environment. +# +# A workaround is to run the testsuite util per util, generate a report per +# util, and remove the trace files. Therefore, we end up with several reports +# that will get uploaded to codecov afterwards. The issue with this +# approach is that the `grcov` call, which is responsible for transforming +# `.profraw` trace files into a `lcov` file, takes a lot of time (~20s), mainly +# because it has to browse all the sources. So calling it for each of the 100 +# utils (with --all-features) results in an absurdly long execution time +# (almost an hour). + +# TODO: Do not instrument 3rd party librairies to save space and performance + +# Exit the script if an unexpected error arise +set -e +# Treat unset variables as errors +set -u +# Print expanded commands to stdout before running them +set -x + +ME="${0}" +ME_dir="$(dirname -- "$(readlink -fm -- "${ME}")")" +REPO_main_dir="$(dirname -- "${ME_dir}")" + +# Features to enable for the `coreutils` package +FEATURES_OPTION=${FEATURES_OPTION:-"--features=feat_os_unix"} +COVERAGE_DIR=${COVERAGE_DIR:-"${REPO_main_dir}/coverage"} + +LLVM_PROFDATA="$(find "$(rustc --print sysroot)" -name llvm-profdata)" + +PROFRAW_DIR="${COVERAGE_DIR}/traces" +PROFDATA_DIR="${COVERAGE_DIR}/data" +REPORT_DIR="${COVERAGE_DIR}/report" +REPORT_PATH="${REPORT_DIR}/total.lcov.info" + +rm -rf "${PROFRAW_DIR}" && mkdir -p "${PROFRAW_DIR}" +rm -rf "${PROFDATA_DIR}" && mkdir -p "${PROFDATA_DIR}" +rm -rf "${REPORT_DIR}" && mkdir -p "${REPORT_DIR}" + +#shellcheck disable=SC2086 +UTIL_LIST=$("${ME_dir}"/show-utils.sh ${FEATURES_OPTION}) + +export CARGO_INCREMENTAL=0 +export RUSTFLAGS="-Cinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export RUSTDOCFLAGS="-Cpanic=abort" +export RUSTUP_TOOLCHAIN="nightly-gnu" +export LLVM_PROFILE_FILE="${PROFRAW_DIR}/coverage-%m-%p.profraw" + +# Disable expanded command printing for the rest of the program +set +x + +run_test_and_aggregate() { + echo "# Running coverage tests for ${1}" + + # Build and run tests for the UTIL + cargo nextest run \ + --profile coverage \ + --no-fail-fast \ + --color=always \ + 2>&1 \ + ${2} \ + | grep -v 'SKIP' + # Note: Do not print the skipped tests on the output as there will be many. + + echo "## Tests for (${1}) generated $(du -h -d1 ${PROFRAW_DIR} | cut -f 1) of profraw files" + + # Aggregate all the trace files into a profdata file + PROFDATA_FILE="${PROFDATA_DIR}/${1}.profdata" + echo "## Aggregating coverage files under ${PROFDATA_FILE}" + "${LLVM_PROFDATA}" merge \ + -sparse \ + -o ${PROFDATA_FILE} \ + ${PROFRAW_DIR}/*.profraw \ + || true + # We don't want an error in `llvm-profdata` to abort the whole program +} + +for UTIL in ${UTIL_LIST}; do + + run_test_and_aggregate \ + "${UTIL}" \ + "-p coreutils -E test(/^test_${UTIL}::/) ${FEATURES_OPTION}" + + echo "## Clear the trace directory to free up space" + rm -rf "${PROFRAW_DIR}" && mkdir -p "${PROFRAW_DIR}" +done; + +echo "Running coverage tests over uucore" +run_test_and_aggregate "uucore" "-p uucore --all-features" + +echo "# Aggregating all the profraw files under ${REPORT_PATH}" +grcov \ + "${PROFDATA_DIR}" \ + --binary-path "${REPO_main_dir}/target/debug/coreutils" \ + --output-types lcov \ + --output-path ${REPORT_PATH} \ + --llvm \ + --keep-only "${REPO_main_dir}"'/src/*' + + +# Notify the report file to github +echo "report=${REPORT_PATH}" >> $GITHUB_OUTPUT diff --git a/util/show-code_coverage.BAT b/util/show-code_coverage.BAT deleted file mode 100644 index 222fff382..000000000 --- a/util/show-code_coverage.BAT +++ /dev/null @@ -1,16 +0,0 @@ -@setLocal -@echo off - -@rem:: # spell-checker:ignore (shell/CMD) COMSPEC ERRORLEVEL - -set "ME_dir=%~dp0." -set "REPO_main_dir=%ME_dir%\.." - -set "ERRORLEVEL=" -set "COVERAGE_REPORT_DIR=%REPO_main_dir%\target\debug\coverage-win" - -call "%ME_dir%\build-code_coverage.BAT" -if ERRORLEVEL 1 goto _undefined_ 2>NUL || @for %%G in ("%COMSPEC%") do @title %%nG & @"%COMSPEC%" /d/c exit %ERRORLEVEL% - -call start "" "%COVERAGE_REPORT_DIR%"\index.html -if ERRORLEVEL 1 goto _undefined_ 2>NUL || @for %%G in ("%COMSPEC%") do @title %%nG & @"%COMSPEC%" /d/c exit %ERRORLEVEL% diff --git a/util/show-code_coverage.sh b/util/show-code_coverage.sh deleted file mode 100755 index 8c6f5e20a..000000000 --- a/util/show-code_coverage.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -# spell-checker:ignore (vars) OSID OSTYPE binfmt greadlink - -# Use GNU coreutils for readlink on *BSD -case "$OSTYPE" in - *bsd*) - READLINK="greadlink" - ;; - *) - READLINK="readlink" - ;; -esac - -ME="${0}" -ME_dir="$(dirname -- "$("${READLINK}" -fm -- "${ME}")")" -REPO_main_dir="$(dirname -- "${ME_dir}")" - -export COVERAGE_REPORT_DIR="${REPO_main_dir}/target/debug/coverage-nix" - -if ! "${ME_dir}/build-code_coverage.sh"; then exit 1; fi - -# WSL? -if [ -z "${OSID_tags}" ]; then - if [ -e '/proc/sys/fs/binfmt_misc/WSLInterop' ] && (grep '^enabled$' '/proc/sys/fs/binfmt_misc/WSLInterop' >/dev/null); then - __="wsl" - case ";${OSID_tags};" in ";;") OSID_tags="$__" ;; *";$__;"*) ;; *) OSID_tags="$__;$OSID_tags" ;; esac - unset __ - # Windows version == ... - # Release ID; see [Release ID/Version vs Build](https://winreleaseinfoprod.blob.core.windows.net/winreleaseinfoprod/en-US.html)[`@`](https://archive.is/GOj1g) - OSID_wsl_build="$(uname -r | sed 's/^[0-9.][0-9.]*-\([0-9][0-9]*\)-.*$/\1/g')" - OSID_wsl_revision="$(uname -v | sed 's/^#\([0-9.][0-9.]*\)-.*$/\1/g')" - export OSID_wsl_build OSID_wsl_revision - fi -fi - -case ";${OSID_tags};" in - *";wsl;"*) powershell.exe -c "$(wslpath -w "${COVERAGE_REPORT_DIR}"/index.html)" ;; - *) xdg-open --version >/dev/null 2>&1 && xdg-open "${COVERAGE_REPORT_DIR}"/index.html || echo "report available at '\"${COVERAGE_REPORT_DIR}\"/index.html'" ;; -esac