diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index eeb11a490..df4c34564 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -1,30 +1,30 @@ name: CICD # spell-checker:ignore (acronyms) CICD MSVC musl -# spell-checker:ignore (env/flags) Ccodegen Coverflow RUSTFLAGS +# spell-checker:ignore (env/flags) Ccodegen Coverflow Cpanic RUSTDOCFLAGS RUSTFLAGS Zpanic # spell-checker:ignore (jargon) SHAs deps softprops toolchain # spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy # spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot gmake grcov halium lcov libssl mkdir popd printf pushd rustc rustfmt rustup shopt xargs -# spell-checker:ignore (misc) aarch alnum armhf coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend uutils +# spell-checker:ignore (misc) aarch alnum armhf coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend tempfile uutils env: PROJECT_NAME: coreutils PROJECT_DESC: "Core universal (cross-platform) utilities" PROJECT_AUTH: "uutils" RUST_MIN_SRV: "1.32.0" ## v1.32.0 - minimum version for half, tempfile, etc - RUST_COV_SRV: "2020-04-29" ## (~v1.45.0) supported rust version for code coverage; (date required/used by 'coverage') ## !maint: refactor when code coverage support is included in the stable channel + RUST_COV_SRV: "2020-08-01" ## (~v1.47.0) supported rust version for code coverage; (date required/used by 'coverage') ## !maint: refactor when code coverage support is included in the stable channel on: [push, pull_request] jobs: - style: - name: Style + code_format: + name: Style/format runs-on: ${{ matrix.job.os }} strategy: fail-fast: false matrix: job: - - { os: ubuntu-latest , features: unix } + - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v1 - name: Initialize workflow variables @@ -58,16 +58,16 @@ jobs: # * convert any warnings to GHA UI annotations; ref: S=$(find tests -name "*.rs" -print0 | xargs -0 cargo fmt -- --check) && printf "%s\n" "$S" || { printf "%s\n" "$S" | sed -E -n "s/^Diff[[:space:]]+in[[:space:]]+${PWD//\//\\/}\/(.*)[[:space:]]+at[[:space:]]+[^0-9]+([0-9]+).*$/::warning file=\1,line=\2::WARNING: \`cargo fmt\`: style violation/p" ; } - clippy: - name: Clippy + code_warnings: + name: Style/warnings runs-on: ${{ matrix.job.os }} strategy: fail-fast: false matrix: job: - - { os: ubuntu-latest , features: unix } - - { os: macos-latest , features: macos } - - { os: windows-latest , features: windows } + - { os: ubuntu-latest , features: feat_os_unix } + - { os: macos-latest , features: feat_os_macos } + - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v1 - name: Initialize workflow variables @@ -309,6 +309,16 @@ jobs: target: ${{ matrix.job.target }} default: true profile: minimal # minimal component installation (ie, no documentation) + - name: Initialize toolchain-dependent workflow variables + id: dep_vars + shell: bash + run: | + ## Dependent VARs setup + # * determine sub-crate utility list + UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})" + CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo "-puu_${u}"; done;)" + echo set-output name=UTILITY_LIST::${UTILITY_LIST} + echo ::set-output name=CARGO_UTILITY_LIST_OPTIONS::${CARGO_UTILITY_LIST_OPTIONS} - name: Install `cargo-tree` # for dependency information uses: actions-rs/install@v0.1 with: @@ -352,6 +362,12 @@ jobs: use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }} command: test args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} + - name: Test individual utilities + uses: actions-rs/cargo@v1 + with: + use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }} + command: test + args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} - name: Archive executable artifacts uses: actions/upload-artifact@v2 with: @@ -454,6 +470,16 @@ jobs: toolchain: ${{ steps.vars.outputs.TOOLCHAIN }} default: true profile: minimal # minimal component installation (ie, no documentation) + - name: Initialize toolchain-dependent workflow variables + id: dep_vars + shell: bash + run: | + ## Dependent VARs setup + # * determine sub-crate utility list + UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})" + CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo "-puu_${u}"; done;)" + echo set-output name=UTILITY_LIST::${UTILITY_LIST} + echo ::set-output name=CARGO_UTILITY_LIST_OPTIONS::${CARGO_UTILITY_LIST_OPTIONS} - name: Test uses: actions-rs/cargo@v1 with: @@ -462,7 +488,19 @@ jobs: env: CARGO_INCREMENTAL: '0' RUSTC_WRAPPER: '' - RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads' + RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort' + RUSTDOCFLAGS: '-Cpanic=abort' + # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} + - name: Test individual utilities + uses: actions-rs/cargo@v1 + with: + command: test + args: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} + env: + CARGO_INCREMENTAL: '0' + RUSTC_WRAPPER: '' + RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort' + RUSTDOCFLAGS: '-Cpanic=abort' # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} - name: "`grcov` ~ install" uses: actions-rs/install@v0.1 @@ -470,33 +508,6 @@ jobs: crate: grcov version: latest use-tool-cache: true - - name: "`grcov` ~ display coverage files" ## (for debugging) - shell: bash - run: | - # display coverage files (per `grcov`) - grcov . --output-type files | sort --unique - - name: "`grcov` ~ configure + fixups" ## note: fixups, when needed, must be done *after* testing so that coverage files exist for renaming - shell: bash - run: | - # create `grcov` configuration file - GRCOV_CONFIG_DIR="${GITHUB_WORKSPACE}/.github/actions-rs" - mkdir -p "${GRCOV_CONFIG_DIR}" - GRCOV_CONFIG_FILE="${GRCOV_CONFIG_DIR}/grcov.yml" - echo "branch: true" >> "${GRCOV_CONFIG_FILE}" - echo "ignore:" >> "${GRCOV_CONFIG_FILE}" - echo "- \"build.rs\"" >> "${GRCOV_CONFIG_FILE}" - echo "- \"/*\"" >> "${GRCOV_CONFIG_FILE}" - echo "- \"[a-zA-Z]:/*\"" >> "${GRCOV_CONFIG_FILE}" - cat "${GRCOV_CONFIG_FILE}" - # ## 'actions-rs/grcov@v0.1' expects coverage files (*.gc*) to be prefixed with the crate name (using '_' in place of '-') - # ## * uutils workspace packages - # prefix="uu_" - # for f in "target/debug/deps/uu_"*-*.gc* ; do to="${f/uu_/${PROJECT_NAME}-uu_}" ; mv "$f" "$to" ; echo "mv $f $to" ; done - # ## * tests - # for f in "target/debug/deps/tests"-*.gc* ; do to="${f/tests/${PROJECT_NAME}-tests}" ; mv "$f" "$to" ; echo "mv $f $to" ; done - # - name: Generate coverage data (via `grcov`) - # id: coverage - # uses: actions-rs/grcov@v0.1 - name: Generate coverage data (via `grcov`) id: coverage shell: bash @@ -504,8 +515,13 @@ jobs: # generate coverage data COVERAGE_REPORT_DIR="target/debug" COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info" + # GRCOV_IGNORE_OPTION='--ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*"' ## `grcov` ignores these params when passed as an environment variable (why?) + # GRCOV_EXCLUDE_OPTION='--excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"' ## `grcov` ignores these params when passed as an environment variable (why?) mkdir -p "${COVERAGE_REPORT_DIR}" - grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch ${GRCOV_IGNORE_OPTION} --ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*" + # display coverage files + grcov . --output-type files --ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique + # generate coverage report + grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" echo ::set-output name=report::${COVERAGE_REPORT_FILE} - name: Upload coverage results (to Codecov.io) uses: codecov/codecov-action@v1 diff --git a/Makefile.toml b/Makefile.toml index 0a72a4658..ded2cd55b 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -208,6 +208,34 @@ dependencies = [ "core::post-test", ] +[tasks.test-util] +description = "## Test (individual) utilities; usage: `cargo make (test-util | test-uutil) [UTIL_NAME...]`" +category = "[project]" +dependencies = [ + "action-test-utils", +] + +[tasks.test-utils] +description = "hidden plural-form alias for 'test-util'" +category = "[project]" +dependencies = [ + "test-util", +] + +[tasks.test-uutil] +description = "hidden alias for 'test-util'" +category = "[project]" +dependencies = [ + "test-util", +] + +[tasks.test-uutils] +description = "hidden alias for 'test-util'" +category = "[project]" +dependencies = [ + "test-util", +] + [tasks.uninstall] description = "## Remove project binary (from $HOME/.cargo/bin)" category = "[project]" @@ -232,7 +260,11 @@ dependencies = [ ] [tasks.uutil] -alias = "utils" +description = "hidden alias for 'util'" +category = "[project]" +dependencies = [ + "util", +] [tasks.uutils] description = "hidden plural-form alias for 'util'" @@ -351,6 +383,15 @@ description = "`codespell` spellcheck repository" command = "codespell" # (from `pip install codespell`) args = [".", "--skip=*/.git,./target,./tests/fixtures", "--ignore-words-list=mut,od"] +[tasks.action-test-utils] +description = "Build individual utilities" +dependencies = [ + "action-determine-utils", +] +command = "cargo" +# args = ["build", "@@remove-empty(CARGO_MAKE_TASK_BUILD_UTILS_ARGS)" ] +args = ["test", "@@split(CARGO_MAKE_TASK_BUILD_UTILS_ARGS, )" ] + [tasks.action-test_quiet] description = "Test (in `--quiet` mode)" command = "cargo" diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index 0b4cd0530..0a35e243b 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -464,7 +464,7 @@ fn write_nonprint_to_end(in_buf: &[u8], writer: &mut W, tab: &[u8]) -> } } -#[test] +#[cfg(test)] mod tests { use std::io::{stdout, BufWriter}; diff --git a/src/uu/factor/src/numeric/gcd.rs b/src/uu/factor/src/numeric/gcd.rs index ec72570ba..6273e788c 100644 --- a/src/uu/factor/src/numeric/gcd.rs +++ b/src/uu/factor/src/numeric/gcd.rs @@ -75,6 +75,7 @@ mod tests { fn divisor(a: u64, b: u64) -> bool { // Test that gcd(a, b) divides a and b let g = gcd(a, b); + if g == 0 { return a == 0 && b == 0; } a % g == 0 && b % g == 0 } diff --git a/src/uu/mknod/src/parsemode.rs b/src/uu/mknod/src/parsemode.rs index e995d93b9..b180bb8e5 100644 --- a/src/uu/mknod/src/parsemode.rs +++ b/src/uu/mknod/src/parsemode.rs @@ -20,18 +20,40 @@ pub fn parse_mode(mode: Option) -> Result { } } -#[test] -fn symbolic_modes() { - assert_eq!(parse_mode(Some("u+x".to_owned())).unwrap(), 0o766); - assert_eq!(parse_mode(Some("+x".to_owned())).unwrap(), 0o777); - assert_eq!(parse_mode(Some("a-w".to_owned())).unwrap(), 0o444); - assert_eq!(parse_mode(Some("g-r".to_owned())).unwrap(), 0o626); -} +#[cfg(test)] +mod test { + /// Test if the program is running under WSL + // ref: @@ + // ToDO: test on WSL2 which likely doesn't need special handling; plan change to `is_wsl_1()` if WSL2 is less needy + pub fn is_wsl() -> bool { + #[cfg(target_os = "linux")] + { + if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") { + if let Ok(s) = std::str::from_utf8(&b) { + let a = s.to_ascii_lowercase(); + return a.contains("microsoft") || a.contains("wsl"); + } + } + } + false + } -#[test] -fn numeric_modes() { - assert_eq!(parse_mode(Some("644".to_owned())).unwrap(), 0o644); - assert_eq!(parse_mode(Some("+100".to_owned())).unwrap(), 0o766); - assert_eq!(parse_mode(Some("-4".to_owned())).unwrap(), 0o662); - assert_eq!(parse_mode(None).unwrap(), 0o666); + #[test] + fn symbolic_modes() { + assert_eq!(super::parse_mode(Some("u+x".to_owned())).unwrap(), 0o766); + assert_eq!( + super::parse_mode(Some("+x".to_owned())).unwrap(), + if !is_wsl() { 0o777 } else { 0o776 } + ); + assert_eq!(super::parse_mode(Some("a-w".to_owned())).unwrap(), 0o444); + assert_eq!(super::parse_mode(Some("g-r".to_owned())).unwrap(), 0o626); + } + + #[test] + fn numeric_modes() { + assert_eq!(super::parse_mode(Some("644".to_owned())).unwrap(), 0o644); + assert_eq!(super::parse_mode(Some("+100".to_owned())).unwrap(), 0o766); + assert_eq!(super::parse_mode(Some("-4".to_owned())).unwrap(), 0o662); + assert_eq!(super::parse_mode(None).unwrap(), 0o666); + } } diff --git a/src/uu/od/src/inputdecoder.rs b/src/uu/od/src/inputdecoder.rs index 0bc6113b9..377f0c4ef 100644 --- a/src/uu/od/src/inputdecoder.rs +++ b/src/uu/od/src/inputdecoder.rs @@ -159,8 +159,8 @@ impl<'a> MemoryDecoder<'a> { #[cfg(test)] mod tests { use super::*; - use byteorder_io::ByteOrder; - use peekreader::PeekReader; + use crate::byteorder_io::ByteOrder; + use crate::peekreader::PeekReader; use std::io::Cursor; #[test] diff --git a/src/uu/od/src/mockstream.rs b/src/uu/od/src/mockstream.rs index f66f1dec7..810e1d35b 100644 --- a/src/uu/od/src/mockstream.rs +++ b/src/uu/od/src/mockstream.rs @@ -1,6 +1,5 @@ // https://github.com/lazy-bitfield/rust-mockstream/pull/2 -use std::error::Error as errorError; use std::io::{Cursor, Error, ErrorKind, Read, Result}; /// `FailingMockStream` mocks a stream which will fail upon read or write @@ -87,7 +86,7 @@ fn test_failing_mock_stream_read() { let mut v = [0; 4]; let error = s.read(v.as_mut()).unwrap_err(); assert_eq!(error.kind(), ErrorKind::BrokenPipe); - assert_eq!(error.description(), "The dog ate the ethernet cable"); + assert_eq!(error.to_string(), "The dog ate the ethernet cable"); // after a single error, it will return Ok(0) assert_eq!(s.read(v.as_mut()).unwrap(), 0); } diff --git a/src/uu/od/src/multifilereader.rs b/src/uu/od/src/multifilereader.rs index dae9ece03..e41c9e39b 100644 --- a/src/uu/od/src/multifilereader.rs +++ b/src/uu/od/src/multifilereader.rs @@ -126,7 +126,7 @@ impl<'b> HasError for MultifileReader<'b> { #[cfg(test)] mod tests { use super::*; - use mockstream::*; + use crate::mockstream::*; use std::io::{Cursor, ErrorKind, Read}; #[test] diff --git a/src/uu/od/src/output_info.rs b/src/uu/od/src/output_info.rs index b1f25e31f..a204fa36e 100644 --- a/src/uu/od/src/output_info.rs +++ b/src/uu/od/src/output_info.rs @@ -99,7 +99,7 @@ impl OutputInfo { /// /// Multiple representations of the same data, will be right-aligned for easy reading. /// For example a 64 bit octal and a 32-bit decimal with a 16-bit hexadecimal looks like this: - /// ``` + /// ```ignore /// 1777777777777777777777 1777777777777777777777 /// 4294967295 4294967295 4294967295 4294967295 /// ffff ffff ffff ffff ffff ffff ffff ffff @@ -131,7 +131,7 @@ impl OutputInfo { /// /// Here is another example showing the alignment of 64-bit unsigned decimal numbers, /// 32-bit hexadecimal number, 16-bit octal numbers and 8-bit hexadecimal numbers: - /// ``` + /// ```ignore /// 18446744073709551615 18446744073709551615 /// ffffffff ffffffff ffffffff ffffffff /// 177777 177777 177777 177777 177777 177777 177777 177777 diff --git a/src/uu/od/src/parse_formats.rs b/src/uu/od/src/parse_formats.rs index 930724d01..61be92c40 100644 --- a/src/uu/od/src/parse_formats.rs +++ b/src/uu/od/src/parse_formats.rs @@ -337,7 +337,7 @@ fn parse_type_string(params: &str) -> Result, Strin pub fn parse_format_flags_str( args_str: &Vec<&'static str>, ) -> Result, String> { - let args = args_str.iter().map(|s| s.to_string()).collect(); + let args: Vec = args_str.iter().map(|s| s.to_string()).collect(); match parse_format_flags(&args) { Err(e) => Err(e), Ok(v) => { diff --git a/src/uu/od/src/partialreader.rs b/src/uu/od/src/partialreader.rs index 2a71cea43..7e906f515 100644 --- a/src/uu/od/src/partialreader.rs +++ b/src/uu/od/src/partialreader.rs @@ -76,8 +76,7 @@ impl HasError for PartialReader { #[cfg(test)] mod tests { use super::*; - use mockstream::*; - use std::error::Error; + use crate::mockstream::*; use std::io::{Cursor, ErrorKind, Read}; #[test] @@ -97,7 +96,7 @@ mod tests { let error = sut.read(v.as_mut()).unwrap_err(); assert_eq!(error.kind(), ErrorKind::PermissionDenied); - assert_eq!(error.description(), "No access"); + assert_eq!(error.to_string(), "No access"); } #[test] @@ -126,7 +125,7 @@ mod tests { let error = sut.read(v.as_mut()).unwrap_err(); assert_eq!(error.kind(), ErrorKind::PermissionDenied); - assert_eq!(error.description(), "No access"); + assert_eq!(error.to_string(), "No access"); } #[test] @@ -173,7 +172,7 @@ mod tests { let error = sut.read(v.as_mut()).unwrap_err(); assert_eq!(error.kind(), ErrorKind::PermissionDenied); - assert_eq!(error.description(), "No access"); + assert_eq!(error.to_string(), "No access"); } #[test] diff --git a/src/uu/od/src/prn_float.rs b/src/uu/od/src/prn_float.rs index 422d3285a..411bc9c10 100644 --- a/src/uu/od/src/prn_float.rs +++ b/src/uu/od/src/prn_float.rs @@ -197,8 +197,6 @@ fn test_format_flo64() { #[test] fn test_format_flo16() { - use half::consts::*; - assert_eq!(format_flo16(f16::from_bits(0x8400u16)), "-6.104e-5"); assert_eq!(format_flo16(f16::from_bits(0x8401u16)), "-6.109e-5"); assert_eq!(format_flo16(f16::from_bits(0x8402u16)), "-6.115e-5"); @@ -213,11 +211,11 @@ fn test_format_flo16() { assert_eq!(format_flo16(f16::from_f32(-0.2)), " -0.2000"); assert_eq!(format_flo16(f16::from_f32(-0.02)), "-2.000e-2"); - assert_eq!(format_flo16(MIN_POSITIVE_SUBNORMAL), " 5.966e-8"); - assert_eq!(format_flo16(MIN), " -6.550e4"); - assert_eq!(format_flo16(NAN), " NaN"); - assert_eq!(format_flo16(INFINITY), " inf"); - assert_eq!(format_flo16(NEG_INFINITY), " -inf"); - assert_eq!(format_flo16(NEG_ZERO), " -0"); - assert_eq!(format_flo16(ZERO), " 0"); + assert_eq!(format_flo16(f16::MIN_POSITIVE_SUBNORMAL), " 5.960e-8"); + assert_eq!(format_flo16(f16::MIN), " -6.550e4"); + assert_eq!(format_flo16(f16::NAN), " NaN"); + assert_eq!(format_flo16(f16::INFINITY), " inf"); + assert_eq!(format_flo16(f16::NEG_INFINITY), " -inf"); + assert_eq!(format_flo16(f16::NEG_ZERO), " -0"); + assert_eq!(format_flo16(f16::ZERO), " 0"); } diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index 824071190..422ea1986 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -4,9 +4,6 @@ use self::tail::parse_size; use crate::common::util::*; use std::char::from_digit; use std::io::Write; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; static FOOBAR_TXT: &'static str = "foobar.txt"; static FOOBAR_2_TXT: &'static str = "foobar2.txt"; @@ -98,8 +95,14 @@ fn test_follow_stdin() { .stdout_is_fixture("follow_stdin.expected"); } +// FixME: test PASSES for usual windows builds, but fails for coverage testing builds (likely related to the specific RUSTFLAGS '-Zpanic_abort_tests -Cpanic=abort') +#[cfg(not(windows))] #[test] fn test_follow_with_pid() { + use std::process::{Command, Stdio}; + use std::thread::sleep; + use std::time::Duration; + let (at, mut ucmd) = at_and_ucmd!(); #[cfg(unix)] diff --git a/util/build-code_coverage.BAT b/util/build-code_coverage.BAT new file mode 100644 index 000000000..25d3f618b --- /dev/null +++ b/util/build-code_coverage.BAT @@ -0,0 +1,59 @@ +@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 new file mode 100644 index 000000000..7ad3165fe --- /dev/null +++ b/util/build-code_coverage.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +# 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 esac +# spell-checker:ignore (utils) genhtml grcov lcov readlink sccache uutils + +FEATURES_OPTION="--features feat_os_unix" + +ME_dir="$(dirname -- $(readlink -fm -- "$0"))" +REPO_main_dir="$(dirname -- "${ME_dir}")" + +cd "${REPO_main_dir}" +echo "[ \"$PWD\" ]" + +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" +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 +genhtml --version 2>/dev/null 1>&2 +if [ $? -eq 0 ]; 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 +if [ $? -ne 0 ]; then exit 1 ; fi diff --git a/util/show-code_coverage.BAT b/util/show-code_coverage.BAT new file mode 100644 index 000000000..222fff382 --- /dev/null +++ b/util/show-code_coverage.BAT @@ -0,0 +1,16 @@ +@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 new file mode 100644 index 000000000..365041434 --- /dev/null +++ b/util/show-code_coverage.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +# spell-checker:ignore (vars) OSID + +ME_dir="$(dirname -- $(readlink -fm -- "$0"))" +REPO_main_dir="$(dirname -- "${ME_dir}")" + +export COVERAGE_REPORT_DIR="${REPO_main_dir}/target/debug/coverage-nix" + +"${ME_dir}/build-code_coverage.sh" +if [ $? -ne 0 ]; then exit 1 ; 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 ; diff --git a/util/show-codecov.BAT b/util/show-codecov.BAT deleted file mode 100644 index 224d870b7..000000000 --- a/util/show-codecov.BAT +++ /dev/null @@ -1,43 +0,0 @@ -@setLocal -@echo off - -@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 RUSTC RUSTFLAGS RUSTUP -@rem ::# spell-checker:ignore (utils) genhtml grcov lcov sccache uutils - -set BIN=uutils - -set "FEATURES_OPTION=--features windows" - -cd "%~dp0.." -call echo [ "%CD%" ] - -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) -set "RUSTFLAGS=-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads" -set RUSTUP_TOOLCHAIN=nightly-x86_64-pc-windows-gnu -call cargo build %FEATURES_OPTION% -call cargo test --no-run %FEATURES_OPTION% -call cargo test --quiet %FEATURES_OPTION% - -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]:/*" -@rem ::# * build LCOV coverage file -call grcov . --output-type lcov --output-path "%COVERAGE_REPORT_DIR%/../lcov.info" --branch %GRCOV_IGNORE_OPTION% -@rem ::# * build HTML -@rem ::# -- use `genhtml` if available for display of additional branch coverage information -call genhtml --version 2>NUL 1>&2 -if NOT ERRORLEVEL 1 ( - call genhtml target/debug/lcov.info --output-directory "%COVERAGE_REPORT_DIR%" --branch-coverage --function-coverage -) else ( - 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% - -call start "" "%COVERAGE_REPORT_DIR%"\index.html diff --git a/util/show-codecov.sh b/util/show-codecov.sh deleted file mode 100755 index 43f93fdea..000000000 --- a/util/show-codecov.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -# spell-checker:ignore (abbrevs/acronyms) HTML gcno llvm -# spell-checker:ignore (jargon) toolchain -# spell-checker:ignore (rust) Ccodegen Cinline Coverflow RUSTC RUSTFLAGS RUSTUP -# spell-checker:ignore (shell) OSID esac -# spell-checker:ignore (utils) genhtml grcov lcov readlink sccache uutils - -BIN=uutils - -FEATURES_OPTION="--features unix" - -cd "$(dirname -- $(readlink -fm -- "$0"/..))" -echo "[ \"$PWD\" ]" - -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 RUSTUP_TOOLCHAIN=nightly -cargo build ${FEATURES_OPTION} -cargo test --no-run ${FEATURES_OPTION} -cargo test --quiet ${FEATURES_OPTION} - -export COVERAGE_REPORT_DIR="target/debug/coverage-nix" -rm -r "${COVERAGE_REPORT_DIR}" 2>/dev/null -mkdir -p "${COVERAGE_REPORT_DIR}" - -# GRCOV_IGNORE_OPTION="--ignore build.rs --ignore \"/cargo/*\" --ignore \"/rustc/*\" --ignore \"${HOME}/.cargo/*\" --ignore \"${PWD}/rustc/*\"" -export GRCOV_IGNORE_OPTION="--ignore build.rs --ignore \"/*\" --ignore \"[A-Za-z]:/*\"" -## FixME: `grcov . ... ${GRCOV_IGNORE_OPTION}` fails, completely ignoring the contents of ${GRCOV_IGNORE_OPTION} -# * build LCOV coverage file -## FixME: grcov . --output-type lcov --output-path "${COVERAGE_REPORT_DIR}/../lcov.info" --branch ${GRCOV_IGNORE_OPTION} -grcov . --output-type lcov --output-path "${COVERAGE_REPORT_DIR}/../lcov.info" --branch --ignore build.rs --ignore '/*' --ignore '[A-Za-z]:/*' -# * build HTML -# -- use `genhtml` if available for display of additional branch coverage information -genhtml --version 2>/dev/null 1>&2 -if [ $? -eq 0 ]; then - genhtml "${COVERAGE_REPORT_DIR}/../lcov.info" --output-directory "${COVERAGE_REPORT_DIR}" --branch-coverage --function-coverage -else - ## FixME: grcov . --output-type html --output-path "${COVERAGE_REPORT_DIR}" --branch ${GRCOV_IGNORE_OPTION} - grcov . --output-type html --output-path "${COVERAGE_REPORT_DIR}" --branch --ignore build.rs --ignore '/*' --ignore '[A-Za-z]:/*' -fi -if [ $? -ne 0 ]; then exit 1 ; fi - -case ";$OSID_tags;" in - *";wsl;"* ) powershell.exe -c "${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 ;