mirror of
https://github.com/uutils/coreutils
synced 2024-11-16 09:48:03 +00:00
Merge branch 'unittests-in-ci' of github.com:tertsdiepraam/coreutils into unittests-in-ci
This commit is contained in:
commit
76edba0e1e
12 changed files with 227 additions and 89 deletions
7
.github/workflows/CICD.yml
vendored
7
.github/workflows/CICD.yml
vendored
|
@ -20,6 +20,13 @@ env:
|
|||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
cargo-deny:
|
||||
name: Style/cargo-deny
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: EmbarkStudios/cargo-deny-action@v1
|
||||
|
||||
style_deps:
|
||||
## ToDO: [2021-11-10; rivy] 'Style/deps' needs more informative output and better integration of results into the GHA dashboard
|
||||
name: Style/deps
|
||||
|
|
2
.github/workflows/GnuTests.yml
vendored
2
.github/workflows/GnuTests.yml
vendored
|
@ -137,6 +137,8 @@ jobs:
|
|||
echo "::error ::Failed to find summary of test results (missing '${SUITE_LOG_FILE}'); failing early"
|
||||
exit 1
|
||||
fi
|
||||
# Compress logs before upload (fails otherwise)
|
||||
gzip ${{ steps.vars.outputs.TEST_LOGS_GLOB }}
|
||||
- name: Reserve SHA1/ID of 'test-summary'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
|
|
@ -94,6 +94,16 @@ uutils: add new utility
|
|||
gitignore: add temporary files
|
||||
```
|
||||
|
||||
## cargo-deny
|
||||
|
||||
This project uses [cargo-deny](https://github.com/EmbarkStudios/cargo-deny/) to
|
||||
detect duplicate dependencies, checks licenses, etc. To run it locally, first
|
||||
install it and then run with:
|
||||
|
||||
```
|
||||
cargo deny --all-features check all
|
||||
```
|
||||
|
||||
## Licensing
|
||||
|
||||
uutils is distributed under the terms of the MIT License; see the `LICENSE` file
|
||||
|
|
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -877,7 +877,7 @@ version = "2.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f37978dab2ca789938a83b2f8bc1ef32db6633af9051a6cd409eff72cbaaa79a"
|
||||
dependencies = [
|
||||
"paste 1.0.6",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1431,31 +1431,12 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
|
||||
dependencies = [
|
||||
"paste-impl",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
|
||||
|
||||
[[package]]
|
||||
name = "paste-impl"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
|
@ -1574,12 +1555,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
|
@ -2559,7 +2534,7 @@ dependencies = [
|
|||
"clap 3.0.10",
|
||||
"coz",
|
||||
"num-traits",
|
||||
"paste 0.1.18",
|
||||
"paste",
|
||||
"quickcheck",
|
||||
"rand",
|
||||
"smallvec",
|
||||
|
|
95
deny.toml
Normal file
95
deny.toml
Normal file
|
@ -0,0 +1,95 @@
|
|||
# spell-checker:ignore SSLeay RUSTSEC
|
||||
|
||||
# This section is considered when running `cargo deny check advisories`
|
||||
# More documentation for the advisories section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
|
||||
[advisories]
|
||||
db-path = "~/.cargo/advisory-db"
|
||||
db-urls = ["https://github.com/rustsec/advisory-db"]
|
||||
vulnerability = "warn"
|
||||
unmaintained = "warn"
|
||||
yanked = "warn"
|
||||
notice = "warn"
|
||||
ignore = [
|
||||
#"RUSTSEC-0000-0000",
|
||||
]
|
||||
|
||||
# This section is considered when running `cargo deny check licenses`
|
||||
# More documentation for the licenses section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
|
||||
[licenses]
|
||||
unlicensed = "deny"
|
||||
allow = [
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"ISC",
|
||||
"BSD-2-Clause",
|
||||
"BSD-2-Clause-FreeBSD",
|
||||
"BSD-3-Clause",
|
||||
"CC0-1.0",
|
||||
"MPL-2.0", # XXX considered copyleft?
|
||||
]
|
||||
copyleft = "deny"
|
||||
allow-osi-fsf-free = "neither"
|
||||
default = "deny"
|
||||
confidence-threshold = 0.8
|
||||
exceptions = [
|
||||
{ allow = ["OpenSSL"], name = "ring" },
|
||||
]
|
||||
|
||||
[[licenses.clarify]]
|
||||
name = "ring"
|
||||
# SPDX considers OpenSSL to encompass both the OpenSSL and SSLeay licenses
|
||||
# https://spdx.org/licenses/OpenSSL.html
|
||||
# ISC - Both BoringSSL and ring use this for their new files
|
||||
# MIT - "Files in third_party/ have their own licenses, as described therein. The MIT
|
||||
# license, for third_party/fiat, which, unlike other third_party directories, is
|
||||
# compiled into non-test libraries, is included below."
|
||||
# OpenSSL - Obviously
|
||||
expression = "ISC AND MIT AND OpenSSL"
|
||||
license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
|
||||
|
||||
# This section is considered when running `cargo deny check bans`.
|
||||
# More documentation about the 'bans' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
|
||||
[bans]
|
||||
multiple-versions = "deny"
|
||||
wildcards = "allow"
|
||||
highlight = "all"
|
||||
|
||||
# For each duplicate dependency, indicate the name of the dependency which
|
||||
# introduces it.
|
||||
# spell-checker: disable
|
||||
skip = [
|
||||
# blake2d_simd
|
||||
{ name = "arrayvec", version = "=0.7.2" },
|
||||
# flimit/unix_socket
|
||||
{ name = "cfg-if", version = "=0.1.10" },
|
||||
# ordered-multimap
|
||||
{ name = "hashbrown", version = "=0.9.1" },
|
||||
# kernel32-sys
|
||||
{ name = "winapi", version = "=0.2.8" },
|
||||
# bindgen 0.59.2
|
||||
{ name = "clap", version = "=2.34.0" },
|
||||
{ name = "strsim", version = "=0.8.0" },
|
||||
{ name = "textwrap", version = "=0.11.0" },
|
||||
{ name = "cpp_common", version = "=0.4.0" },
|
||||
# quickcheck
|
||||
{ name = "env_logger", version = "=0.8.4" },
|
||||
# cpp_*
|
||||
{ name = "memchr", version = "=1.0.2" },
|
||||
{ name = "quote", version = "=0.3.15" },
|
||||
{ name = "unicode-xid", version = "=0.0.4" },
|
||||
# exacl
|
||||
{ name = "nix", version = "=0.21.0" },
|
||||
]
|
||||
# spell-checker: enable
|
||||
|
||||
# This section is considered when running `cargo deny check sources`.
|
||||
# More documentation about the 'sources' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
|
||||
[sources]
|
||||
unknown-registry = "warn"
|
||||
unknown-git = "warn"
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
allow-git = []
|
|
@ -23,7 +23,7 @@ smallvec = "1.7" # TODO(nicoo): Use `union` feature, requires Rust 1.49 or late
|
|||
uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore" }
|
||||
|
||||
[dev-dependencies]
|
||||
paste = "0.1.18"
|
||||
paste = "1.0.6"
|
||||
quickcheck = "1.0.3"
|
||||
|
||||
[[bin]]
|
||||
|
|
|
@ -63,7 +63,7 @@ fn sleep(args: &[&str]) -> UResult<()> {
|
|||
args.iter().try_fold(
|
||||
Duration::new(0, 0),
|
||||
|result, arg| match uucore::parse_time::from_str(&arg[..]) {
|
||||
Ok(m) => Ok(m + result),
|
||||
Ok(m) => Ok(m.saturating_add(result)),
|
||||
Err(f) => Err(USimpleError::new(1, f)),
|
||||
},
|
||||
)?;
|
||||
|
|
|
@ -1162,46 +1162,6 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn split_into_n_chunks_by_line_round_robin<R>(
|
||||
settings: &Settings,
|
||||
reader: &mut R,
|
||||
num_chunks: u64,
|
||||
) -> UResult<()>
|
||||
where
|
||||
R: BufRead,
|
||||
{
|
||||
// This object is responsible for creating the filename for each chunk.
|
||||
let mut filename_iterator = FilenameIterator::new(
|
||||
&settings.prefix,
|
||||
&settings.additional_suffix,
|
||||
settings.suffix_length,
|
||||
settings.suffix_type,
|
||||
);
|
||||
|
||||
// Create one writer for each chunk. This will create each
|
||||
// of the underlying files (if not in `--filter` mode).
|
||||
let mut writers = vec![];
|
||||
for _ in 0..num_chunks {
|
||||
let filename = filename_iterator
|
||||
.next()
|
||||
.ok_or_else(|| USimpleError::new(1, "output file suffixes exhausted"))?;
|
||||
let writer = platform::instantiate_current_writer(&settings.filter, filename.as_str());
|
||||
writers.push(writer);
|
||||
}
|
||||
|
||||
let num_chunks: usize = num_chunks.try_into().unwrap();
|
||||
for (i, line_result) in reader.lines().enumerate() {
|
||||
let line = line_result.unwrap();
|
||||
let maybe_writer = writers.get_mut(i % num_chunks);
|
||||
let writer = maybe_writer.unwrap();
|
||||
let bytes = line.as_bytes();
|
||||
writer.write_all(bytes)?;
|
||||
writer.write_all(b"\n")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn split(settings: &Settings) -> UResult<()> {
|
||||
let mut reader = BufReader::new(if settings.input == "-" {
|
||||
Box::new(stdin()) as Box<dyn Read>
|
||||
|
@ -1228,9 +1188,6 @@ fn split(settings: &Settings) -> UResult<()> {
|
|||
let chunk_number = chunk_number - 1;
|
||||
kth_chunk_by_line(settings, &mut reader, chunk_number, num_chunks)
|
||||
}
|
||||
Strategy::Number(NumberType::RoundRobin(num_chunks)) => {
|
||||
split_into_n_chunks_by_line_round_robin(settings, &mut reader, num_chunks)
|
||||
}
|
||||
Strategy::Number(_) => Err(USimpleError::new(1, "-n mode not yet fully implemented")),
|
||||
Strategy::Lines(chunk_size) => {
|
||||
let mut writer = LineChunkWriter::new(chunk_size, settings)
|
||||
|
|
|
@ -6,11 +6,39 @@
|
|||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (vars) NANOS numstr
|
||||
//! Parsing a duration from a string.
|
||||
//!
|
||||
//! Use the [`from_str`] function to parse a [`Duration`] from a string.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::display::Quotable;
|
||||
|
||||
/// Parse a duration from a string.
|
||||
///
|
||||
/// The string may contain only a number, like "123" or "4.5", or it
|
||||
/// may contain a number with a unit specifier, like "123s" meaning
|
||||
/// one hundred twenty three seconds or "4.5d" meaning four and a half
|
||||
/// days. If no unit is specified, the unit is assumed to be seconds.
|
||||
///
|
||||
/// This function uses [`Duration::saturating_mul`] to compute the
|
||||
/// number of seconds, so it does not overflow. If overflow would have
|
||||
/// occurred, [`Duration::MAX`] is returned instead.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function returns an error if the input string is empty, the
|
||||
/// input is not a valid number, or the unit specifier is invalid or
|
||||
/// unknown.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::time::Duration;
|
||||
/// use uucore::parse_time::from_str;
|
||||
/// assert_eq!(from_str("123"), Ok(Duration::from_secs(123)));
|
||||
/// assert_eq!(from_str("2d"), Ok(Duration::from_secs(60 * 60 * 24 * 2)));
|
||||
/// ```
|
||||
pub fn from_str(string: &str) -> Result<Duration, String> {
|
||||
let len = string.len();
|
||||
if len == 0 {
|
||||
|
@ -39,5 +67,42 @@ pub fn from_str(string: &str) -> Result<Duration, String> {
|
|||
let whole_secs = num.trunc();
|
||||
let nanos = (num.fract() * (NANOS_PER_SEC as f64)).trunc();
|
||||
let duration = Duration::new(whole_secs as u64, nanos as u32);
|
||||
Ok(duration * times)
|
||||
Ok(duration.saturating_mul(times))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::parse_time::from_str;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_no_units() {
|
||||
assert_eq!(from_str("123"), Ok(Duration::from_secs(123)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_units() {
|
||||
assert_eq!(from_str("2d"), Ok(Duration::from_secs(60 * 60 * 24 * 2)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_saturating_mul() {
|
||||
assert_eq!(from_str("9223372036854775808d"), Ok(Duration::MAX));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_empty() {
|
||||
assert!(from_str("").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_invalid_unit() {
|
||||
assert!(from_str("123X").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_invalid_magnitude() {
|
||||
assert!(from_str("12abc3s").is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore dont
|
||||
use crate::common::util::*;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -115,3 +116,28 @@ fn test_sleep_sum_duration_many() {
|
|||
fn test_sleep_wrong_time() {
|
||||
new_ucmd!().args(&["0.1s", "abc"]).fails();
|
||||
}
|
||||
|
||||
// TODO These tests would obviously block for a very long time. We
|
||||
// only want to verify that there is no error here, so we could just
|
||||
// figure out a way to terminate the child process after a short
|
||||
// period of time.
|
||||
|
||||
// #[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_dont_overflow() {
|
||||
new_ucmd!()
|
||||
.arg("9223372036854775808d")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
// #[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_sum_overflow() {
|
||||
new_ucmd!()
|
||||
.args(&["100000000000000d", "100000000000000d", "100000000000000d"])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
|
|
@ -605,19 +605,3 @@ fn test_line_bytes() {
|
|||
assert_eq!(at.read("xac"), "cccc\ndd\n");
|
||||
assert_eq!(at.read("xad"), "ee\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round_robin() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
let file_read = |f| {
|
||||
let mut s = String::new();
|
||||
at.open(f).read_to_string(&mut s).unwrap();
|
||||
s
|
||||
};
|
||||
|
||||
ucmd.args(&["-n", "r/2", "fivelines.txt"]).succeeds();
|
||||
|
||||
assert_eq!(file_read("xaa"), "1\n3\n5\n");
|
||||
assert_eq!(file_read("xab"), "2\n4\n");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore dont
|
||||
use crate::common::util::*;
|
||||
|
||||
// FIXME: this depends on the system having true and false in PATH
|
||||
|
@ -64,3 +65,19 @@ fn test_preserve_status() {
|
|||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dont_overflow() {
|
||||
new_ucmd!()
|
||||
.args(&["9223372036854775808d", "sleep", "0"])
|
||||
.succeeds()
|
||||
.code_is(0)
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
new_ucmd!()
|
||||
.args(&["-k", "9223372036854775808d", "10", "sleep", "0"])
|
||||
.succeeds()
|
||||
.code_is(0)
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue