1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Merge branch 'master' into blake2b_simd

This commit is contained in:
Sylvestre Ledru 2021-05-30 09:29:40 +02:00 committed by GitHub
commit 13b2a4afd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
123 changed files with 1511 additions and 1418 deletions

View file

@ -11,7 +11,7 @@ env:
PROJECT_NAME: coreutils
PROJECT_DESC: "Core universal (cross-platform) utilities"
PROJECT_AUTH: "uutils"
RUST_MIN_SRV: "1.40.0" ## v1.40.0
RUST_MIN_SRV: "1.43.1" ## v1.43.0
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]
@ -94,7 +94,7 @@ jobs:
run: |
# `clippy` testing
# * convert any warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>
S=$(cargo clippy ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::warning file=\2,line=\3,col=\4::WARNING: \`cargo clippy\`: \1/p;" -e '}' ; }
S=$(cargo +nightly clippy --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::warning file=\2,line=\3,col=\4::WARNING: \`cargo clippy\`: \1/p;" -e '}' ; }
min_version:
name: MinRustV # Minimum supported rust version
@ -614,3 +614,20 @@ jobs:
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
name: codecov-umbrella
fail_ci_if_error: false
spellcheck:
name: Spell Check
runs-on: ${{ matrix.job.os }}
strategy:
matrix:
job:
- { os: ubuntu-latest }
steps:
- uses: actions/checkout@v1
- name: Install/setup prerequisites
shell: bash
run: |
sudo apt-get -y update ; sudo apt-get -y install npm ; sudo npm install cspell -g;
- name: Run `cspell`
shell: bash
run: |
cspell --config .vscode/cSpell.json --no-summary --no-progress $( git ls-files | grep "\.\(rs\|md\)" ) | sed "s/\(.*\):\(.*\):\(.*\) - \(.*\)/::warning file=\1,line=\2,col=\3::cspell: \4/" || true

430
Cargo.lock generated
View file

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
@ -138,15 +140,8 @@ dependencies = [
"lazy_static",
"memchr 2.4.0",
"regex-automata",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
[[package]]
name = "byte-tools"
version = "0.2.0"
@ -159,15 +154,6 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cast"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374"
dependencies = [
"rustc_version",
]
[[package]]
name = "cc"
version = "1.0.67"
@ -258,7 +244,6 @@ dependencies = [
"rand 0.7.3",
"regex",
"sha1",
"tempdir",
"tempfile",
"textwrap",
"time",
@ -289,7 +274,6 @@ dependencies = [
"uu_expand",
"uu_expr",
"uu_factor",
"uu_factor_benches",
"uu_false",
"uu_fmt",
"uu_fold",
@ -468,42 +452,6 @@ dependencies = [
"unicode-xid 0.0.4",
]
[[package]]
name = "criterion"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools 0.10.0",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d"
dependencies = [
"cast",
"itertools 0.9.0",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
@ -549,28 +497,6 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "csv"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
dependencies = [
"memchr 2.4.0",
]
[[package]]
name = "ctor"
version = "0.1.20"
@ -711,7 +637,18 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
@ -801,15 +738,6 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.10.0"
@ -819,21 +747,6 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "js-sys"
version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -956,6 +869,17 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "num-bigint"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@ -1025,12 +949,6 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "ouroboros"
version = "0.9.3"
@ -1082,15 +1000,6 @@ dependencies = [
"proc-macro-hack",
]
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pkg-config"
version = "0.3.19"
@ -1107,34 +1016,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "plotters"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590"
[[package]]
name = "plotters-svg"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211"
dependencies = [
"plotters-backend",
]
[[package]]
name = "ppv-lite86"
version = "0.2.10"
@ -1225,19 +1106,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi 0.3.9",
]
[[package]]
name = "rand"
version = "0.5.6"
@ -1257,14 +1125,26 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc",
"rand_hc 0.2.0",
"rand_pcg",
]
[[package]]
name = "rand"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [
"libc",
"rand_chacha 0.3.0",
"rand_core 0.6.2",
"rand_hc 0.3.0",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
@ -1275,6 +1155,16 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
"rand_core 0.6.2",
]
[[package]]
name = "rand_core"
version = "0.3.1"
@ -1296,7 +1186,16 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
"getrandom 0.1.16",
]
[[package]]
name = "rand_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
dependencies = [
"getrandom 0.2.3",
]
[[package]]
@ -1308,6 +1207,15 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core 0.6.2",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
@ -1342,15 +1250,6 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
@ -1422,21 +1321,6 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
[[package]]
name = "rustc_version"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
dependencies = [
"semver 0.11.0",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "same-file"
version = "1.0.6"
@ -1458,16 +1342,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser 0.7.0",
]
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser 0.10.2",
"semver-parser",
]
[[package]]
@ -1476,53 +1351,6 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "serde"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
[[package]]
name = "serde_cbor"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha1"
version = "0.6.0"
@ -1615,26 +1443,16 @@ dependencies = [
"unicode-xid 0.2.2",
]
[[package]]
name = "tempdir"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
dependencies = [
"rand 0.4.6",
"remove_dir_all",
]
[[package]]
name = "tempfile"
version = "3.1.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"libc",
"rand 0.7.3",
"redox_syscall 0.1.57",
"rand 0.8.3",
"redox_syscall 0.2.8",
"remove_dir_all",
"winapi 0.3.9",
]
@ -1723,28 +1541,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "typenum"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
@ -2031,6 +1833,8 @@ name = "uu_expr"
version = "0.0.6"
dependencies = [
"libc",
"num-bigint",
"num-traits",
"onig",
"uucore",
"uucore_procs",
@ -2040,6 +1844,7 @@ dependencies = [
name = "uu_factor"
version = "0.0.6"
dependencies = [
"clap",
"coz",
"num-traits",
"paste",
@ -2050,17 +1855,6 @@ dependencies = [
"uucore_procs",
]
[[package]]
name = "uu_factor_benches"
version = "0.0.0"
dependencies = [
"array-init",
"criterion",
"rand 0.7.3",
"rand_chacha",
"uu_factor",
]
[[package]]
name = "uu_false"
version = "0.0.6"
@ -2539,8 +2333,8 @@ dependencies = [
"ouroboros",
"rand 0.7.3",
"rayon",
"semver 0.9.0",
"tempdir",
"semver",
"tempfile",
"unicode-width",
"uucore",
"uucore_procs",
@ -2882,68 +2676,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-bindgen"
version = "0.2.74"
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote 1.0.9",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [
"quote 1.0.9",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "web-sys"
version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
dependencies = [
"js-sys",
"wasm-bindgen",
]
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wild"

View file

@ -325,7 +325,8 @@ who = { optional=true, version="0.0.6", package="uu_who", path="src/uu/who"
whoami = { optional=true, version="0.0.6", package="uu_whoami", path="src/uu/whoami" }
yes = { optional=true, version="0.0.6", package="uu_yes", path="src/uu/yes" }
factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" }
# this breaks clippy linting with: "tests/by-util/test_factor_benches.rs: No such file or directory (os error 2)"
# factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" }
#
# * pinned transitive dependencies
@ -342,14 +343,11 @@ pretty_assertions = "0.7.2"
rand = "0.7"
regex = "1.0"
sha1 = { version="0.6", features=["std"] }
## tempfile 3.2 depends on recent version of rand which depends on getrandom v0.2 which has compiler errors for MinRustV v1.32.0
## min dep for tempfile = Rustc 1.40
tempfile = "= 3.1.0"
tempfile = "3.2.0"
time = "0.1"
unindent = "0.1"
uucore = { version=">=0.0.8", package="uucore", path="src/uucore", features=["entries"] }
walkdir = "2.2"
tempdir = "0.3"
[target.'cfg(unix)'.dev-dependencies]
rust-users = { version="0.10", package="users" }

View file

@ -39,7 +39,7 @@ to compile anywhere, and this is as good a way as any to try and learn it.
### Rust Version
uutils follows Rust's release channels and is tested against stable, beta and nightly.
The current oldest supported version of the Rust compiler is `1.40.0`.
The current oldest supported version of the Rust compiler is `1.43.1`.
On both Windows and Redox, only the nightly version is tested currently.

1
clippy.toml Normal file
View file

@ -0,0 +1 @@
msrv = "1.43.1"

View file

@ -136,7 +136,8 @@ fn basename(fullname: &str, suffix: &str) -> String {
}
}
#[allow(clippy::manual_strip)] // can be replaced with strip_suffix once the minimum rust version is 1.45
// can be replaced with strip_suffix once MSRV is 1.45
#[allow(clippy::manual_strip)]
fn strip_suffix(name: &str, suffix: &str) -> String {
if name == suffix {
return name.to_owned();

View file

@ -232,6 +232,7 @@ fn get_usage() -> String {
static OPT_ARCHIVE: &str = "archive";
static OPT_ATTRIBUTES_ONLY: &str = "attributes-only";
static OPT_BACKUP: &str = "backup";
static OPT_BACKUP_NO_ARG: &str = "b";
static OPT_CLI_SYMBOLIC_LINKS: &str = "cli-symbolic-links";
static OPT_CONTEXT: &str = "context";
static OPT_COPY_CONTENTS: &str = "copy-contents";
@ -357,7 +358,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.help("remove each existing destination file before attempting to open it \
(contrast with --force). On Windows, current only works for writeable files."))
.arg(Arg::with_name(OPT_BACKUP)
.short("b")
.long(OPT_BACKUP)
.help("make a backup of each existing destination file")
.takes_value(true)
@ -366,6 +366,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.possible_values(backup_control::BACKUP_CONTROL_VALUES)
.value_name("CONTROL")
)
.arg(Arg::with_name(OPT_BACKUP_NO_ARG)
.short(OPT_BACKUP_NO_ARG)
.help("like --backup but does not accept an argument")
)
.arg(Arg::with_name(OPT_SUFFIX)
.short("S")
.long(OPT_SUFFIX)
@ -592,7 +596,7 @@ impl Options {
|| matches.is_present(OPT_ARCHIVE);
let backup_mode = backup_control::determine_backup_mode(
matches.is_present(OPT_BACKUP),
matches.is_present(OPT_BACKUP_NO_ARG) || matches.is_present(OPT_BACKUP),
matches.value_of(OPT_BACKUP),
);
let backup_suffix = backup_control::determine_backup_suffix(matches.value_of(OPT_SUFFIX));
@ -665,8 +669,8 @@ impl Options {
}
},
backup: backup_mode,
backup_suffix: backup_suffix,
overwrite: overwrite,
backup_suffix,
overwrite,
no_target_dir,
preserve_attributes,
recursive,
@ -1085,7 +1089,7 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu
}
#[cfg(not(windows))]
#[allow(clippy::unnecessary_wraps)] // needed for windows version
#[allow(clippy::unnecessary_unwrap)] // needed for windows version
fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
match std::os::unix::fs::symlink(source, dest).context(context) {
Ok(_) => Ok(()),
@ -1104,7 +1108,7 @@ fn context_for(src: &Path, dest: &Path) -> String {
/// Implements a simple backup copy for the destination file.
/// TODO: for the backup, should this function be replaced by `copy_file(...)`?
fn backup_dest(dest: &Path, backup_path: &PathBuf) -> CopyResult<PathBuf> {
fn backup_dest(dest: &Path, backup_path: &Path) -> CopyResult<PathBuf> {
fs::copy(dest, &backup_path)?;
Ok(backup_path.into())
}

View file

@ -124,12 +124,7 @@ where
// split the file based on patterns
for pattern in patterns.into_iter() {
let pattern_as_str = pattern.to_string();
#[allow(clippy::match_like_matches_macro)]
let is_skip = if let patterns::Pattern::SkipToMatch(_, _, _) = pattern {
true
} else {
false
};
let is_skip = matches!(pattern, patterns::Pattern::SkipToMatch(_, _, _));
match pattern {
patterns::Pattern::UpToLine(n, ex) => {
let mut up_to_line = n;
@ -488,10 +483,11 @@ where
/// Shrink the buffer so that its length is equal to the set size, returning an iterator for
/// the elements that were too much.
fn shrink_buffer_to_size(&mut self) -> impl Iterator<Item = String> + '_ {
let mut shrink_offset = 0;
if self.buffer.len() > self.size {
shrink_offset = self.buffer.len() - self.size;
}
let shrink_offset = if self.buffer.len() > self.size {
self.buffer.len() - self.size
} else {
0
};
self.buffer
.drain(..shrink_offset)
.map(|(_, line)| line.unwrap())

View file

@ -16,6 +16,8 @@ path = "src/expr.rs"
[dependencies]
libc = "0.2.42"
num-bigint = "0.4.0"
num-traits = "0.2.14"
onig = "~4.3.2"
uucore = { version=">=0.0.8", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }

View file

@ -12,6 +12,8 @@
// spell-checker:ignore (ToDO) binop binops ints paren prec
use num_bigint::BigInt;
use num_traits::{One, Zero};
use onig::{Regex, RegexOptions, Syntax};
use crate::tokens::Token;
@ -39,20 +41,17 @@ impl AstNode {
for _ in 0..depth {
print!("\t",);
}
match *self {
AstNode::Leaf {
ref token_idx,
ref value,
} => println!(
match self {
AstNode::Leaf { token_idx, value } => println!(
"Leaf( {} ) at #{} ( evaluate -> {:?} )",
value,
token_idx,
self.evaluate()
),
AstNode::Node {
ref token_idx,
ref op_type,
ref operands,
token_idx,
op_type,
operands,
} => {
println!(
"Node( {} ) at #{} (evaluate -> {:?})",
@ -81,36 +80,33 @@ impl AstNode {
})
}
pub fn evaluate(&self) -> Result<String, String> {
match *self {
AstNode::Leaf { ref value, .. } => Ok(value.clone()),
AstNode::Node { ref op_type, .. } => match self.operand_values() {
match self {
AstNode::Leaf { value, .. } => Ok(value.clone()),
AstNode::Node { op_type, .. } => match self.operand_values() {
Err(reason) => Err(reason),
Ok(operand_values) => match op_type.as_ref() {
"+" => infix_operator_two_ints(
|a: i64, b: i64| checked_binop(|| a.checked_add(b), "+"),
&operand_values,
),
"-" => infix_operator_two_ints(
|a: i64, b: i64| checked_binop(|| a.checked_sub(b), "-"),
&operand_values,
),
"*" => infix_operator_two_ints(
|a: i64, b: i64| checked_binop(|| a.checked_mul(b), "*"),
&operand_values,
),
"+" => {
infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a + b), &operand_values)
}
"-" => {
infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a - b), &operand_values)
}
"*" => {
infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a * b), &operand_values)
}
"/" => infix_operator_two_ints(
|a: i64, b: i64| {
if b == 0 {
|a: BigInt, b: BigInt| {
if b.is_zero() {
Err("division by zero".to_owned())
} else {
checked_binop(|| a.checked_div(b), "/")
Ok(a / b)
}
},
&operand_values,
),
"%" => infix_operator_two_ints(
|a: i64, b: i64| {
if b == 0 {
|a: BigInt, b: BigInt| {
if b.is_zero() {
Err("division by zero".to_owned())
} else {
Ok(a % b)
@ -119,32 +115,32 @@ impl AstNode {
&operand_values,
),
"=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok(bool_as_int(a == b)),
|a: BigInt, b: BigInt| Ok(bool_as_int(a == b)),
|a: &String, b: &String| Ok(bool_as_string(a == b)),
&operand_values,
),
"!=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok(bool_as_int(a != b)),
|a: BigInt, b: BigInt| Ok(bool_as_int(a != b)),
|a: &String, b: &String| Ok(bool_as_string(a != b)),
&operand_values,
),
"<" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok(bool_as_int(a < b)),
|a: BigInt, b: BigInt| Ok(bool_as_int(a < b)),
|a: &String, b: &String| Ok(bool_as_string(a < b)),
&operand_values,
),
">" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok(bool_as_int(a > b)),
|a: BigInt, b: BigInt| Ok(bool_as_int(a > b)),
|a: &String, b: &String| Ok(bool_as_string(a > b)),
&operand_values,
),
"<=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok(bool_as_int(a <= b)),
|a: BigInt, b: BigInt| Ok(bool_as_int(a <= b)),
|a: &String, b: &String| Ok(bool_as_string(a <= b)),
&operand_values,
),
">=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok(bool_as_int(a >= b)),
|a: BigInt, b: BigInt| Ok(bool_as_int(a >= b)),
|a: &String, b: &String| Ok(bool_as_string(a >= b)),
&operand_values,
),
@ -161,7 +157,7 @@ impl AstNode {
}
}
pub fn operand_values(&self) -> Result<Vec<String>, String> {
if let AstNode::Node { ref operands, .. } = *self {
if let AstNode::Node { operands, .. } = self {
let mut out = Vec::with_capacity(operands.len());
for operand in operands {
match operand.evaluate() {
@ -217,9 +213,9 @@ fn maybe_dump_ast(result: &Result<Box<AstNode>, String>) {
if let Ok(debug_var) = env::var("EXPR_DEBUG_AST") {
if debug_var == "1" {
println!("EXPR_DEBUG_AST");
match *result {
Ok(ref ast) => ast.debug_dump(),
Err(ref reason) => println!("\terr: {:?}", reason),
match result {
Ok(ast) => ast.debug_dump(),
Err(reason) => println!("\terr: {:?}", reason),
}
}
}
@ -304,7 +300,7 @@ fn push_token_to_either_stack(
out_stack: &mut TokenStack,
op_stack: &mut TokenStack,
) -> Result<(), String> {
let result = match *token {
let result = match token {
Token::Value { .. } => {
out_stack.push((token_idx, token.clone()));
Ok(())
@ -420,24 +416,14 @@ fn move_till_match_paren(
}
}
fn checked_binop<F: Fn() -> Option<T>, T>(cb: F, op: &str) -> Result<T, String> {
match cb() {
Some(v) => Ok(v),
None => Err(format!("{}: Numerical result out of range", op)),
}
}
fn infix_operator_two_ints<F>(f: F, values: &[String]) -> Result<String, String>
where
F: Fn(i64, i64) -> Result<i64, String>,
F: Fn(BigInt, BigInt) -> Result<BigInt, String>,
{
assert!(values.len() == 2);
if let Ok(left) = values[0].parse::<i64>() {
if let Ok(right) = values[1].parse::<i64>() {
return match f(left, right) {
Ok(result) => Ok(result.to_string()),
Err(reason) => Err(reason),
};
if let Ok(left) = values[0].parse::<BigInt>() {
if let Ok(right) = values[1].parse::<BigInt>() {
return f(left, right).map(|big_int| big_int.to_string());
}
}
Err("Expected an integer operand".to_string())
@ -449,13 +435,14 @@ fn infix_operator_two_ints_or_two_strings<FI, FS>(
values: &[String],
) -> Result<String, String>
where
FI: Fn(i64, i64) -> Result<i64, String>,
FI: Fn(BigInt, BigInt) -> Result<u8, String>,
FS: Fn(&String, &String) -> Result<String, String>,
{
assert!(values.len() == 2);
if let (Some(a_int), Some(b_int)) =
(values[0].parse::<i64>().ok(), values[1].parse::<i64>().ok())
{
if let (Some(a_int), Some(b_int)) = (
values[0].parse::<BigInt>().ok(),
values[1].parse::<BigInt>().ok(),
) {
match fi(a_int, b_int) {
Ok(result) => Ok(result.to_string()),
Err(reason) => Err(reason),
@ -541,7 +528,7 @@ fn prefix_operator_substr(values: &[String]) -> String {
subj.chars().skip(idx).take(len).collect()
}
fn bool_as_int(b: bool) -> i64 {
fn bool_as_int(b: bool) -> u8 {
if b {
1
} else {
@ -559,8 +546,8 @@ fn value_as_bool(s: &str) -> bool {
if s.is_empty() {
return false;
}
match s.parse::<i64>() {
Ok(n) => n != 0,
match s.parse::<BigInt>() {
Ok(n) => n.is_one(),
Err(_) => true,
}
}

View file

@ -18,6 +18,8 @@
// spell-checker:ignore (ToDO) paren
use num_bigint::BigInt;
#[derive(Debug, Clone)]
pub enum Token {
Value {
@ -51,24 +53,19 @@ impl Token {
}
fn is_infix_plus(&self) -> bool {
match *self {
Token::InfixOp { ref value, .. } => value == "+",
match self {
Token::InfixOp { value, .. } => value == "+",
_ => false,
}
}
fn is_a_number(&self) -> bool {
match *self {
Token::Value { ref value, .. } => value.parse::<i64>().is_ok(),
match self {
Token::Value { value, .. } => value.parse::<BigInt>().is_ok(),
_ => false,
}
}
fn is_a_close_paren(&self) -> bool {
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
match *self {
Token::ParClose => true,
_ => false,
}
matches!(*self, Token::ParClose)
}
}
@ -147,7 +144,7 @@ fn push_token_if_not_escaped(acc: &mut Vec<(usize, Token)>, tok_idx: usize, toke
// Smells heuristics... :(
let prev_is_plus = match acc.last() {
None => false,
Some(ref t) => t.1.is_infix_plus(),
Some(t) => t.1.is_infix_plus(),
};
let should_use_as_escaped = if prev_is_plus && acc.len() >= 2 {
let pre_prev = &acc[acc.len() - 2];

View file

@ -21,6 +21,7 @@ rand = { version = "0.7", features = ["small_rng"] }
smallvec = { version = "0.6.14, < 1.0" }
uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore" }
uucore_procs = { version = ">=0.0.5", package = "uucore_procs", path = "../../uucore_procs" }
clap = "2.33"
[dev-dependencies]
paste = "0.1.18"

View file

@ -30,7 +30,7 @@ impl Iterator for Sieve {
#[inline]
fn next(&mut self) -> Option<u64> {
while let Some(n) = self.inner.next() {
for n in &mut self.inner {
let mut prime = true;
while let Some((next, inc)) = self.filts.peek() {
// need to keep checking the min element of the heap

View file

@ -13,18 +13,21 @@ use std::error::Error;
use std::io::{self, stdin, stdout, BufRead, Write};
mod factor;
use clap::{App, Arg};
pub use factor::*;
use uucore::InvalidEncodingHandling;
mod miller_rabin;
pub mod numeric;
mod rho;
pub mod table;
static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
static VERSION: &str = env!("CARGO_PKG_VERSION");
static SUMMARY: &str = "Print the prime factors of the given NUMBER(s).
If none are specified, read from standard input.";
static LONG_HELP: &str = "";
mod options {
pub static NUMBER: &str = "NUMBER";
}
fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box<dyn Error>> {
num_str
@ -34,14 +37,21 @@ fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box<dy
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let matches = app!(SYNTAX, SUMMARY, LONG_HELP).parse(
args.collect_str(InvalidEncodingHandling::Ignore)
.accept_any(),
);
let matches = App::new(executable!())
.version(VERSION)
.about(SUMMARY)
.arg(Arg::with_name(options::NUMBER).multiple(true))
.get_matches_from(args);
let stdout = stdout();
let mut w = io::BufWriter::new(stdout.lock());
if matches.free.is_empty() {
if let Some(values) = matches.values_of(options::NUMBER) {
for number in values {
if let Err(e) = print_factors_str(number, &mut w) {
show_warning!("{}: {}", number, e);
}
}
} else {
let stdin = stdin();
for line in stdin.lock().lines() {
@ -51,12 +61,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}
}
}
} else {
for number in &matches.free {
if let Err(e) = print_factors_str(number, &mut w) {
show_warning!("{}: {}", number, e);
}
}
}
if let Err(e) = w.flush() {

View file

@ -264,12 +264,9 @@ impl<'a> ParagraphStream<'a> {
return false;
}
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
l_slice[..colon_posn].chars().all(|x| match x as usize {
y if !(33..=126).contains(&y) => false,
_ => true,
})
l_slice[..colon_posn]
.chars()
.all(|x| !matches!(x as usize, y if !(33..=126).contains(&y)))
}
}
}
@ -541,12 +538,7 @@ impl<'a> WordSplit<'a> {
}
fn is_punctuation(c: char) -> bool {
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
match c {
'!' | '.' | '?' => true,
_ => false,
}
matches!(c, '!' | '.' | '?')
}
}

View file

@ -50,14 +50,23 @@ struct Options {
}
fn is_custom_binary(program: &str) -> bool {
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
match program {
"md5sum" | "sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum"
| "sha3sum" | "sha3-224sum" | "sha3-256sum" | "sha3-384sum" | "sha3-512sum"
| "shake128sum" | "shake256sum" | "b2sum" => true,
_ => false,
}
matches!(
program,
"md5sum"
| "sha1sum"
| "sha224sum"
| "sha256sum"
| "sha384sum"
| "sha512sum"
| "sha3sum"
| "sha3-224sum"
| "sha3-256sum"
| "sha3-384sum"
| "sha3-512sum"
| "shake128sum"
| "shake256sum"
| "b2sum"
)
}
#[allow(clippy::cognitive_complexity)]

View file

@ -14,7 +14,7 @@ pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>
let mut num_end = 0usize;
let mut has_num = false;
let mut last_char = 0 as char;
while let Some((n, c)) = chars.next() {
for (n, c) in &mut chars {
if c.is_numeric() {
has_num = true;
num_end = n;
@ -109,7 +109,7 @@ pub fn parse_num(src: &str) -> Result<(usize, bool), ParseError> {
let mut num_end = 0usize;
let mut last_char = 0 as char;
let mut num_count = 0usize;
while let Some((n, c)) = chars.next() {
for (n, c) in &mut chars {
if c.is_numeric() {
num_end = n;
num_count += 1;

View file

@ -520,6 +520,7 @@ fn copy_file_to_file(file: &Path, target: &Path, b: &Behavior) -> i32 {
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
#[allow(clippy::cognitive_complexity)]
fn copy(from: &Path, to: &Path, b: &Behavior) -> Result<(), ()> {
if b.compare && !need_copy(from, to, b) {
return Ok(());

View file

@ -218,6 +218,7 @@ struct LongFormat {
}
impl Config {
#[allow(clippy::cognitive_complexity)]
fn from(options: clap::ArgMatches) -> Config {
let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) {
(
@ -1614,7 +1615,7 @@ fn display_date(metadata: &Metadata, config: &Config) -> String {
Some(time) => {
//Date is recent if from past 6 months
//According to GNU a Gregorian year has 365.2425 * 24 * 60 * 60 == 31556952 seconds on the average.
let recent = time + chrono::Duration::seconds(31556952 / 2) > chrono::Local::now();
let recent = time + chrono::Duration::seconds(31_556_952 / 2) > chrono::Local::now();
match config.time_style {
TimeStyle::FullIso => time.format("%Y-%m-%d %H:%M:%S.%f %z"),
@ -1696,7 +1697,6 @@ fn file_is_executable(md: &Metadata) -> bool {
md.mode() & ((S_IXUSR | S_IXGRP | S_IXOTH) as u32) != 0
}
#[allow(clippy::clippy::collapsible_else_if)]
fn classify_file(path: &PathData) -> Option<char> {
let file_type = path.file_type()?;

View file

@ -15,14 +15,11 @@ use clap::{App, Arg};
use std::env;
use std::iter;
use std::mem::forget;
use std::path::{is_separator, PathBuf};
use rand::Rng;
use tempfile::Builder;
mod tempdir;
static ABOUT: &str = "create a temporary file or directory.";
static VERSION: &str = env!("CARGO_PKG_VERSION");
@ -213,50 +210,48 @@ pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) ->
0
}
fn exec(
tmpdir: PathBuf,
prefix: &str,
rand: usize,
suffix: &str,
make_dir: bool,
quiet: bool,
) -> i32 {
if make_dir {
match tempdir::new_in(&tmpdir, prefix, rand, suffix) {
Ok(ref f) => {
println!("{}", f);
return 0;
}
Err(e) => {
if !quiet {
show_error!("{}: {}", e, tmpdir.display());
}
return 1;
}
}
}
fn exec(dir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool, quiet: bool) -> i32 {
let res = if make_dir {
let tmpdir = Builder::new()
.prefix(prefix)
.rand_bytes(rand)
.suffix(suffix)
.tempdir_in(&dir);
// `into_path` consumes the TempDir without removing it
tmpdir.map(|d| d.into_path().to_string_lossy().to_string())
} else {
let tmpfile = Builder::new()
.prefix(prefix)
.rand_bytes(rand)
.suffix(suffix)
.tempfile_in(tmpdir);
let tmpfile = match tmpfile {
Ok(f) => f,
.tempfile_in(&dir);
match tmpfile {
Ok(f) => {
// `keep` ensures that the file is not deleted
match f.keep() {
Ok((_, p)) => Ok(p.to_string_lossy().to_string()),
Err(e) => {
if !quiet {
show_error!("failed to create tempfile: {}", e);
}
show_error!("'{}': {}", dir.display(), e);
return 1;
}
}
}
Err(x) => Err(x),
}
};
let tmpname = tmpfile.path().to_string_lossy().to_string();
println!("{}", tmpname);
// CAUTION: Not to call `drop` of tmpfile, which removes the tempfile,
// I call a dangerous function `forget`.
forget(tmpfile);
match res {
Ok(ref f) => {
println!("{}", f);
0
}
Err(e) => {
if !quiet {
show_error!("{}: {}", e, dir.display());
}
1
}
}
}

View file

@ -1,51 +0,0 @@
// spell-checker:ignore (ToDO) tempdir tmpdir
// Mainly taken from crate `tempdir`
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::io::Result as IOResult;
use std::io::{Error, ErrorKind};
use std::path::Path;
// How many times should we (re)try finding an unused random name? It should be
// enough that an attacker will run out of luck before we run out of patience.
const NUM_RETRIES: u32 = 1 << 31;
#[cfg(any(unix, target_os = "redox"))]
fn create_dir<P: AsRef<Path>>(path: P) -> IOResult<()> {
use std::fs::DirBuilder;
use std::os::unix::fs::DirBuilderExt;
DirBuilder::new().mode(0o700).create(path)
}
#[cfg(windows)]
fn create_dir<P: AsRef<Path>>(path: P) -> IOResult<()> {
::std::fs::create_dir(path)
}
pub fn new_in<P: AsRef<Path>>(
tmpdir: P,
prefix: &str,
rand: usize,
suffix: &str,
) -> IOResult<String> {
let mut rng = thread_rng();
for _ in 0..NUM_RETRIES {
let rand_chars: String = rng.sample_iter(&Alphanumeric).take(rand).collect();
let leaf = format!("{}{}{}", prefix, rand_chars, suffix);
let path = tmpdir.as_ref().join(&leaf);
match create_dir(&path) {
Ok(_) => return Ok(path.to_string_lossy().into_owned()),
Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {}
Err(e) => return Err(e),
}
}
Err(Error::new(
ErrorKind::AlreadyExists,
"too many temporary directories already exist",
))
}

View file

@ -85,12 +85,7 @@ fn od_format_type(type_char: FormatType, byte_size: u8) -> Option<FormatterItemI
}
fn od_argument_with_option(ch: char) -> bool {
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
match ch {
'A' | 'j' | 'N' | 'S' | 'w' => true,
_ => false,
}
matches!(ch, 'A' | 'j' | 'N' | 'S' | 'w')
}
/// Parses format flags from command line

View file

@ -76,7 +76,7 @@ pub fn parse_inputs(matches: &dyn CommandLineOpts) -> Result<CommandLineInputs,
input_strings.push("-");
}
Ok(CommandLineInputs::FileNames(
input_strings.iter().map(|s| s.to_string()).collect(),
input_strings.iter().map(|&s| s.to_string()).collect(),
))
}
@ -92,7 +92,7 @@ pub fn parse_inputs_traditional(input_strings: Vec<&str>) -> Result<CommandLineI
Ok(match offset0 {
Ok(n) => CommandLineInputs::FileAndOffset(("-".to_string(), n, None)),
_ => CommandLineInputs::FileNames(
input_strings.iter().map(|s| s.to_string()).collect(),
input_strings.iter().map(|&s| s.to_string()).collect(),
),
})
}
@ -179,7 +179,7 @@ mod tests {
impl<'a> MockOptions<'a> {
fn new(inputs: Vec<&'a str>, option_names: Vec<&'a str>) -> MockOptions<'a> {
MockOptions {
inputs: inputs.iter().map(|s| s.to_string()).collect::<Vec<_>>(),
inputs: inputs.iter().map(|&s| s.to_string()).collect::<Vec<_>>(),
option_names,
}
}

View file

@ -50,10 +50,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.map(|v| v.map(ToString::to_string).collect())
.unwrap_or_default();
let mut separator = "\n";
if matches.is_present(OPT_NULL) {
separator = "\x00";
}
let separator = if matches.is_present(OPT_NULL) {
"\x00"
} else {
"\n"
};
if variables.is_empty() {
for (env_var, value) in env::vars() {

View file

@ -108,10 +108,13 @@ impl WordFilter {
// Ignore empty string regex from cmd-line-args
let arg_reg: Option<String> = if matches.is_present(options::WORD_REGEXP) {
match matches.value_of(options::WORD_REGEXP) {
Some(v) => match v.is_empty() {
true => None,
false => Some(v.to_string()),
},
Some(v) => {
if v.is_empty() {
None
} else {
Some(v.to_string())
}
}
None => None,
}
} else {

View file

@ -386,13 +386,8 @@ fn prompt(msg: &str) -> bool {
let stdin = stdin();
let mut stdin = stdin.lock();
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
match stdin.read_until(b'\n', &mut buf) {
Ok(x) if x > 0 => match buf[0] {
b'y' | b'Y' => true,
_ => false,
},
Ok(x) if x > 0 => matches!(buf[0], b'y' | b'Y'),
_ => false,
}
}

View file

@ -20,6 +20,8 @@ static OPT_VERBOSE: &str = "verbose";
static ARG_DIRS: &str = "dirs";
static ENOTDIR: i32 = 20;
fn get_usage() -> String {
format!("{0} [OPTION]... DIRECTORY...", executable!())
}
@ -105,6 +107,11 @@ fn remove(dirs: Vec<String>, ignore: bool, parents: bool, verbose: bool) -> Resu
fn remove_dir(path: &Path, ignore: bool, verbose: bool) -> Result<(), i32> {
let mut read_dir = match fs::read_dir(path) {
Ok(m) => m,
Err(e) if e.raw_os_error() == Some(ENOTDIR) => {
// To match the GNU output
show_error!("failed to remove '{}': Not a directory", path.display());
return Err(1);
}
Err(e) => {
show_error!("reading directory '{}': {}", path.display(), e);
return Err(1);

View file

@ -2,7 +2,7 @@
Most of the time when sorting is spent comparing lines. The comparison functions however differ based
on which arguments are passed to `sort`, therefore it is important to always benchmark multiple scenarios.
This is an overwiew over what was benchmarked, and if you make changes to `sort`, you are encouraged to check
This is an overview over what was benchmarked, and if you make changes to `sort`, you are encouraged to check
how performance was affected for the workloads listed below. Feel free to add other workloads to the
list that we should improve / make sure not to regress.

View file

@ -25,7 +25,7 @@ ouroboros = "0.9.3"
rand = "0.7"
rayon = "1.5"
semver = "0.9.0"
tempdir = "0.3.7"
tempfile = "3"
unicode-width = "0.1.8"
uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }

View file

@ -26,7 +26,7 @@ use std::{
///
/// The code we should exit with.
pub fn check(path: &str, settings: &GlobalSettings) -> i32 {
let file = open(path).expect("failed to open input file");
let file = open(path);
let (recycled_sender, recycled_receiver) = sync_channel(2);
let (loaded_sender, loaded_receiver) = sync_channel(2);
thread::spawn({

View file

@ -73,6 +73,7 @@ impl Chunk {
/// * `lines`: The recycled vector to fill with lines. Must be empty.
/// * `settings`: The global settings.
#[allow(clippy::too_many_arguments)]
#[allow(clippy::borrowed_box)]
pub fn read(
sender_option: &mut Option<SyncSender<Chunk>>,
mut buffer: Vec<u8>,
@ -164,6 +165,7 @@ fn parse_lines<'a>(
/// The remaining bytes must be copied to the start of the buffer for the next invocation,
/// if another invocation is necessary, which is determined by the other return value.
/// * Whether this function should be called again.
#[allow(clippy::borrowed_box)]
fn read_to_buffer(
file: &mut Box<dyn Read + Send>,
next_files: &mut impl Iterator<Item = Box<dyn Read + Send>>,

View file

@ -23,7 +23,7 @@ use std::{
use itertools::Itertools;
use tempdir::TempDir;
use tempfile::TempDir;
use crate::{
chunks::{self, Chunk},
@ -34,7 +34,12 @@ const MIN_BUFFER_SIZE: usize = 8_000;
/// Sort files by using auxiliary files for storing intermediate chunks (if needed), and output the result.
pub fn ext_sort(files: &mut impl Iterator<Item = Box<dyn Read + Send>>, settings: &GlobalSettings) {
let tmp_dir = crash_if_err!(1, TempDir::new_in(&settings.tmp_dir, "uutils_sort"));
let tmp_dir = crash_if_err!(
1,
tempfile::Builder::new()
.prefix("uutils_sort")
.tempdir_in(&settings.tmp_dir)
);
let (sorted_sender, sorted_receiver) = std::sync::mpsc::sync_channel(1);
let (recycled_sender, recycled_receiver) = std::sync::mpsc::sync_channel(1);
thread::spawn({

View file

@ -29,7 +29,7 @@ pub fn merge<'a>(files: &[impl AsRef<OsStr>], settings: &'a GlobalSettings) -> F
let (request_sender, request_receiver) = channel();
let mut reader_files = Vec::with_capacity(files.len());
let mut loaded_receivers = Vec::with_capacity(files.len());
for (file_number, file) in files.iter().filter_map(open).enumerate() {
for (file_number, file) in files.iter().map(open).enumerate() {
let (sender, receiver) = sync_channel(2);
loaded_receivers.push(receiver);
reader_files.push(ReaderFile {

View file

@ -68,10 +68,10 @@ impl NumInfo {
}
first_char = false;
if parse_settings
.thousands_separator
.map_or(false, |c| c == char)
{
if matches!(
parse_settings.thousands_separator,
Some(c) if c == char
) {
continue;
}
@ -174,7 +174,11 @@ impl NumInfo {
pub fn numeric_str_cmp((a, a_info): (&str, &NumInfo), (b, b_info): (&str, &NumInfo)) -> Ordering {
// check for a difference in the sign
if a_info.sign != b_info.sign {
return a_info.sign.cmp(&b_info.sign);
return if a.is_empty() && b.is_empty() {
Ordering::Equal
} else {
a_info.sign.cmp(&b_info.sign)
};
}
// check for a difference in the exponent
@ -419,8 +423,8 @@ mod tests {
#[test]
fn minus_zero() {
// This matches GNU sort behavior.
test_helper("-0", "0", Ordering::Less);
test_helper("-0x", "0", Ordering::Less);
test_helper("-0", "0", Ordering::Equal);
test_helper("-0x", "0", Ordering::Equal);
}
#[test]
fn double_minus() {

View file

@ -99,17 +99,16 @@ static OPT_TMP_DIR: &str = "temporary-directory";
static ARG_FILES: &str = "files";
static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';
static NEGATIVE: char = '-';
static POSITIVE: char = '+';
const NEGATIVE: char = '-';
const POSITIVE: char = '+';
// Choosing a higher buffer size does not result in performance improvements
// (at least not on my machine). TODO: In the future, we should also take the amount of
// available memory into consideration, instead of relying on this constant only.
static DEFAULT_BUF_SIZE: usize = 1_000_000_000; // 1 GB
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy)]
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Debug)]
enum SortMode {
Numeric,
HumanNumeric,
@ -119,6 +118,21 @@ enum SortMode {
Random,
Default,
}
impl SortMode {
fn get_short_name(&self) -> Option<char> {
match self {
SortMode::Numeric => Some('n'),
SortMode::HumanNumeric => Some('h'),
SortMode::GeneralNumeric => Some('g'),
SortMode::Month => Some('M'),
SortMode::Version => Some('V'),
SortMode::Random => Some('R'),
SortMode::Default => None,
}
}
}
#[derive(Clone)]
pub struct GlobalSettings {
mode: SortMode,
@ -212,7 +226,7 @@ impl Default for GlobalSettings {
}
}
}
#[derive(Clone)]
#[derive(Clone, PartialEq, Debug)]
struct KeySettings {
mode: SortMode,
ignore_blanks: bool,
@ -222,6 +236,60 @@ struct KeySettings {
reverse: bool,
}
impl KeySettings {
/// Checks if the supplied combination of `mode`, `ignore_non_printing` and `dictionary_order` is allowed.
fn check_compatibility(
mode: SortMode,
ignore_non_printing: bool,
dictionary_order: bool,
) -> Result<(), String> {
if matches!(
mode,
SortMode::Numeric | SortMode::HumanNumeric | SortMode::GeneralNumeric | SortMode::Month
) {
if dictionary_order {
return Err(format!(
"options '-{}{}' are incompatible",
'd',
mode.get_short_name().unwrap()
));
} else if ignore_non_printing {
return Err(format!(
"options '-{}{}' are incompatible",
'i',
mode.get_short_name().unwrap()
));
}
}
Ok(())
}
fn set_sort_mode(&mut self, mode: SortMode) -> Result<(), String> {
if self.mode != SortMode::Default {
return Err(format!(
"options '-{}{}' are incompatible",
self.mode.get_short_name().unwrap(),
mode.get_short_name().unwrap()
));
}
Self::check_compatibility(mode, self.ignore_non_printing, self.dictionary_order)?;
self.mode = mode;
Ok(())
}
fn set_dictionary_order(&mut self) -> Result<(), String> {
Self::check_compatibility(self.mode, self.ignore_non_printing, true)?;
self.dictionary_order = true;
Ok(())
}
fn set_ignore_non_printing(&mut self) -> Result<(), String> {
Self::check_compatibility(self.mode, true, self.dictionary_order)?;
self.ignore_non_printing = true;
Ok(())
}
}
impl From<&GlobalSettings> for KeySettings {
fn from(settings: &GlobalSettings) -> Self {
Self {
@ -235,6 +303,12 @@ impl From<&GlobalSettings> for KeySettings {
}
}
impl Default for KeySettings {
fn default() -> Self {
Self::from(&GlobalSettings::default())
}
}
#[derive(Clone, Debug)]
enum NumCache {
AsF64(GeneralF64ParseResult),
@ -297,10 +371,10 @@ impl<'a> Line<'a> {
fn print(&self, writer: &mut impl Write, settings: &GlobalSettings) {
if settings.zero_terminated && !settings.debug {
crash_if_err!(1, writer.write_all(self.line.as_bytes()));
crash_if_err!(1, writer.write_all("\0".as_bytes()));
crash_if_err!(1, writer.write_all(b"\0"));
} else if !settings.debug {
crash_if_err!(1, writer.write_all(self.line.as_bytes()));
crash_if_err!(1, writer.write_all("\n".as_bytes()));
crash_if_err!(1, writer.write_all(b"\n"));
} else {
crash_if_err!(1, self.print_debug(settings, writer));
}
@ -330,8 +404,7 @@ impl<'a> Line<'a> {
&self.line[selection.clone()],
NumInfoParseSettings {
accept_si_units: selector.settings.mode == SortMode::HumanNumeric,
thousands_separator: Some(THOUSANDS_SEP),
decimal_pt: Some(DECIMAL_PT),
..Default::default()
},
);
let initial_selection = selection.clone();
@ -367,16 +440,24 @@ impl<'a> Line<'a> {
SortMode::Month => {
let initial_selection = &self.line[selection.clone()];
let month = if month_parse(initial_selection) == Month::Unknown {
// We failed to parse a month, which is equivalent to matching nothing.
0..0
} else {
// We parsed a month. Match the three first non-whitespace characters, which must be the month we parsed.
let mut chars = initial_selection
let mut month_chars = initial_selection
.char_indices()
.skip_while(|(_, c)| c.is_whitespace());
chars.next().unwrap().0
..chars.nth(2).map_or(initial_selection.len(), |(idx, _)| idx)
let month = if month_parse(initial_selection) == Month::Unknown {
// We failed to parse a month, which is equivalent to matching nothing.
// Add the "no match for key" marker to the first non-whitespace character.
let first_non_whitespace = month_chars.next();
first_non_whitespace.map_or(
initial_selection.len()..initial_selection.len(),
|(idx, _)| idx..idx,
)
} else {
// We parsed a month. Match the first three non-whitespace characters, which must be the month we parsed.
month_chars.next().unwrap().0
..month_chars
.nth(2)
.map_or(initial_selection.len(), |(idx, _)| idx)
};
// Shorten selection to month.
@ -406,14 +487,18 @@ impl<'a> Line<'a> {
}
}
}
if !(settings.mode == SortMode::Random
|| settings.stable
|| settings.unique
|| !(settings.dictionary_order
if settings.mode != SortMode::Random
&& !settings.stable
&& !settings.unique
&& (settings.dictionary_order
|| settings.ignore_blanks
|| settings.ignore_case
|| settings.ignore_non_printing
|| settings.mode != SortMode::Default))
|| settings.mode != SortMode::Default
|| settings
.selectors
.last()
.map_or(true, |selector| selector != &Default::default()))
{
// A last resort comparator is in use, underline the whole line.
if self.line.is_empty() {
@ -477,7 +562,7 @@ fn tokenize_with_separator(line: &str, separator: char) -> Vec<Field> {
tokens
}
#[derive(Clone)]
#[derive(Clone, PartialEq, Debug)]
struct KeyPosition {
/// 1-indexed, 0 is invalid.
field: usize,
@ -487,87 +572,45 @@ struct KeyPosition {
}
impl KeyPosition {
fn parse(key: &str, default_char_index: usize, settings: &mut KeySettings) -> Self {
fn new(key: &str, default_char_index: usize, ignore_blanks: bool) -> Result<Self, String> {
let mut field_and_char = key.split('.');
let mut field = field_and_char
let field = field_and_char
.next()
.unwrap_or_else(|| crash!(1, "invalid key `{}`", key));
let mut char = field_and_char.next();
// If there is a char index, we expect options to appear after it. Otherwise we expect them after the field index.
let value_with_options = char.as_mut().unwrap_or(&mut field);
let mut ignore_blanks = settings.ignore_blanks;
if let Some(options_start) = value_with_options.chars().position(char::is_alphabetic) {
for option in value_with_options[options_start..].chars() {
// valid options: MbdfghinRrV
match option {
'M' => settings.mode = SortMode::Month,
'b' => ignore_blanks = true,
'd' => settings.dictionary_order = true,
'f' => settings.ignore_case = true,
'g' => settings.mode = SortMode::GeneralNumeric,
'h' => settings.mode = SortMode::HumanNumeric,
'i' => settings.ignore_non_printing = true,
'n' => settings.mode = SortMode::Numeric,
'R' => settings.mode = SortMode::Random,
'r' => settings.reverse = true,
'V' => settings.mode = SortMode::Version,
c => crash!(1, "invalid option for key: `{}`", c),
}
// All numeric sorts and month sort conflict with dictionary_order and ignore_non_printing.
// Instad of reporting an error, let them overwrite each other.
// FIXME: This should only override if the overridden flag is a global flag.
// If conflicting flags are attached to the key, GNU sort crashes and we should probably too.
match option {
'h' | 'n' | 'g' | 'M' => {
settings.dictionary_order = false;
settings.ignore_non_printing = false;
}
'd' | 'i' => {
settings.mode = match settings.mode {
SortMode::Numeric
| SortMode::HumanNumeric
| SortMode::GeneralNumeric
| SortMode::Month => SortMode::Default,
// Only SortMode::Default and SortMode::Version work with dictionary_order and ignore_non_printing
m @ SortMode::Default
| m @ SortMode::Version
| m @ SortMode::Random => m,
}
}
_ => {}
}
}
// Strip away option characters from the original value so we can parse it later
*value_with_options = &value_with_options[..options_start];
}
.ok_or_else(|| format!("invalid key `{}`", key))?;
let char = field_and_char.next();
let field = field
.parse()
.unwrap_or_else(|e| crash!(1, "failed to parse field index for key `{}`: {}", key, e));
.map_err(|e| format!("failed to parse field index `{}`: {}", field, e))?;
if field == 0 {
crash!(1, "field index was 0");
return Err("field index can not be 0".to_string());
}
let char = char.map_or(default_char_index, |char| {
char.parse().unwrap_or_else(|e| {
crash!(
1,
"failed to parse character index for key `{}`: {}",
key,
e
)
})
});
Self {
let char = char.map_or(Ok(default_char_index), |char| {
char.parse()
.map_err(|e| format!("failed to parse character index `{}`: {}", char, e))
})?;
Ok(Self {
field,
char,
ignore_blanks,
})
}
}
impl Default for KeyPosition {
fn default() -> Self {
KeyPosition {
field: 1,
char: 1,
ignore_blanks: false,
}
}
}
#[derive(Clone)]
#[derive(Clone, PartialEq, Debug)]
struct FieldSelector {
from: KeyPosition,
to: Option<KeyPosition>,
@ -577,21 +620,120 @@ struct FieldSelector {
is_default_selection: bool,
}
impl FieldSelector {
fn new(from: KeyPosition, to: Option<KeyPosition>, settings: KeySettings) -> Self {
impl Default for FieldSelector {
fn default() -> Self {
Self {
from: Default::default(),
to: None,
settings: Default::default(),
needs_tokens: false,
is_default_selection: true,
}
}
}
impl FieldSelector {
/// Splits this position into the actual position and the attached options.
fn split_key_options(position: &str) -> (&str, &str) {
if let Some((options_start, _)) = position.char_indices().find(|(_, c)| c.is_alphabetic()) {
position.split_at(options_start)
} else {
(position, "")
}
}
fn parse(key: &str, global_settings: &GlobalSettings) -> Self {
let mut from_to = key.split(',');
let (from, from_options) = Self::split_key_options(from_to.next().unwrap());
let to = from_to.next().map(|to| Self::split_key_options(to));
let options_are_empty = from_options.is_empty() && matches!(to, None | Some((_, "")));
crash_if_err!(
2,
if options_are_empty {
// Inherit the global settings if there are no options attached to this key.
(|| {
// This would be ideal for a try block, I think. In the meantime this closure allows
// to use the `?` operator here.
Self::new(
KeyPosition::new(from, 1, global_settings.ignore_blanks)?,
to.map(|(to, _)| KeyPosition::new(to, 0, global_settings.ignore_blanks))
.transpose()?,
KeySettings::from(global_settings),
)
})()
} else {
// Do not inherit from `global_settings`, as there are options attached to this key.
Self::parse_with_options((from, from_options), to)
}
.map_err(|e| format!("failed to parse key `{}`: {}", key, e))
)
}
fn parse_with_options(
(from, from_options): (&str, &str),
to: Option<(&str, &str)>,
) -> Result<Self, String> {
/// Applies `options` to `key_settings`, returning if the 'b'-flag (ignore blanks) was present.
fn parse_key_settings(
options: &str,
key_settings: &mut KeySettings,
) -> Result<bool, String> {
let mut ignore_blanks = false;
for option in options.chars() {
match option {
'M' => key_settings.set_sort_mode(SortMode::Month)?,
'b' => ignore_blanks = true,
'd' => key_settings.set_dictionary_order()?,
'f' => key_settings.ignore_case = true,
'g' => key_settings.set_sort_mode(SortMode::GeneralNumeric)?,
'h' => key_settings.set_sort_mode(SortMode::HumanNumeric)?,
'i' => key_settings.set_ignore_non_printing()?,
'n' => key_settings.set_sort_mode(SortMode::Numeric)?,
'R' => key_settings.set_sort_mode(SortMode::Random)?,
'r' => key_settings.reverse = true,
'V' => key_settings.set_sort_mode(SortMode::Version)?,
c => return Err(format!("invalid option: `{}`", c)),
}
}
Ok(ignore_blanks)
}
let mut key_settings = KeySettings::default();
let from = parse_key_settings(from_options, &mut key_settings)
.map(|ignore_blanks| KeyPosition::new(from, 1, ignore_blanks))??;
let to = if let Some((to, to_options)) = to {
Some(
parse_key_settings(to_options, &mut key_settings)
.map(|ignore_blanks| KeyPosition::new(to, 0, ignore_blanks))??,
)
} else {
None
};
Self::new(from, to, key_settings)
}
fn new(
from: KeyPosition,
to: Option<KeyPosition>,
settings: KeySettings,
) -> Result<Self, String> {
if from.char == 0 {
Err("invalid character index 0 for the start position of a field".to_string())
} else {
Ok(Self {
is_default_selection: from.field == 1
&& from.char == 1
&& to.is_none()
// TODO: Once our MinRustV is 1.42 or higher, change this to the matches! macro
&& match settings.mode {
SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric => false,
_ => true,
},
&& !matches!(
settings.mode,
SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric
)
&& !from.ignore_blanks,
needs_tokens: from.field != 1 || from.char == 0 || to.is_some(),
from,
to,
settings,
})
}
}
@ -607,8 +749,7 @@ impl FieldSelector {
range,
NumInfoParseSettings {
accept_si_units: self.settings.mode == SortMode::HumanNumeric,
thousands_separator: Some(THOUSANDS_SEP),
decimal_pt: Some(DECIMAL_PT),
..Default::default()
},
);
// Shorten the range to what we need to pass to numeric_str_cmp later.
@ -650,7 +791,7 @@ impl FieldSelector {
tokens: Option<&[Field]>,
position: &KeyPosition,
) -> Resolution {
if tokens.map_or(false, |fields| fields.len() < position.field) {
if matches!(tokens, Some(tokens) if tokens.len() < position.field) {
Resolution::TooHigh
} else if position.char == 0 {
let end = tokens.unwrap()[position.field - 1].end;
@ -667,22 +808,21 @@ impl FieldSelector {
} else {
tokens.unwrap()[position.field - 1].start
};
// strip blanks if needed
if position.ignore_blanks {
idx += line[idx..]
.char_indices()
.find(|(_, c)| !c.is_whitespace())
.map_or(line[idx..].len(), |(idx, _)| idx);
}
// apply the character index
idx += line[idx..]
.char_indices()
.nth(position.char - 1)
.map_or(line.len(), |(idx, _)| idx);
.map_or(line[idx..].len(), |(idx, _)| idx);
if idx >= line.len() {
Resolution::TooHigh
} else {
if position.ignore_blanks {
if let Some((not_whitespace, _)) =
line[idx..].char_indices().find(|(_, c)| !c.is_whitespace())
{
idx += not_whitespace;
} else {
return Resolution::TooHigh;
}
}
Resolution::StartOfChar(idx)
}
}
@ -692,8 +832,9 @@ impl FieldSelector {
Resolution::StartOfChar(from) => {
let to = self.to.as_ref().map(|to| resolve_index(line, tokens, &to));
match to {
let mut range = match to {
Some(Resolution::StartOfChar(mut to)) => {
// We need to include the character at `to`.
to += line[to..].chars().next().map_or(1, |c| c.len_utf8());
from..to
}
@ -704,7 +845,11 @@ impl FieldSelector {
// If `to` is before the start of the line, report no match.
// This can happen if the line starts with a separator.
Some(Resolution::TooLow) => 0..0,
};
if range.start > range.end {
range.end = range.start;
}
range
}
Resolution::TooLow | Resolution::EndOfChar(_) => {
unreachable!("This should only happen if the field start index is 0, but that should already have caused an error.")
@ -892,7 +1037,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.long(OPT_SEPARATOR)
.help("custom separator for -k")
.takes_value(true))
.arg(Arg::with_name(OPT_ZERO_TERMINATED)
.arg(
Arg::with_name(OPT_ZERO_TERMINATED)
.short("z")
.long(OPT_ZERO_TERMINATED)
.help("line delimiter is NUL, not newline"),
@ -947,7 +1093,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let mut files = Vec::new();
for path in &files0_from {
let reader = open(path.as_str()).expect("Could not read from file specified.");
let reader = open(path.as_str());
let buf_reader = BufReader::new(reader);
for line in buf_reader.split(b'\0').flatten() {
files.push(
@ -1045,35 +1191,17 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if matches.is_present(OPT_KEY) {
for key in &matches.args[OPT_KEY].vals {
let key = key.to_string_lossy();
let mut from_to = key.split(',');
let mut key_settings = KeySettings::from(&settings);
let from = KeyPosition::parse(
from_to
.next()
.unwrap_or_else(|| crash!(1, "invalid key `{}`", key)),
1,
&mut key_settings,
);
if from.char == 0 {
crash!(
1,
"invalid character index 0 in `{}` for the start position of a field",
key
)
}
let to = from_to
.next()
.map(|to| KeyPosition::parse(to, 0, &mut key_settings));
let field_selector = FieldSelector::new(from, to, key_settings);
settings.selectors.push(field_selector);
settings
.selectors
.push(FieldSelector::parse(&key.to_string_lossy(), &settings));
}
}
if !settings.stable || !matches.is_present(OPT_KEY) {
if !matches.is_present(OPT_KEY) {
// add a default selector matching the whole line
let key_settings = KeySettings::from(&settings);
settings.selectors.push(FieldSelector::new(
settings.selectors.push(
FieldSelector::new(
KeyPosition {
field: 1,
char: 1,
@ -1081,7 +1209,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
},
None,
key_settings,
));
)
.unwrap(),
);
}
exec(&files, &settings)
@ -1108,7 +1238,7 @@ fn exec(files: &[String], settings: &GlobalSettings) -> i32 {
}
return check::check(files.first().unwrap(), settings);
} else {
let mut lines = files.iter().filter_map(open);
let mut lines = files.iter().map(open);
ext_sort(&mut lines, &settings);
}
@ -1203,6 +1333,8 @@ fn compare_by<'a>(a: &Line<'a>, b: &Line<'a>, global_settings: &GlobalSettings)
fn get_leading_gen(input: &str) -> Range<usize> {
let trimmed = input.trim_start();
let leading_whitespace_len = input.len() - trimmed.len();
// check for inf, -inf and nan
for allowed_prefix in &["inf", "-inf", "nan"] {
if trimmed.is_char_boundary(allowed_prefix.len())
&& trimmed[..allowed_prefix.len()].eq_ignore_ascii_case(allowed_prefix)
@ -1211,11 +1343,11 @@ fn get_leading_gen(input: &str) -> Range<usize> {
}
}
// Make this iter peekable to see if next char is numeric
let mut char_indices = trimmed.char_indices().peekable();
let mut char_indices = itertools::peek_nth(trimmed.char_indices());
let first = char_indices.peek();
if first.map_or(false, |&(_, c)| c == NEGATIVE || c == POSITIVE) {
if matches!(first, Some((_, NEGATIVE)) | Some((_, POSITIVE))) {
char_indices.next();
}
@ -1225,17 +1357,30 @@ fn get_leading_gen(input: &str) -> Range<usize> {
if c.is_ascii_digit() {
continue;
}
if c == DECIMAL_PT && !had_decimal_pt {
if c == DECIMAL_PT && !had_decimal_pt && !had_e_notation {
had_decimal_pt = true;
continue;
}
let next_char_numeric = char_indices
.peek()
.map_or(false, |(_, c)| c.is_ascii_digit());
if (c == 'e' || c == 'E') && !had_e_notation && next_char_numeric {
if (c == 'e' || c == 'E') && !had_e_notation {
// we can only consume the 'e' if what follow is either a digit, or a sign followed by a digit.
if let Some(&(_, next_char)) = char_indices.peek() {
if (next_char == '+' || next_char == '-')
&& matches!(
char_indices.peek_nth(2),
Some((_, c)) if c.is_ascii_digit()
)
{
// Consume the sign. The following digits will be consumed by the main loop.
char_indices.next();
had_e_notation = true;
continue;
}
if next_char.is_ascii_digit() {
had_e_notation = true;
continue;
}
}
}
return leading_whitespace_len..(leading_whitespace_len + idx);
}
leading_whitespace_len..input.len()
@ -1390,18 +1535,17 @@ fn print_sorted<'a, T: Iterator<Item = &'a Line<'a>>>(iter: T, settings: &Global
}
// from cat.rs
fn open(path: impl AsRef<OsStr>) -> Option<Box<dyn Read + Send>> {
fn open(path: impl AsRef<OsStr>) -> Box<dyn Read + Send> {
let path = path.as_ref();
if path == "-" {
let stdin = stdin();
return Some(Box::new(stdin) as Box<dyn Read + Send>);
return Box::new(stdin) as Box<dyn Read + Send>;
}
match File::open(Path::new(path)) {
Ok(f) => Some(Box::new(f) as Box<dyn Read + Send>),
Ok(f) => Box::new(f) as Box<dyn Read + Send>,
Err(e) => {
show_error!("{0:?}: {1}", path, e.to_string());
None
crash!(2, "cannot read: {0:?}: {1}", path, e);
}
}
}
@ -1415,7 +1559,7 @@ mod tests {
fn test_get_hash() {
let a = "Ted".to_string();
assert_eq!(2646829031758483623, get_hash(&a));
assert_eq!(2_646_829_031_758_483_623, get_hash(&a));
}
#[test]

View file

@ -200,6 +200,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
split(&settings)
}
#[allow(dead_code)]
struct Settings {
prefix: String,
numeric_suffix: bool,
@ -210,7 +211,7 @@ struct Settings {
filter: Option<String>,
strategy: String,
strategy_param: String,
verbose: bool,
verbose: bool, // TODO: warning: field is never read: `verbose`
}
trait Splitter {

View file

@ -25,8 +25,7 @@ static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str =
"Run COMMAND, with modified buffering operations for its standard streams.\n\n\
Mandatory arguments to long options are mandatory for short options too.";
static LONG_HELP: &str =
"If MODE is 'L' the corresponding stream will be line buffered.\n\
static LONG_HELP: &str = "If MODE is 'L' the corresponding stream will be line buffered.\n\
This option is invalid with standard input.\n\n\
If MODE is '0' the corresponding stream will be unbuffered.\n\n\
Otherwise MODE is a number which may be followed by one of the following:\n\n\

View file

@ -199,6 +199,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}
}
#[allow(clippy::if_same_then_else)]
if matches.is_present(options::FILE_SYSTEM) {
#[cfg(any(target_os = "linux", target_os = "windows"))]
syncfs(files);

View file

@ -121,13 +121,7 @@ impl Parser {
/// Test if the next token in the stream is a BOOLOP (-a or -o), without
/// removing the token from the stream.
fn peek_is_boolop(&mut self) -> bool {
// TODO: change to `matches!(self.peek(), Symbol::BoolOp(_))` once MSRV is 1.42
// #[allow(clippy::match_like_matches_macro)] // needs MSRV 1.43
if let Symbol::BoolOp(_) = self.peek() {
true
} else {
false
}
matches!(self.peek(), Symbol::BoolOp(_))
}
/// Parse an expression.
@ -271,11 +265,10 @@ impl Parser {
fn boolop(&mut self, op: Symbol) {
if op == Symbol::BoolOp(OsString::from("-a")) {
self.term();
self.stack.push(op);
} else {
self.expr();
self.stack.push(op);
}
self.stack.push(op);
}
/// Parse a (possible) unary argument test (string length or file

View file

@ -145,14 +145,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|| matches.is_present(options::sources::CURRENT)
{
let timestamp = if matches.is_present(options::sources::DATE) {
parse_date(matches.value_of(options::sources::DATE).unwrap().as_ref())
parse_date(matches.value_of(options::sources::DATE).unwrap())
} else {
parse_timestamp(
matches
.value_of(options::sources::CURRENT)
.unwrap()
.as_ref(),
)
parse_timestamp(matches.value_of(options::sources::CURRENT).unwrap())
};
(timestamp, timestamp)
} else {

View file

@ -110,7 +110,7 @@ impl<'a> Iterator for ExpandSet<'a> {
fn next(&mut self) -> Option<Self::Item> {
// while the Range has elements, try to return chars from it
// but make sure that they actually turn out to be Chars!
while let Some(n) = self.range.next() {
for n in &mut self.range {
if let Some(c) = from_u32(n) {
return Some(c);
}

View file

@ -15,16 +15,40 @@ use std::fs::{metadata, OpenOptions};
use std::io::ErrorKind;
use std::path::Path;
#[derive(Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
enum TruncateMode {
Absolute,
Reference,
Extend,
Reduce,
AtMost,
AtLeast,
RoundDown,
RoundUp,
Absolute(u64),
Extend(u64),
Reduce(u64),
AtMost(u64),
AtLeast(u64),
RoundDown(u64),
RoundUp(u64),
}
impl TruncateMode {
/// Compute a target size in bytes for this truncate mode.
///
/// `fsize` is the size of the reference file, in bytes.
///
/// # Examples
///
/// ```rust,ignore
/// let mode = TruncateMode::Extend(5);
/// let fsize = 10;
/// assert_eq!(mode.to_size(fsize), 15);
/// ```
fn to_size(&self, fsize: u64) -> u64 {
match self {
TruncateMode::Absolute(modsize) => *modsize,
TruncateMode::Extend(modsize) => fsize + modsize,
TruncateMode::Reduce(modsize) => fsize - modsize,
TruncateMode::AtMost(modsize) => fsize.min(*modsize),
TruncateMode::AtLeast(modsize) => fsize.max(*modsize),
TruncateMode::RoundDown(modsize) => fsize - fsize % modsize,
TruncateMode::RoundUp(modsize) => fsize + fsize % modsize,
}
}
}
static ABOUT: &str = "Shrink or extend the size of each file to the specified size.";
@ -116,114 +140,205 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let no_create = matches.is_present(options::NO_CREATE);
let reference = matches.value_of(options::REFERENCE).map(String::from);
let size = matches.value_of(options::SIZE).map(String::from);
if reference.is_none() && size.is_none() {
crash!(1, "you must specify either --reference or --size");
} else {
truncate(no_create, io_blocks, reference, size, files);
if let Err(e) = truncate(no_create, io_blocks, reference, size, files) {
match e.kind() {
ErrorKind::NotFound => {
// TODO Improve error-handling so that the error
// returned by `truncate()` provides the necessary
// parameter for formatting the error message.
let reference = matches.value_of(options::REFERENCE).map(String::from);
crash!(
1,
"cannot stat '{}': No such file or directory",
reference.unwrap()
);
}
_ => crash!(1, "{}", e.to_string()),
}
}
}
0
}
/// Truncate the named file to the specified size.
///
/// If `create` is true, then the file will be created if it does not
/// already exist. If `size` is larger than the number of bytes in the
/// file, then the file will be padded with zeros. If `size` is smaller
/// than the number of bytes in the file, then the file will be
/// truncated and any bytes beyond `size` will be lost.
///
/// # Errors
///
/// If the file could not be opened, or there was a problem setting the
/// size of the file.
fn file_truncate(filename: &str, create: bool, size: u64) -> std::io::Result<()> {
let path = Path::new(filename);
let f = OpenOptions::new().write(true).create(create).open(path)?;
f.set_len(size)
}
/// Truncate files to a size relative to a given file.
///
/// `rfilename` is the name of the reference file.
///
/// `size_string` gives the size relative to the reference file to which
/// to set the target files. For example, "+3K" means "set each file to
/// be three kilobytes larger than the size of the reference file".
///
/// If `create` is true, then each file will be created if it does not
/// already exist.
///
/// # Errors
///
/// If the any file could not be opened, or there was a problem setting
/// the size of at least one file.
fn truncate_reference_and_size(
rfilename: &str,
size_string: &str,
filenames: Vec<String>,
create: bool,
) -> std::io::Result<()> {
let mode = match parse_mode_and_size(size_string) {
Ok(m) => match m {
TruncateMode::Absolute(_) => {
crash!(1, "you must specify a relative --size with --reference")
}
_ => m,
},
Err(_) => crash!(1, "Invalid number: {}", size_string),
};
let fsize = metadata(rfilename)?.len();
let tsize = mode.to_size(fsize);
for filename in &filenames {
file_truncate(filename, create, tsize)?;
}
Ok(())
}
/// Truncate files to match the size of a given reference file.
///
/// `rfilename` is the name of the reference file.
///
/// If `create` is true, then each file will be created if it does not
/// already exist.
///
/// # Errors
///
/// If the any file could not be opened, or there was a problem setting
/// the size of at least one file.
fn truncate_reference_file_only(
rfilename: &str,
filenames: Vec<String>,
create: bool,
) -> std::io::Result<()> {
let tsize = metadata(rfilename)?.len();
for filename in &filenames {
file_truncate(filename, create, tsize)?;
}
Ok(())
}
/// Truncate files to a specified size.
///
/// `size_string` gives either an absolute size or a relative size. A
/// relative size adjusts the size of each file relative to its current
/// size. For example, "3K" means "set each file to be three kilobytes"
/// whereas "+3K" means "set each file to be three kilobytes larger than
/// its current size".
///
/// If `create` is true, then each file will be created if it does not
/// already exist.
///
/// # Errors
///
/// If the any file could not be opened, or there was a problem setting
/// the size of at least one file.
fn truncate_size_only(
size_string: &str,
filenames: Vec<String>,
create: bool,
) -> std::io::Result<()> {
let mode = match parse_mode_and_size(size_string) {
Ok(m) => m,
Err(_) => crash!(1, "Invalid number: {}", size_string),
};
for filename in &filenames {
let fsize = metadata(filename).map(|m| m.len()).unwrap_or(0);
let tsize = mode.to_size(fsize);
file_truncate(filename, create, tsize)?;
}
Ok(())
}
fn truncate(
no_create: bool,
_: bool,
reference: Option<String>,
size: Option<String>,
filenames: Vec<String>,
) {
let (modsize, mode) = match size {
Some(size_string) => {
) -> std::io::Result<()> {
let create = !no_create;
// There are four possibilities
// - reference file given and size given,
// - reference file given but no size given,
// - no reference file given but size given,
// - no reference file given and no size given,
match (reference, size) {
(Some(rfilename), Some(size_string)) => {
truncate_reference_and_size(&rfilename, &size_string, filenames, create)
}
(Some(rfilename), None) => truncate_reference_file_only(&rfilename, filenames, create),
(None, Some(size_string)) => truncate_size_only(&size_string, filenames, create),
(None, None) => crash!(1, "you must specify either --reference or --size"),
}
}
/// Decide whether a character is one of the size modifiers, like '+' or '<'.
fn is_modifier(c: char) -> bool {
c == '+' || c == '-' || c == '<' || c == '>' || c == '/' || c == '%'
}
/// Parse a size string with optional modifier symbol as its first character.
///
/// A size string is as described in [`parse_size`]. The first character
/// of `size_string` might be a modifier symbol, like `'+'` or
/// `'<'`. The first element of the pair returned by this function
/// indicates which modifier symbol was present, or
/// [`TruncateMode::Absolute`] if none.
///
/// # Panics
///
/// If `size_string` is empty, or if no number could be parsed from the
/// given string (for example, if the string were `"abc"`).
///
/// # Examples
///
/// ```rust,ignore
/// assert_eq!(parse_mode_and_size("+123"), (TruncateMode::Extend, 123));
/// ```
fn parse_mode_and_size(size_string: &str) -> Result<TruncateMode, ()> {
// Trim any whitespace.
let size_string = size_string.trim();
// Get the modifier character from the size string, if any. For
// example, if the argument is "+123", then the modifier is '+'.
let c = size_string.chars().next().unwrap();
let mode = match c {
let size_string = if is_modifier(c) {
&size_string[1..]
} else {
size_string
};
parse_size(size_string).map(match c {
'+' => TruncateMode::Extend,
'-' => TruncateMode::Reduce,
'<' => TruncateMode::AtMost,
'>' => TruncateMode::AtLeast,
'/' => TruncateMode::RoundDown,
'%' => TruncateMode::RoundUp,
_ => TruncateMode::Absolute, /* assume that the size is just a number */
};
// If there was a modifier character, strip it.
let size_string = match mode {
TruncateMode::Absolute => size_string,
_ => &size_string[1..],
};
let num_bytes = match parse_size(size_string) {
Ok(b) => b,
Err(_) => crash!(1, "Invalid number: {}", size_string),
};
(num_bytes, mode)
}
None => (0, TruncateMode::Reference),
};
let refsize = match reference {
Some(ref rfilename) => {
match mode {
// Only Some modes work with a reference
TruncateMode::Reference => (), //No --size was given
TruncateMode::Extend => (),
TruncateMode::Reduce => (),
_ => crash!(1, "you must specify a relative --size with --reference"),
};
match metadata(rfilename) {
Ok(meta) => meta.len(),
Err(f) => match f.kind() {
ErrorKind::NotFound => {
crash!(1, "cannot stat '{}': No such file or directory", rfilename)
}
_ => crash!(1, "{}", f.to_string()),
},
}
}
None => 0,
};
for filename in &filenames {
let path = Path::new(filename);
match OpenOptions::new()
.read(true)
.write(true)
.create(!no_create)
.open(path)
{
Ok(file) => {
let fsize = match reference {
Some(_) => refsize,
None => match metadata(filename) {
Ok(meta) => meta.len(),
Err(f) => {
show_warning!("{}", f.to_string());
continue;
}
},
};
let tsize: u64 = match mode {
TruncateMode::Absolute => modsize,
TruncateMode::Reference => fsize,
TruncateMode::Extend => fsize + modsize,
TruncateMode::Reduce => fsize - modsize,
TruncateMode::AtMost => fsize.min(modsize),
TruncateMode::AtLeast => fsize.max(modsize),
TruncateMode::RoundDown => fsize - fsize % modsize,
TruncateMode::RoundUp => fsize + fsize % modsize,
};
match file.set_len(tsize) {
Ok(_) => {}
Err(f) => crash!(1, "{}", f.to_string()),
};
}
Err(f) => crash!(1, "{}", f.to_string()),
}
}
_ => TruncateMode::Absolute,
})
}
/// Parse a size string into a number of bytes.
@ -285,7 +400,9 @@ fn parse_size(size: &str) -> Result<u64, ()> {
#[cfg(test)]
mod tests {
use crate::parse_mode_and_size;
use crate::parse_size;
use crate::TruncateMode;
#[test]
fn test_parse_size_zero() {
@ -311,4 +428,15 @@ mod tests {
assert_eq!(parse_size("123M").unwrap(), 123 * 1024 * 1024);
assert_eq!(parse_size("123MB").unwrap(), 123 * 1000 * 1000);
}
#[test]
fn test_parse_mode_and_size() {
assert_eq!(parse_mode_and_size("10"), Ok(TruncateMode::Absolute(10)));
assert_eq!(parse_mode_and_size("+10"), Ok(TruncateMode::Extend(10)));
assert_eq!(parse_mode_and_size("-10"), Ok(TruncateMode::Reduce(10)));
assert_eq!(parse_mode_and_size("<10"), Ok(TruncateMode::AtMost(10)));
assert_eq!(parse_mode_and_size(">10"), Ok(TruncateMode::AtLeast(10)));
assert_eq!(parse_mode_and_size("/10"), Ok(TruncateMode::RoundDown(10)));
assert_eq!(parse_mode_and_size("%10"), Ok(TruncateMode::RoundUp(10)));
}
}

View file

@ -6,19 +6,14 @@
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
/* last synced with: whoami (GNU coreutils) 8.22 */
// Allow dead code here in order to keep all fields, constants here, for consistency.
#![allow(dead_code)]
#[macro_use]
extern crate uucore;
use uucore::utmpx::*;
use clap::{App, Arg};
use uucore::utmpx::{self, Utmpx};
static ABOUT: &str = "Display who is currently logged in, according to FILE.";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Print the user names of users currently logged in to the current host";
static ARG_FILES: &str = "files";
@ -26,13 +21,23 @@ fn get_usage() -> String {
format!("{0} [FILE]", executable!())
}
fn get_long_usage() -> String {
format!(
"Output who is currently logged in according to FILE.
If FILE is not specified, use {}. /var/log/wtmp as FILE is common.",
utmpx::DEFAULT_FILE
)
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let usage = get_usage();
let after_help = get_long_usage();
let matches = App::new(executable!())
.version(VERSION)
.about(ABOUT)
.usage(&usage[..])
.after_help(&after_help[..])
.arg(Arg::with_name(ARG_FILES).takes_value(true).max_values(1))
.get_matches_from(args);
@ -44,7 +49,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let filename = if !files.is_empty() {
files[0].as_ref()
} else {
DEFAULT_FILE
utmpx::DEFAULT_FILE
};
let mut users = Utmpx::iter_all_records()

View file

@ -551,10 +551,11 @@ impl Who {
" ?".into()
};
let mut s = ut.host();
if self.do_lookup {
s = safe_unwrap!(ut.canon_host());
}
let s = if self.do_lookup {
safe_unwrap!(ut.canon_host())
} else {
ut.host()
};
let hoststr = if s.is_empty() { s } else { format!("({})", s) };
self.print_line(

View file

@ -179,7 +179,7 @@ impl MountInfo {
/* for Irix 6.5 */
| "ignore" => self.dummy = true,
_ => self.dummy = self.fs_type == "none"
&& self.mount_option.find(MOUNT_OPT_BIND).is_none(),
&& !self.mount_option.contains(MOUNT_OPT_BIND)
}
// set MountInfo::remote
#[cfg(windows)]

View file

@ -40,6 +40,7 @@ pub enum ExitStatus {
Signal(i32),
}
#[allow(clippy::trivially_copy_pass_by_ref)]
impl ExitStatus {
fn from_std_status(status: StdExitStatus) -> Self {
#[cfg(unix)]

View file

@ -146,15 +146,16 @@ pub trait Args: Iterator<Item = OsString> + Sized {
InvalidEncodingHandling::Ignore => s.is_ok(),
_ => true,
})
.map(|s| match s.is_ok() {
true => s.unwrap(),
false => s.unwrap_err(),
.map(|s| match s {
Ok(v) => v,
Err(e) => e,
})
.collect();
match full_conversion {
true => ConversionResult::Complete(result_vector),
false => ConversionResult::Lossy(result_vector),
if full_conversion {
ConversionResult::Complete(result_vector)
} else {
ConversionResult::Lossy(result_vector)
}
}

View file

@ -33,7 +33,7 @@ pub fn determine_backup_suffix(supplied_suffix: Option<&str>) -> String {
if let Some(suffix) = supplied_suffix {
String::from(suffix)
} else {
env::var("SIMPLE_BACKUP_SUFFIX").unwrap_or("~".to_owned())
env::var("SIMPLE_BACKUP_SUFFIX").unwrap_or_else(|_| "~".to_owned())
}
}

View file

@ -1,6 +1,3 @@
#![allow(dead_code)] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0
#![allow(unused_macros)] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0
// Copyright (C) ~ Roy Ivy III <rivy.dev@gmail.com>; MIT license
extern crate proc_macro;
@ -44,7 +41,6 @@ impl syn::parse::Parse for Tokens {
}
#[proc_macro]
#[cfg(not(test))] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0
pub fn main(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let Tokens { expr } = syn::parse_macro_input!(stream as Tokens);
proc_dbg!(&expr);

View file

@ -34,7 +34,7 @@ fn test_base32_encode_file() {
#[test]
fn test_decode() {
for decode_param in vec!["-d", "--decode"] {
for decode_param in &["-d", "--decode"] {
let input = "JBSWY3DPFQQFO33SNRSCC===\n";
new_ucmd!()
.arg(decode_param)
@ -56,7 +56,7 @@ fn test_garbage() {
#[test]
fn test_ignore_garbage() {
for ignore_garbage_param in vec!["-i", "--ignore-garbage"] {
for ignore_garbage_param in &["-i", "--ignore-garbage"] {
let input = "JBSWY\x013DPFQ\x02QFO33SNRSCC===\n";
new_ucmd!()
.arg("-d")
@ -69,7 +69,7 @@ fn test_ignore_garbage() {
#[test]
fn test_wrap() {
for wrap_param in vec!["-w", "--wrap"] {
for wrap_param in &["-w", "--wrap"] {
let input = "The quick brown fox jumps over the lazy dog.";
new_ucmd!()
.arg(wrap_param)
@ -84,16 +84,21 @@ fn test_wrap() {
#[test]
fn test_wrap_no_arg() {
for wrap_param in vec!["-w", "--wrap"] {
new_ucmd!().arg(wrap_param).fails().stderr_only(format!(
"error: The argument '--wrap <wrap>\' requires a value but none was supplied\n\nUSAGE:\n base32 [OPTION]... [FILE]\n\nFor more information try --help"
));
for wrap_param in &["-w", "--wrap"] {
let expected_stderr = "error: The argument '--wrap <wrap>\' requires a value but none was \
supplied\n\nUSAGE:\n base32 [OPTION]... [FILE]\n\nFor more \
information try --help"
.to_string();
new_ucmd!()
.arg(wrap_param)
.fails()
.stderr_only(expected_stderr);
}
}
#[test]
fn test_wrap_bad_arg() {
for wrap_param in vec!["-w", "--wrap"] {
for wrap_param in &["-w", "--wrap"] {
new_ucmd!()
.arg(wrap_param)
.arg("b")

View file

@ -26,7 +26,7 @@ fn test_base64_encode_file() {
#[test]
fn test_decode() {
for decode_param in vec!["-d", "--decode"] {
for decode_param in &["-d", "--decode"] {
let input = "aGVsbG8sIHdvcmxkIQ==";
new_ucmd!()
.arg(decode_param)
@ -48,7 +48,7 @@ fn test_garbage() {
#[test]
fn test_ignore_garbage() {
for ignore_garbage_param in vec!["-i", "--ignore-garbage"] {
for ignore_garbage_param in &["-i", "--ignore-garbage"] {
let input = "aGVsbG8sIHdvcmxkIQ==\0";
new_ucmd!()
.arg("-d")
@ -61,7 +61,7 @@ fn test_ignore_garbage() {
#[test]
fn test_wrap() {
for wrap_param in vec!["-w", "--wrap"] {
for wrap_param in &["-w", "--wrap"] {
let input = "The quick brown fox jumps over the lazy dog.";
new_ucmd!()
.arg(wrap_param)
@ -74,7 +74,7 @@ fn test_wrap() {
#[test]
fn test_wrap_no_arg() {
for wrap_param in vec!["-w", "--wrap"] {
for wrap_param in &["-w", "--wrap"] {
new_ucmd!().arg(wrap_param).fails().stderr_contains(
&"The argument '--wrap <wrap>' requires a value but none was supplied",
);
@ -83,7 +83,7 @@ fn test_wrap_no_arg() {
#[test]
fn test_wrap_bad_arg() {
for wrap_param in vec!["-w", "--wrap"] {
for wrap_param in &["-w", "--wrap"] {
new_ucmd!()
.arg(wrap_param)
.arg("b")

View file

@ -4,7 +4,7 @@ use std::ffi::OsStr;
#[test]
fn test_help() {
for help_flg in vec!["-h", "--help"] {
for help_flg in &["-h", "--help"] {
new_ucmd!()
.arg(&help_flg)
.succeeds()
@ -15,7 +15,7 @@ fn test_help() {
#[test]
fn test_version() {
for version_flg in vec!["-V", "--version"] {
for version_flg in &["-V", "--version"] {
assert!(new_ucmd!()
.arg(&version_flg)
.succeeds()
@ -59,7 +59,7 @@ fn test_dont_remove_suffix() {
#[test]
fn test_multiple_param() {
for multiple_param in vec!["-a", "--multiple"] {
for &multiple_param in &["-a", "--multiple"] {
let path = "/foo/bar/baz";
new_ucmd!()
.args(&[multiple_param, path, path])
@ -70,7 +70,7 @@ fn test_multiple_param() {
#[test]
fn test_suffix_param() {
for suffix_param in vec!["-s", "--suffix"] {
for &suffix_param in &["-s", "--suffix"] {
let path = "/foo/bar/baz.exe";
new_ucmd!()
.args(&[suffix_param, ".exe", path, path])
@ -81,7 +81,7 @@ fn test_suffix_param() {
#[test]
fn test_zero_param() {
for zero_param in vec!["-z", "--zero"] {
for &zero_param in &["-z", "--zero"] {
let path = "/foo/bar/baz";
new_ucmd!()
.args(&[zero_param, "-a", path, path])
@ -91,7 +91,12 @@ fn test_zero_param() {
}
fn expect_error(input: Vec<&str>) {
assert!(new_ucmd!().args(&input).fails().no_stdout().stderr().len() > 0);
assert!(!new_ucmd!()
.args(&input)
.fails()
.no_stdout()
.stderr_str()
.is_empty());
}
#[test]

View file

@ -237,7 +237,7 @@ fn test_numbered_lines_no_trailing_newline() {
#[test]
fn test_stdin_show_nonprinting() {
for same_param in vec!["-v", "--show-nonprinting"] {
for same_param in &["-v", "--show-nonprinting"] {
new_ucmd!()
.args(&[same_param])
.pipe_in("\t\0\n")
@ -248,7 +248,7 @@ fn test_stdin_show_nonprinting() {
#[test]
fn test_stdin_show_tabs() {
for same_param in vec!["-T", "--show-tabs"] {
for same_param in &["-T", "--show-tabs"] {
new_ucmd!()
.args(&[same_param])
.pipe_in("\t\0\n")
@ -259,7 +259,7 @@ fn test_stdin_show_tabs() {
#[test]
fn test_stdin_show_ends() {
for same_param in vec!["-E", "--show-ends"] {
for &same_param in &["-E", "--show-ends"] {
new_ucmd!()
.args(&[same_param, "-"])
.pipe_in("\t\0\n\t")
@ -270,7 +270,7 @@ fn test_stdin_show_ends() {
#[test]
fn test_stdin_show_all() {
for same_param in vec!["-A", "--show-all"] {
for same_param in &["-A", "--show-all"] {
new_ucmd!()
.args(&[same_param])
.pipe_in("\t\0\n")
@ -299,7 +299,7 @@ fn test_stdin_nonprinting_and_tabs() {
#[test]
fn test_stdin_squeeze_blank() {
for same_param in vec!["-s", "--squeeze-blank"] {
for same_param in &["-s", "--squeeze-blank"] {
new_ucmd!()
.arg(same_param)
.pipe_in("\n\na\n\n\n\n\nb\n\n\n")
@ -310,7 +310,7 @@ fn test_stdin_squeeze_blank() {
#[test]
fn test_stdin_number_non_blank() {
for same_param in vec!["-b", "--number-nonblank"] {
for same_param in &["-b", "--number-nonblank"] {
new_ucmd!()
.arg(same_param)
.arg("-")
@ -322,7 +322,7 @@ fn test_stdin_number_non_blank() {
#[test]
fn test_non_blank_overrides_number() {
for same_param in vec!["-b", "--number-nonblank"] {
for &same_param in &["-b", "--number-nonblank"] {
new_ucmd!()
.args(&[same_param, "-"])
.pipe_in("\na\nb\n\n\nc")
@ -333,7 +333,7 @@ fn test_non_blank_overrides_number() {
#[test]
fn test_squeeze_blank_before_numbering() {
for same_param in vec!["-s", "--squeeze-blank"] {
for &same_param in &["-s", "--squeeze-blank"] {
new_ucmd!()
.args(&[same_param, "-n", "-"])
.pipe_in("a\n\n\nb")
@ -406,10 +406,12 @@ fn test_domain_socket() {
use std::io::prelude::*;
use std::sync::{Arc, Barrier};
use std::thread;
use tempdir::TempDir;
use unix_socket::UnixListener;
let dir = TempDir::new("unix_socket").expect("failed to create dir");
let dir = tempfile::Builder::new()
.prefix("unix_socket")
.tempdir()
.expect("failed to create dir");
let socket_path = dir.path().join("sock");
let listener = UnixListener::bind(&socket_path).expect("failed to create socket");
@ -427,7 +429,7 @@ fn test_domain_socket() {
let child = new_ucmd!().args(&[socket_path]).run_no_wait();
barrier.wait();
let stdout = &child.wait_with_output().unwrap().stdout.clone();
let stdout = &child.wait_with_output().unwrap().stdout;
let output = String::from_utf8_lossy(&stdout);
assert_eq!("a\tb", output);

View file

@ -6,7 +6,7 @@ fn test_invalid_option() {
new_ucmd!().arg("-w").arg("/").fails();
}
static DIR: &'static str = "/tmp";
static DIR: &str = "/tmp";
#[test]
fn test_invalid_group() {

View file

@ -8,8 +8,8 @@ use self::chmod::strip_minus_from_mode;
extern crate chmod;
use self::libc::umask;
static TEST_FILE: &'static str = "file";
static REFERENCE_FILE: &'static str = "reference";
static TEST_FILE: &str = "file";
static REFERENCE_FILE: &str = "reference";
static REFERENCE_PERMS: u32 = 0o247;
lazy_static! {
static ref UMASK_MUTEX: Mutex<()> = Mutex::new(());
@ -69,6 +69,7 @@ fn run_tests(tests: Vec<TestCase>) {
}
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_octal() {
let tests = vec![
TestCase {
@ -121,6 +122,7 @@ fn test_chmod_octal() {
}
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_ugoa() {
let _guard = UMASK_MUTEX.lock();
@ -216,6 +218,7 @@ fn test_chmod_ugoa() {
}
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_ugo_copy() {
let tests = vec![
TestCase {
@ -248,6 +251,7 @@ fn test_chmod_ugo_copy() {
}
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_many_options() {
let _guard = UMASK_MUTEX.lock();
@ -264,6 +268,7 @@ fn test_chmod_many_options() {
}
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_reference_file() {
let tests = vec![
TestCase {
@ -303,6 +308,7 @@ fn test_permission_denied() {
}
#[test]
#[allow(clippy::unreadable_literal)]
fn test_chmod_recursive() {
let _guard = UMASK_MUTEX.lock();
@ -477,7 +483,7 @@ fn test_chmod_strip_minus_from_mode() {
];
for test in tests {
let mut args: Vec<String> = test.0.split(" ").map(|v| v.to_string()).collect();
let mut args: Vec<String> = test.0.split(' ').map(|v| v.to_string()).collect();
let _mode_had_minus_prefix = strip_minus_from_mode(&mut args);
assert_eq!(test.1, args.join(" "));
}

View file

@ -39,7 +39,7 @@ mod test_passgrp {
#[test]
fn test_usr2uid() {
assert_eq!(0, usr2uid("root").unwrap());
assert!(usr2uid("88888888").is_err());
assert!(usr2uid("88_888_888").is_err());
assert!(usr2uid("auserthatdoesntexist").is_err());
}
@ -50,14 +50,14 @@ mod test_passgrp {
} else {
assert_eq!(0, grp2gid("wheel").unwrap());
}
assert!(grp2gid("88888888").is_err());
assert!(grp2gid("88_888_888").is_err());
assert!(grp2gid("agroupthatdoesntexist").is_err());
}
#[test]
fn test_uid2usr() {
assert_eq!("root", uid2usr(0).unwrap());
assert!(uid2usr(88888888).is_err());
assert!(uid2usr(88_888_888).is_err());
}
#[test]
@ -67,7 +67,7 @@ mod test_passgrp {
} else {
assert_eq!("wheel", gid2grp(0).unwrap());
}
assert!(gid2grp(88888888).is_err());
assert!(gid2grp(88_888_888).is_err());
}
}

View file

@ -85,12 +85,12 @@ fn test_crc_for_bigger_than_32_bytes() {
let result = ucmd.arg("chars.txt").succeeds();
let mut stdout_splitted = result.stdout_str().split(" ");
let mut stdout_splitted = result.stdout_str().split(' ');
let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap();
assert_eq!(cksum, 586047089);
assert_eq!(cksum, 586_047_089);
assert_eq!(bytes_cnt, 16);
}
@ -100,11 +100,11 @@ fn test_stdin_larger_than_128_bytes() {
let result = ucmd.arg("larger_than_2056_bytes.txt").succeeds();
let mut stdout_splitted = result.stdout_str().split(" ");
let mut stdout_splitted = result.stdout_str().split(' ');
let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap();
assert_eq!(cksum, 945881979);
assert_eq!(cksum, 945_881_979);
assert_eq!(bytes_cnt, 2058);
}

View file

@ -74,7 +74,7 @@ fn output_delimiter_require_arg() {
#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn zero_terminated() {
for param in vec!["-z", "--zero-terminated"] {
for &param in &["-z", "--zero-terminated"] {
new_ucmd!()
.args(&[param, "a", "b"])
.fails()

View file

@ -108,7 +108,7 @@ fn test_cp_multiple_files() {
#[test]
// FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590
#[cfg(not(macos))]
#[cfg(not(target_os = "macos"))]
fn test_cp_recurse() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("-r")
@ -132,7 +132,7 @@ fn test_cp_with_dirs_t() {
#[test]
// FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590
#[cfg(not(macos))]
#[cfg(not(target_os = "macos"))]
fn test_cp_with_dirs() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
@ -316,6 +316,22 @@ fn test_cp_arg_backup() {
);
}
#[test]
fn test_cp_arg_backup_with_other_args() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HOW_ARE_YOU_SOURCE)
.arg("-vbL")
.succeeds();
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
assert_eq!(
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
"How are you?\n"
);
}
#[test]
fn test_cp_arg_backup_arg_first() {
let (at, mut ucmd) = at_and_ucmd!();

View file

@ -1,13 +1,13 @@
use crate::common::util::*;
static INPUT: &'static str = "lists.txt";
static INPUT: &str = "lists.txt";
struct TestedSequence<'b> {
name: &'b str,
sequence: &'b str,
}
static EXAMPLE_SEQUENCES: &'static [TestedSequence<'static>] = &[
static EXAMPLE_SEQUENCES: &[TestedSequence] = &[
TestedSequence {
name: "singular",
sequence: "2",
@ -34,14 +34,14 @@ static EXAMPLE_SEQUENCES: &'static [TestedSequence<'static>] = &[
},
];
static COMPLEX_SEQUENCE: &'static TestedSequence<'static> = &TestedSequence {
static COMPLEX_SEQUENCE: &TestedSequence = &TestedSequence {
name: "",
sequence: "9-,6-7,-2,4",
};
#[test]
fn test_byte_sequence() {
for param in vec!["-b", "--bytes"] {
for &param in &["-b", "--bytes"] {
for example_seq in EXAMPLE_SEQUENCES {
new_ucmd!()
.args(&[param, example_seq.sequence, INPUT])
@ -53,7 +53,7 @@ fn test_byte_sequence() {
#[test]
fn test_char_sequence() {
for param in vec!["-c", "--characters"] {
for &param in &["-c", "--characters"] {
for example_seq in EXAMPLE_SEQUENCES {
//as of coreutils 8.25 a char range is effectively the same as a byte range; there is no distinct treatment of utf8 chars.
new_ucmd!()
@ -66,7 +66,7 @@ fn test_char_sequence() {
#[test]
fn test_field_sequence() {
for param in vec!["-f", "--fields"] {
for &param in &["-f", "--fields"] {
for example_seq in EXAMPLE_SEQUENCES {
new_ucmd!()
.args(&[param, example_seq.sequence, INPUT])
@ -78,7 +78,7 @@ fn test_field_sequence() {
#[test]
fn test_specify_delimiter() {
for param in vec!["-d", "--delimiter"] {
for &param in &["-d", "--delimiter"] {
new_ucmd!()
.args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT])
.succeeds()
@ -122,7 +122,7 @@ fn test_zero_terminated() {
#[test]
fn test_only_delimited() {
for param in vec!["-s", "--only-delimited"] {
for param in &["-s", "--only-delimited"] {
new_ucmd!()
.args(&["-d_", param, "-f", "1"])
.pipe_in("91\n82\n7_3")

View file

@ -118,7 +118,7 @@ fn test_null_delimiter() {
let mut vars: Vec<_> = out.split('\0').collect();
assert_eq!(vars.len(), 3);
vars.sort();
vars.sort_unstable();
assert_eq!(vars[0], "");
assert_eq!(vars[1], "ABC=xyz");
assert_eq!(vars[2], "FOO=bar");
@ -135,7 +135,7 @@ fn test_unset_variable() {
.succeeds()
.stdout_move_str();
assert_eq!(out.lines().any(|line| line.starts_with("HOME=")), false);
assert!(!out.lines().any(|line| line.starts_with("HOME=")));
}
#[test]
@ -196,7 +196,7 @@ fn test_change_directory() {
fn test_fail_change_directory() {
let scene = TestScenario::new(util_name!());
let some_non_existing_path = "some_nonexistent_path";
assert_eq!(Path::new(some_non_existing_path).is_dir(), false);
assert!(!Path::new(some_non_existing_path).is_dir());
let out = scene
.ucmd()

View file

@ -2,55 +2,95 @@ use crate::common::util::*;
#[test]
fn test_simple_arithmetic() {
new_ucmd!().args(&["1", "+", "1"]).run().stdout_is("2\n");
new_ucmd!()
.args(&["1", "+", "1"])
.succeeds()
.stdout_only("2\n");
new_ucmd!().args(&["1", "-", "1"]).run().stdout_is("0\n");
new_ucmd!()
.args(&["1", "-", "1"])
.fails()
.status_code(1)
.stdout_only("0\n");
new_ucmd!().args(&["3", "*", "2"]).run().stdout_is("6\n");
new_ucmd!()
.args(&["3", "*", "2"])
.succeeds()
.stdout_only("6\n");
new_ucmd!().args(&["4", "/", "2"]).run().stdout_is("2\n");
new_ucmd!()
.args(&["4", "/", "2"])
.succeeds()
.stdout_only("2\n");
}
#[test]
fn test_complex_arithmetic() {
let run = new_ucmd!()
new_ucmd!()
.args(&["9223372036854775807", "+", "9223372036854775807"])
.run();
run.stdout_is("");
run.stderr_is("expr: +: Numerical result out of range");
.succeeds()
.stdout_only("18446744073709551614\n");
let run = new_ucmd!().args(&["9", "/", "0"]).run();
run.stdout_is("");
run.stderr_is("expr: division by zero");
new_ucmd!()
.args(&[
"92233720368547758076549841651981984981498415651",
"%",
"922337203685",
])
.succeeds()
.stdout_only("533691697086\n");
new_ucmd!()
.args(&[
"92233720368547758076549841651981984981498415651",
"*",
"922337203685",
])
.succeeds()
.stdout_only("85070591730190566808700855121818604965830915152801178873935\n");
new_ucmd!()
.args(&[
"92233720368547758076549841651981984981498415651",
"-",
"922337203685",
])
.succeeds()
.stdout_only("92233720368547758076549841651981984059161211966\n");
new_ucmd!()
.args(&["9", "/", "0"])
.fails()
.stderr_only("expr: division by zero\n");
}
#[test]
fn test_parenthesis() {
new_ucmd!()
.args(&["(", "1", "+", "1", ")", "*", "2"])
.run()
.stdout_is("4\n");
.succeeds()
.stdout_only("4\n");
}
#[test]
fn test_or() {
new_ucmd!()
.args(&["0", "|", "foo"])
.run()
.stdout_is("foo\n");
.succeeds()
.stdout_only("foo\n");
new_ucmd!()
.args(&["foo", "|", "bar"])
.run()
.stdout_is("foo\n");
.succeeds()
.stdout_only("foo\n");
}
#[test]
fn test_and() {
new_ucmd!()
.args(&["foo", "&", "1"])
.run()
.stdout_is("foo\n");
.succeeds()
.stdout_only("foo\n");
new_ucmd!().args(&["", "&", "1"]).run().stdout_is("0\n");
}

View file

@ -4,6 +4,7 @@
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
#![allow(clippy::unreadable_literal)]
use crate::common::util::*;
use std::time::SystemTime;
@ -39,6 +40,18 @@ fn test_first_100000_integers() {
assert_eq!(hash_check, "4ed2d8403934fa1c76fe4b84c5d4b8850299c359");
}
#[test]
fn test_cli_args() {
// Make sure that factor works with CLI arguments as well.
new_ucmd!().args(&["3"]).succeeds().stdout_contains("3: 3");
new_ucmd!()
.args(&["3", "6"])
.succeeds()
.stdout_contains("3: 3")
.stdout_contains("6: 2 3");
}
#[test]
fn test_random() {
use conv::prelude::*;
@ -77,7 +90,7 @@ fn test_random() {
};
}
factors.sort();
factors.sort_unstable();
(product, factors)
};
@ -92,7 +105,7 @@ fn test_random() {
for factor in factors {
outstring.push_str(&(format!(" {}", factor))[..]);
}
outstring.push_str("\n");
outstring.push('\n');
}
run(instring.as_bytes(), outstring.as_bytes());
@ -131,7 +144,7 @@ fn test_random_big() {
f_bits.push(extrarange.sample(&mut rng));
}
f_bits.push(extrabits);
f_bits.sort();
f_bits.sort_unstable();
// compute sequential differences here. We leave off the +14 bits
// so we can just index PRIMES_BY_BITS
@ -160,7 +173,7 @@ fn test_random_big() {
}
assert_eq!(nbits, 64);
factors.sort();
factors.sort_unstable();
(product, factors)
};
@ -174,7 +187,7 @@ fn test_random_big() {
for factor in factors {
outstring.push_str(&(format!(" {}", factor))[..]);
}
outstring.push_str("\n");
outstring.push('\n');
}
run(instring.as_bytes(), outstring.as_bytes());
@ -202,7 +215,7 @@ fn run(instring: &[u8], outstring: &[u8]) {
.stdout_is(String::from_utf8(outstring.to_owned()).unwrap());
}
const PRIMES_BY_BITS: &'static [&'static [u64]] = &[
const PRIMES_BY_BITS: &[&[u64]] = &[
PRIMES14, PRIMES15, PRIMES16, PRIMES17, PRIMES18, PRIMES19, PRIMES20, PRIMES21, PRIMES22,
PRIMES23, PRIMES24, PRIMES25, PRIMES26, PRIMES27, PRIMES28, PRIMES29, PRIMES30, PRIMES31,
PRIMES32, PRIMES33, PRIMES34, PRIMES35, PRIMES36, PRIMES37, PRIMES38, PRIMES39, PRIMES40,
@ -210,7 +223,7 @@ const PRIMES_BY_BITS: &'static [&'static [u64]] = &[
PRIMES50,
];
const PRIMES64: &'static [u64] = &[
const PRIMES64: &[u64] = &[
18446744073709551557,
18446744073709551533,
18446744073709551521,
@ -262,7 +275,7 @@ const PRIMES64: &'static [u64] = &[
18446744073709549571,
];
const PRIMES14: &'static [u64] = &[
const PRIMES14: &[u64] = &[
16381, 16369, 16363, 16361, 16349, 16339, 16333, 16319, 16301, 16273, 16267, 16253, 16249,
16231, 16229, 16223, 16217, 16193, 16189, 16187, 16183, 16141, 16139, 16127, 16111, 16103,
16097, 16091, 16087, 16073, 16069, 16067, 16063, 16061, 16057, 16033, 16007, 16001, 15991,
@ -274,7 +287,7 @@ const PRIMES14: &'static [u64] = &[
15373,
];
const PRIMES15: &'static [u64] = &[
const PRIMES15: &[u64] = &[
32749, 32719, 32717, 32713, 32707, 32693, 32687, 32653, 32647, 32633, 32621, 32611, 32609,
32603, 32587, 32579, 32573, 32569, 32563, 32561, 32537, 32533, 32531, 32507, 32503, 32497,
32491, 32479, 32467, 32443, 32441, 32429, 32423, 32413, 32411, 32401, 32381, 32377, 32371,
@ -285,7 +298,7 @@ const PRIMES15: &'static [u64] = &[
31847, 31817, 31799, 31793, 31771, 31769, 31751,
];
const PRIMES16: &'static [u64] = &[
const PRIMES16: &[u64] = &[
65521, 65519, 65497, 65479, 65449, 65447, 65437, 65423, 65419, 65413, 65407, 65393, 65381,
65371, 65357, 65353, 65327, 65323, 65309, 65293, 65287, 65269, 65267, 65257, 65239, 65213,
65203, 65183, 65179, 65173, 65171, 65167, 65147, 65141, 65129, 65123, 65119, 65111, 65101,
@ -295,7 +308,7 @@ const PRIMES16: &'static [u64] = &[
64627, 64621, 64613, 64609, 64601, 64591, 64579, 64577, 64567, 64553,
];
const PRIMES17: &'static [u64] = &[
const PRIMES17: &[u64] = &[
131071, 131063, 131059, 131041, 131023, 131011, 131009, 130987, 130981, 130973, 130969, 130957,
130927, 130873, 130859, 130843, 130841, 130829, 130817, 130811, 130807, 130787, 130783, 130769,
130729, 130699, 130693, 130687, 130681, 130657, 130651, 130649, 130643, 130639, 130633, 130631,
@ -306,7 +319,7 @@ const PRIMES17: &'static [u64] = &[
130073, 130069, 130057, 130051,
];
const PRIMES18: &'static [u64] = &[
const PRIMES18: &[u64] = &[
262139, 262133, 262127, 262121, 262111, 262109, 262103, 262079, 262069, 262051, 262049, 262027,
262007, 261983, 261977, 261973, 261971, 261959, 261917, 261887, 261881, 261847, 261823, 261799,
261791, 261787, 261773, 261761, 261757, 261739, 261721, 261713, 261707, 261697, 261673, 261643,
@ -316,7 +329,7 @@ const PRIMES18: &'static [u64] = &[
261169, 261167, 261127,
];
const PRIMES19: &'static [u64] = &[
const PRIMES19: &[u64] = &[
524287, 524269, 524261, 524257, 524243, 524231, 524221, 524219, 524203, 524201, 524197, 524189,
524171, 524149, 524123, 524119, 524113, 524099, 524087, 524081, 524071, 524063, 524057, 524053,
524047, 523997, 523987, 523969, 523949, 523937, 523927, 523907, 523903, 523877, 523867, 523847,
@ -326,7 +339,7 @@ const PRIMES19: &'static [u64] = &[
523403, 523387, 523357, 523351, 523349, 523333, 523307, 523297,
];
const PRIMES20: &'static [u64] = &[
const PRIMES20: &[u64] = &[
1048573, 1048571, 1048559, 1048549, 1048517, 1048507, 1048447, 1048433, 1048423, 1048391,
1048387, 1048367, 1048361, 1048357, 1048343, 1048309, 1048291, 1048273, 1048261, 1048219,
1048217, 1048213, 1048193, 1048189, 1048139, 1048129, 1048127, 1048123, 1048063, 1048051,
@ -336,7 +349,7 @@ const PRIMES20: &'static [u64] = &[
1047691, 1047689, 1047671, 1047667, 1047653, 1047649, 1047647, 1047589, 1047587, 1047559,
];
const PRIMES21: &'static [u64] = &[
const PRIMES21: &[u64] = &[
2097143, 2097133, 2097131, 2097097, 2097091, 2097083, 2097047, 2097041, 2097031, 2097023,
2097013, 2096993, 2096987, 2096971, 2096959, 2096957, 2096947, 2096923, 2096911, 2096909,
2096893, 2096881, 2096873, 2096867, 2096851, 2096837, 2096807, 2096791, 2096789, 2096777,
@ -346,7 +359,7 @@ const PRIMES21: &'static [u64] = &[
2096221, 2096209, 2096191, 2096183, 2096147,
];
const PRIMES22: &'static [u64] = &[
const PRIMES22: &[u64] = &[
4194301, 4194287, 4194277, 4194271, 4194247, 4194217, 4194199, 4194191, 4194187, 4194181,
4194173, 4194167, 4194143, 4194137, 4194131, 4194107, 4194103, 4194023, 4194011, 4194007,
4193977, 4193971, 4193963, 4193957, 4193939, 4193929, 4193909, 4193869, 4193807, 4193803,
@ -356,7 +369,7 @@ const PRIMES22: &'static [u64] = &[
4193297,
];
const PRIMES23: &'static [u64] = &[
const PRIMES23: &[u64] = &[
8388593, 8388587, 8388581, 8388571, 8388547, 8388539, 8388473, 8388461, 8388451, 8388449,
8388439, 8388427, 8388421, 8388409, 8388377, 8388371, 8388319, 8388301, 8388287, 8388283,
8388277, 8388239, 8388209, 8388187, 8388113, 8388109, 8388091, 8388071, 8388059, 8388019,
@ -365,7 +378,7 @@ const PRIMES23: &'static [u64] = &[
8387723, 8387707, 8387671, 8387611, 8387609, 8387591,
];
const PRIMES24: &'static [u64] = &[
const PRIMES24: &[u64] = &[
16777213, 16777199, 16777183, 16777153, 16777141, 16777139, 16777127, 16777121, 16777099,
16777049, 16777027, 16776989, 16776973, 16776971, 16776967, 16776961, 16776941, 16776937,
16776931, 16776919, 16776901, 16776899, 16776869, 16776857, 16776839, 16776833, 16776817,
@ -375,7 +388,7 @@ const PRIMES24: &'static [u64] = &[
16776317, 16776313, 16776289, 16776217, 16776211,
];
const PRIMES25: &'static [u64] = &[
const PRIMES25: &[u64] = &[
33554393, 33554383, 33554371, 33554347, 33554341, 33554317, 33554291, 33554273, 33554267,
33554249, 33554239, 33554221, 33554201, 33554167, 33554159, 33554137, 33554123, 33554093,
33554083, 33554077, 33554051, 33554021, 33554011, 33554009, 33553999, 33553991, 33553969,
@ -385,7 +398,7 @@ const PRIMES25: &'static [u64] = &[
33553519, 33553517, 33553511, 33553489, 33553463, 33553451, 33553417,
];
const PRIMES26: &'static [u64] = &[
const PRIMES26: &[u64] = &[
67108859, 67108837, 67108819, 67108777, 67108763, 67108757, 67108753, 67108747, 67108739,
67108729, 67108721, 67108709, 67108693, 67108669, 67108667, 67108661, 67108649, 67108633,
67108597, 67108579, 67108529, 67108511, 67108507, 67108493, 67108471, 67108463, 67108453,
@ -396,7 +409,7 @@ const PRIMES26: &'static [u64] = &[
67107863,
];
const PRIMES27: &'static [u64] = &[
const PRIMES27: &[u64] = &[
134217689, 134217649, 134217617, 134217613, 134217593, 134217541, 134217529, 134217509,
134217497, 134217493, 134217487, 134217467, 134217439, 134217437, 134217409, 134217403,
134217401, 134217367, 134217361, 134217353, 134217323, 134217301, 134217277, 134217257,
@ -407,7 +420,7 @@ const PRIMES27: &'static [u64] = &[
134216737, 134216729,
];
const PRIMES28: &'static [u64] = &[
const PRIMES28: &[u64] = &[
268435399, 268435367, 268435361, 268435337, 268435331, 268435313, 268435291, 268435273,
268435243, 268435183, 268435171, 268435157, 268435147, 268435133, 268435129, 268435121,
268435109, 268435091, 268435067, 268435043, 268435039, 268435033, 268435019, 268435009,
@ -418,7 +431,7 @@ const PRIMES28: &'static [u64] = &[
268434479, 268434461,
];
const PRIMES29: &'static [u64] = &[
const PRIMES29: &[u64] = &[
536870909, 536870879, 536870869, 536870849, 536870839, 536870837, 536870819, 536870813,
536870791, 536870779, 536870767, 536870743, 536870729, 536870723, 536870717, 536870701,
536870683, 536870657, 536870641, 536870627, 536870611, 536870603, 536870599, 536870573,
@ -428,7 +441,7 @@ const PRIMES29: &'static [u64] = &[
536870027, 536869999, 536869951, 536869943, 536869937, 536869919, 536869901, 536869891,
];
const PRIMES30: &'static [u64] = &[
const PRIMES30: &[u64] = &[
1073741789, 1073741783, 1073741741, 1073741723, 1073741719, 1073741717, 1073741689, 1073741671,
1073741663, 1073741651, 1073741621, 1073741567, 1073741561, 1073741527, 1073741503, 1073741477,
1073741467, 1073741441, 1073741419, 1073741399, 1073741387, 1073741381, 1073741371, 1073741329,
@ -437,7 +450,7 @@ const PRIMES30: &'static [u64] = &[
1073740853, 1073740847, 1073740819, 1073740807,
];
const PRIMES31: &'static [u64] = &[
const PRIMES31: &[u64] = &[
2147483647, 2147483629, 2147483587, 2147483579, 2147483563, 2147483549, 2147483543, 2147483497,
2147483489, 2147483477, 2147483423, 2147483399, 2147483353, 2147483323, 2147483269, 2147483249,
2147483237, 2147483179, 2147483171, 2147483137, 2147483123, 2147483077, 2147483069, 2147483059,
@ -446,7 +459,7 @@ const PRIMES31: &'static [u64] = &[
2147482763, 2147482739, 2147482697, 2147482693, 2147482681, 2147482663, 2147482661,
];
const PRIMES32: &'static [u64] = &[
const PRIMES32: &[u64] = &[
4294967291, 4294967279, 4294967231, 4294967197, 4294967189, 4294967161, 4294967143, 4294967111,
4294967087, 4294967029, 4294966997, 4294966981, 4294966943, 4294966927, 4294966909, 4294966877,
4294966829, 4294966813, 4294966769, 4294966667, 4294966661, 4294966657, 4294966651, 4294966639,
@ -454,7 +467,7 @@ const PRIMES32: &'static [u64] = &[
4294966373, 4294966367, 4294966337, 4294966297,
];
const PRIMES33: &'static [u64] = &[
const PRIMES33: &[u64] = &[
8589934583, 8589934567, 8589934543, 8589934513, 8589934487, 8589934307, 8589934291, 8589934289,
8589934271, 8589934237, 8589934211, 8589934207, 8589934201, 8589934187, 8589934151, 8589934141,
8589934139, 8589934117, 8589934103, 8589934099, 8589934091, 8589934069, 8589934049, 8589934027,
@ -463,7 +476,7 @@ const PRIMES33: &'static [u64] = &[
8589933647, 8589933641, 8589933637, 8589933631, 8589933629, 8589933619, 8589933601, 8589933581,
];
const PRIMES34: &'static [u64] = &[
const PRIMES34: &[u64] = &[
17179869143,
17179869107,
17179869071,
@ -514,7 +527,7 @@ const PRIMES34: &'static [u64] = &[
17179868183,
];
const PRIMES35: &'static [u64] = &[
const PRIMES35: &[u64] = &[
34359738337,
34359738319,
34359738307,
@ -547,7 +560,7 @@ const PRIMES35: &'static [u64] = &[
34359737371,
];
const PRIMES36: &'static [u64] = &[
const PRIMES36: &[u64] = &[
68719476731,
68719476719,
68719476713,
@ -599,7 +612,7 @@ const PRIMES36: &'static [u64] = &[
68719475729,
];
const PRIMES37: &'static [u64] = &[
const PRIMES37: &[u64] = &[
137438953447,
137438953441,
137438953427,
@ -625,7 +638,7 @@ const PRIMES37: &'static [u64] = &[
137438952491,
];
const PRIMES38: &'static [u64] = &[
const PRIMES38: &[u64] = &[
274877906899,
274877906857,
274877906837,
@ -665,7 +678,7 @@ const PRIMES38: &'static [u64] = &[
274877905931,
];
const PRIMES39: &'static [u64] = &[
const PRIMES39: &[u64] = &[
549755813881,
549755813869,
549755813821,
@ -711,7 +724,7 @@ const PRIMES39: &'static [u64] = &[
549755812867,
];
const PRIMES40: &'static [u64] = &[
const PRIMES40: &[u64] = &[
1099511627689,
1099511627609,
1099511627581,
@ -741,7 +754,7 @@ const PRIMES40: &'static [u64] = &[
1099511626771,
];
const PRIMES41: &'static [u64] = &[
const PRIMES41: &[u64] = &[
2199023255531,
2199023255521,
2199023255497,
@ -780,7 +793,7 @@ const PRIMES41: &'static [u64] = &[
2199023254567,
];
const PRIMES42: &'static [u64] = &[
const PRIMES42: &[u64] = &[
4398046511093,
4398046511087,
4398046511071,
@ -820,7 +833,7 @@ const PRIMES42: &'static [u64] = &[
4398046510093,
];
const PRIMES43: &'static [u64] = &[
const PRIMES43: &[u64] = &[
8796093022151,
8796093022141,
8796093022091,
@ -855,7 +868,7 @@ const PRIMES43: &'static [u64] = &[
8796093021269,
];
const PRIMES44: &'static [u64] = &[
const PRIMES44: &[u64] = &[
17592186044399,
17592186044299,
17592186044297,
@ -888,7 +901,7 @@ const PRIMES44: &'static [u64] = &[
17592186043409,
];
const PRIMES45: &'static [u64] = &[
const PRIMES45: &[u64] = &[
35184372088777,
35184372088763,
35184372088751,
@ -929,7 +942,7 @@ const PRIMES45: &'static [u64] = &[
35184372087869,
];
const PRIMES46: &'static [u64] = &[
const PRIMES46: &[u64] = &[
70368744177643,
70368744177607,
70368744177601,
@ -964,7 +977,7 @@ const PRIMES46: &'static [u64] = &[
70368744176711,
];
const PRIMES47: &'static [u64] = &[
const PRIMES47: &[u64] = &[
140737488355213,
140737488355201,
140737488355181,
@ -986,7 +999,7 @@ const PRIMES47: &'static [u64] = &[
140737488354329,
];
const PRIMES48: &'static [u64] = &[
const PRIMES48: &[u64] = &[
281474976710597,
281474976710591,
281474976710567,
@ -1019,7 +1032,7 @@ const PRIMES48: &'static [u64] = &[
281474976709637,
];
const PRIMES49: &'static [u64] = &[
const PRIMES49: &[u64] = &[
562949953421231,
562949953421201,
562949953421189,
@ -1053,7 +1066,7 @@ const PRIMES49: &'static [u64] = &[
562949953420297,
];
const PRIMES50: &'static [u64] = &[
const PRIMES50: &[u64] = &[
1125899906842597,
1125899906842589,
1125899906842573,

View file

@ -1,6 +1,6 @@
use crate::common::util::*;
static INPUT: &'static str = "lorem_ipsum.txt";
static INPUT: &str = "lorem_ipsum.txt";
#[test]
fn test_stdin_default() {

View file

@ -116,11 +116,11 @@ fn test_install_ancestors_mode_directories() {
assert!(at.dir_exists(ancestor2));
assert!(at.dir_exists(target_dir));
assert_ne!(0o40700 as u32, at.metadata(ancestor1).permissions().mode());
assert_ne!(0o40700 as u32, at.metadata(ancestor2).permissions().mode());
assert_ne!(0o40_700_u32, at.metadata(ancestor1).permissions().mode());
assert_ne!(0o40_700_u32, at.metadata(ancestor2).permissions().mode());
// Expected mode only on the target_dir.
assert_eq!(0o40700 as u32, at.metadata(target_dir).permissions().mode());
assert_eq!(0o40_700_u32, at.metadata(target_dir).permissions().mode());
}
#[test]
@ -184,7 +184,7 @@ fn test_install_mode_numeric() {
assert!(at.file_exists(file));
assert!(at.file_exists(dest_file));
let permissions = at.metadata(dest_file).permissions();
assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));
assert_eq!(0o100_333_u32, PermissionsExt::mode(&permissions));
let mode_arg = "-m 0333";
at.mkdir(dir2);
@ -195,7 +195,7 @@ fn test_install_mode_numeric() {
assert!(at.file_exists(file));
assert!(at.file_exists(dest_file));
let permissions = at.metadata(dest_file).permissions();
assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));
assert_eq!(0o100_333_u32, PermissionsExt::mode(&permissions));
}
#[test]
@ -213,7 +213,7 @@ fn test_install_mode_symbolic() {
assert!(at.file_exists(file));
assert!(at.file_exists(dest_file));
let permissions = at.metadata(dest_file).permissions();
assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions));
assert_eq!(0o100_003_u32, PermissionsExt::mode(&permissions));
}
#[test]
@ -251,7 +251,7 @@ fn test_install_mode_directories() {
assert!(at.dir_exists(component));
let permissions = at.metadata(component).permissions();
assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
assert_eq!(0o040_333_u32, PermissionsExt::mode(&permissions));
}
#[test]

View file

@ -19,9 +19,7 @@ use std::path::PathBuf;
#[cfg(not(windows))]
use std::sync::Mutex;
#[cfg(not(windows))]
extern crate tempdir;
#[cfg(not(windows))]
use self::tempdir::TempDir;
extern crate tempfile;
#[cfg(not(windows))]
lazy_static! {
@ -53,6 +51,7 @@ fn test_ls_a() {
.unwrap(),
);
#[allow(clippy::trivial_regex)]
let re_pwd = Regex::new(r"^\.\n").unwrap();
// Using the present working directory
@ -126,7 +125,7 @@ fn test_ls_width() {
for option in &["-w 100", "-w=100", "--width=100", "--width 100"] {
scene
.ucmd()
.args(&option.split(" ").collect::<Vec<_>>())
.args(&option.split(' ').collect::<Vec<_>>())
.succeeds()
.stdout_only("test-width-1 test-width-2 test-width-3 test-width-4\n");
}
@ -134,7 +133,7 @@ fn test_ls_width() {
for option in &["-w 50", "-w=50", "--width=50", "--width 50"] {
scene
.ucmd()
.args(&option.split(" ").collect::<Vec<_>>())
.args(&option.split(' ').collect::<Vec<_>>())
.succeeds()
.stdout_only("test-width-1 test-width-3\ntest-width-2 test-width-4\n");
}
@ -151,7 +150,7 @@ fn test_ls_width() {
] {
scene
.ucmd()
.args(&option.split(" ").collect::<Vec<_>>())
.args(&option.split(' ').collect::<Vec<_>>())
.succeeds()
.stdout_only("test-width-1\ntest-width-2\ntest-width-3\ntest-width-4\n");
}
@ -165,7 +164,7 @@ fn test_ls_width() {
for option in &["-w 1a", "-w=1a", "--width=1a", "--width 1a"] {
scene
.ucmd()
.args(&option.split(" ").collect::<Vec<_>>())
.args(&option.split(' ').collect::<Vec<_>>())
.fails()
.stderr_only("ls: invalid line width: 1a");
}
@ -419,7 +418,7 @@ fn test_ls_long_formats() {
] {
let result = scene
.ucmd()
.args(&arg.split(" ").collect::<Vec<_>>())
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_two.is_match(result.stdout_str()));
@ -429,7 +428,7 @@ fn test_ls_long_formats() {
let result = scene
.ucmd()
.arg("-n")
.args(&arg.split(" ").collect::<Vec<_>>())
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_two_num.is_match(result.stdout_str()));
@ -448,7 +447,7 @@ fn test_ls_long_formats() {
] {
let result = scene
.ucmd()
.args(&arg.split(" ").collect::<Vec<_>>())
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_one.is_match(result.stdout_str()));
@ -458,7 +457,7 @@ fn test_ls_long_formats() {
let result = scene
.ucmd()
.arg("-n")
.args(&arg.split(" ").collect::<Vec<_>>())
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_one_num.is_match(result.stdout_str()));
@ -480,7 +479,7 @@ fn test_ls_long_formats() {
] {
let result = scene
.ucmd()
.args(&arg.split(" ").collect::<Vec<_>>())
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_zero.is_match(result.stdout_str()));
@ -490,7 +489,7 @@ fn test_ls_long_formats() {
let result = scene
.ucmd()
.arg("-n")
.args(&arg.split(" ").collect::<Vec<_>>())
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_zero.is_match(result.stdout_str()));
@ -1065,7 +1064,7 @@ fn test_ls_indicator_style() {
for opt in options {
scene
.ucmd()
.arg(format!("{}", opt))
.arg(opt.to_string())
.succeeds()
.stdout_contains(&"/");
}
@ -1087,7 +1086,10 @@ fn test_ls_indicator_style() {
{
use self::unix_socket::UnixListener;
let dir = TempDir::new("unix_socket").expect("failed to create dir");
let dir = tempfile::Builder::new()
.prefix("unix_socket")
.tempdir()
.expect("failed to create dir");
let socket_path = dir.path().join("sock");
let _listener = UnixListener::bind(&socket_path).expect("failed to create socket");

View file

@ -1,12 +1,12 @@
use crate::common::util::*;
static TEST_DIR1: &'static str = "mkdir_test1";
static TEST_DIR2: &'static str = "mkdir_test2";
static TEST_DIR3: &'static str = "mkdir_test3";
static TEST_DIR4: &'static str = "mkdir_test4/mkdir_test4_1";
static TEST_DIR5: &'static str = "mkdir_test5/mkdir_test5_1";
static TEST_DIR6: &'static str = "mkdir_test6";
static TEST_FILE7: &'static str = "mkdir_test7";
static TEST_DIR1: &str = "mkdir_test1";
static TEST_DIR2: &str = "mkdir_test2";
static TEST_DIR3: &str = "mkdir_test3";
static TEST_DIR4: &str = "mkdir_test4/mkdir_test4_1";
static TEST_DIR5: &str = "mkdir_test5/mkdir_test5_1";
static TEST_DIR6: &str = "mkdir_test6";
static TEST_FILE7: &str = "mkdir_test7";
#[test]
fn test_mkdir_mkdir() {

View file

@ -3,19 +3,19 @@ use crate::common::util::*;
use std::path::PathBuf;
use tempfile::tempdir;
static TEST_TEMPLATE1: &'static str = "tempXXXXXX";
static TEST_TEMPLATE2: &'static str = "temp";
static TEST_TEMPLATE3: &'static str = "tempX";
static TEST_TEMPLATE4: &'static str = "tempXX";
static TEST_TEMPLATE5: &'static str = "tempXXX";
static TEST_TEMPLATE6: &'static str = "tempXXXlate";
static TEST_TEMPLATE7: &'static str = "XXXtemplate";
static TEST_TEMPLATE1: &str = "tempXXXXXX";
static TEST_TEMPLATE2: &str = "temp";
static TEST_TEMPLATE3: &str = "tempX";
static TEST_TEMPLATE4: &str = "tempXX";
static TEST_TEMPLATE5: &str = "tempXXX";
static TEST_TEMPLATE6: &str = "tempXXXlate";
static TEST_TEMPLATE7: &str = "XXXtemplate";
#[cfg(unix)]
static TEST_TEMPLATE8: &'static str = "tempXXXl/ate";
static TEST_TEMPLATE8: &str = "tempXXXl/ate";
#[cfg(windows)]
static TEST_TEMPLATE8: &'static str = "tempXXXl\\ate";
static TEST_TEMPLATE8: &str = "tempXXXl\\ate";
const TMPDIR: &'static str = "TMPDIR";
const TMPDIR: &str = "TMPDIR";
#[test]
fn test_mktemp_mktemp() {

View file

@ -82,7 +82,7 @@ fn test_mv_strip_slashes() {
let dir = "test_mv_strip_slashes_dir";
let file = "test_mv_strip_slashes_file";
let mut source = file.to_owned();
source.push_str("/");
source.push('/');
at.mkdir(dir);
at.touch(file);

View file

@ -9,7 +9,7 @@ use std::io::Write;
use std::path::Path;
// octal dump of 'abcdefghijklmnopqrstuvwxyz\n'
static ALPHA_OUT: &'static str = "
static ALPHA_OUT: &str = "
0000000 061141 062143 063145 064147 065151 066153 067155 070157
0000020 071161 072163 073165 074167 075171 000012
0000033
@ -563,7 +563,7 @@ fn test_dec_offset() {
#[test]
fn test_no_offset() {
let input = [0u8; 31];
const LINE: &'static str = " 00000000 00000000 00000000 00000000\n";
const LINE: &str = " 00000000 00000000 00000000 00000000\n";
let expected_output = [LINE, LINE, LINE, LINE].join("");
new_ucmd!()

View file

@ -7,7 +7,7 @@ struct TestData<'b> {
out: &'b str,
}
static EXAMPLE_DATA: &'static [TestData<'static>] = &[
static EXAMPLE_DATA: &[TestData] = &[
// Ensure that paste properly handles files lacking a final newline.
TestData {
name: "no-nl-1",
@ -64,8 +64,8 @@ static EXAMPLE_DATA: &'static [TestData<'static>] = &[
#[test]
fn test_combine_pairs_of_lines() {
for s in vec!["-s", "--serial"] {
for d in vec!["-d", "--delimiters"] {
for &s in &["-s", "--serial"] {
for &d in &["-d", "--delimiters"] {
new_ucmd!()
.args(&[s, d, "\t\n", "html_colors.txt"])
.run()
@ -76,7 +76,7 @@ fn test_combine_pairs_of_lines() {
#[test]
fn test_multi_stdin() {
for d in vec!["-d", "--delimiters"] {
for &d in &["-d", "--delimiters"] {
new_ucmd!()
.args(&[d, "\t\n", "-", "-"])
.pipe_in_fixture("html_colors.txt")

View file

@ -1,6 +1,6 @@
use crate::common::util::*;
static GIBBERISH: &'static str = "supercalifragilisticexpialidocious";
static GIBBERISH: &str = "supercalifragilisticexpialidocious";
#[test]
fn test_canonicalize() {

View file

@ -61,6 +61,7 @@ const TESTS: [TestCase; 10] = [
},
];
#[allow(clippy::needless_lifetimes)]
fn convert_path<'a>(path: &'a str) -> Cow<'a, str> {
#[cfg(windows)]
return path.replace("/", "\\").into();

View file

@ -108,3 +108,19 @@ fn test_rmdir_ignore_nonempty_directory_with_parents() {
assert!(at.dir_exists(dir));
}
#[test]
fn test_rmdir_remove_symlink_match_gnu_error() {
let (at, mut ucmd) = at_and_ucmd!();
let file = "file";
let fl = "fl";
at.touch(file);
assert!(at.file_exists(file));
at.symlink_file(file, fl);
assert!(at.file_exists(fl));
ucmd.arg("fl/")
.fails()
.stderr_is("rmdir: failed to remove 'fl/': Not a directory");
}

View file

@ -14,11 +14,11 @@ fn test_output_is_random_permutation() {
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.split('\n')
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
result_seq.sort_unstable();
assert_ne!(result.stdout_str(), input, "Output is not randomised");
assert_eq!(result_seq, input_seq, "Output is not a permutation");
}
@ -31,11 +31,11 @@ fn test_zero_termination() {
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\0")
.split('\0')
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
result_seq.sort_unstable();
assert_eq!(result_seq, input_seq, "Output is not a permutation");
}
@ -55,11 +55,11 @@ fn test_echo() {
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.split('\n')
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
result_seq.sort_unstable();
assert_eq!(result_seq, input_seq, "Output is not a permutation");
}
@ -81,11 +81,11 @@ fn test_head_count() {
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.split('\n')
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
result_seq.sort_unstable();
assert_eq!(result_seq.len(), repeat_limit, "Output is not limited");
assert!(
result_seq.iter().all(|x| input_seq.contains(x)),
@ -113,7 +113,7 @@ fn test_repeat() {
let result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.split('\n')
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
@ -141,11 +141,11 @@ fn test_file_input() {
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.split('\n')
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
result_seq.sort_unstable();
assert_eq!(result_seq, expected_seq, "Output is not a permutation");
}

View file

@ -4,14 +4,14 @@ fn test_helper(file_name: &str, possible_args: &[&str]) {
for args in possible_args {
new_ucmd!()
.arg(format!("{}.txt", file_name))
.args(&args.split(' ').collect::<Vec<&str>>())
.args(&args.split_whitespace().collect::<Vec<&str>>())
.succeeds()
.stdout_is_fixture(format!("{}.expected", file_name));
new_ucmd!()
.arg(format!("{}.txt", file_name))
.arg("--debug")
.args(&args.split(' ').collect::<Vec<&str>>())
.args(&args.split_whitespace().collect::<Vec<&str>>())
.succeeds()
.stdout_is_fixture(format!("{}.expected.debug", file_name));
}
@ -288,7 +288,7 @@ fn test_dictionary_order() {
#[test]
fn test_dictionary_order2() {
for non_dictionary_order2_param in vec!["-d"] {
for non_dictionary_order2_param in &["-d"] {
new_ucmd!()
.pipe_in("a👦🏻aa b\naaaa b")
.arg(non_dictionary_order2_param)
@ -299,7 +299,7 @@ fn test_dictionary_order2() {
#[test]
fn test_non_printing_chars() {
for non_printing_chars_param in vec!["-i"] {
for non_printing_chars_param in &["-i"] {
new_ucmd!()
.pipe_in("a👦🏻aa\naaaa")
.arg(non_printing_chars_param)
@ -361,7 +361,7 @@ fn test_mixed_floats_ints_chars_numeric_stable() {
#[test]
fn test_numeric_floats_and_ints2() {
for numeric_sort_param in vec!["-n", "--numeric-sort"] {
for numeric_sort_param in &["-n", "--numeric-sort"] {
let input = "1.444\n8.013\n1\n-8\n1.04\n-1";
new_ucmd!()
.arg(numeric_sort_param)
@ -373,7 +373,7 @@ fn test_numeric_floats_and_ints2() {
#[test]
fn test_numeric_floats2() {
for numeric_sort_param in vec!["-n", "--numeric-sort"] {
for numeric_sort_param in &["-n", "--numeric-sort"] {
let input = "1.444\n8.013\n1.58590\n-8.90880\n1.040000000\n-.05";
new_ucmd!()
.arg(numeric_sort_param)
@ -426,7 +426,7 @@ fn test_default_unsorted_ints2() {
#[test]
fn test_numeric_unique_ints2() {
for numeric_unique_sort_param in vec!["-nu"] {
for numeric_unique_sort_param in &["-nu"] {
let input = "9\n9\n8\n1\n";
new_ucmd!()
.arg(numeric_unique_sort_param)
@ -471,7 +471,7 @@ fn test_keys_invalid_field() {
new_ucmd!()
.args(&["-k", "1."])
.fails()
.stderr_only("sort: failed to parse character index for key `1.`: cannot parse integer from empty string");
.stderr_only("sort: failed to parse key `1.`: failed to parse character index ``: cannot parse integer from empty string");
}
#[test]
@ -479,7 +479,7 @@ fn test_keys_invalid_field_option() {
new_ucmd!()
.args(&["-k", "1.1x"])
.fails()
.stderr_only("sort: invalid option for key: `x`");
.stderr_only("sort: failed to parse key `1.1x`: invalid option: `x`");
}
#[test]
@ -487,7 +487,7 @@ fn test_keys_invalid_field_zero() {
new_ucmd!()
.args(&["-k", "0.1"])
.fails()
.stderr_only("sort: field index was 0");
.stderr_only("sort: failed to parse key `0.1`: field index can not be 0");
}
#[test]
@ -495,7 +495,7 @@ fn test_keys_invalid_char_zero() {
new_ucmd!()
.args(&["-k", "1.0"])
.fails()
.stderr_only("sort: invalid character index 0 in `1.0` for the start position of a field");
.stderr_only("sort: failed to parse key `1.0`: invalid character index 0 for the start position of a field");
}
#[test]
@ -526,6 +526,11 @@ fn test_keys_with_options_blanks_start() {
}
}
#[test]
fn test_keys_blanks_with_char_idx() {
test_helper("keys_blanks", &["-k 1.2b"])
}
#[test]
fn test_keys_with_options_blanks_end() {
let input = "a b
@ -574,6 +579,54 @@ aaaa
.stdout_only(input);
}
#[test]
fn test_keys_negative_size_match() {
// If the end of a field is before its start, we should not crash.
// Debug output should report "no match for key" at the start position (i.e. the later position).
test_helper("keys_negative_size", &["-k 3,1"]);
}
#[test]
fn test_keys_ignore_flag() {
test_helper("keys_ignore_flag", &["-k 1n -b"])
}
#[test]
fn test_doesnt_inherit_key_settings() {
let input = " 1
2
10
";
new_ucmd!()
.args(&["-k", "1b", "-n"])
.pipe_in(input)
.succeeds()
.stdout_only(
" 1
10
2
",
);
}
#[test]
fn test_inherits_key_settings() {
let input = " 1
2
10
";
new_ucmd!()
.args(&["-k", "1", "-n"])
.pipe_in(input)
.succeeds()
.stdout_only(
" 1
2
10
",
);
}
#[test]
fn test_zero_terminated() {
test_helper("zero-terminated", &["-z"]);
@ -695,10 +748,9 @@ fn test_dictionary_and_nonprinting_conflicts() {
.succeeds();
}
for conflicting_arg in &conflicting_args {
// FIXME: this should ideally fail.
new_ucmd!()
.args(&["-k", &format!("1{},1{}", restricted_arg, conflicting_arg)])
.succeeds();
.fails();
}
}
}
@ -711,3 +763,22 @@ fn test_trailing_separator() {
.succeeds()
.stdout_is("aax\naaa\n");
}
#[test]
fn test_nonexistent_file() {
new_ucmd!()
.arg("nonexistent.txt")
.fails()
.status_code(2)
.stderr_only(
#[cfg(not(windows))]
"sort: cannot read: \"nonexistent.txt\": No such file or directory (os error 2)",
#[cfg(windows)]
"sort: cannot read: \"nonexistent.txt\": The system cannot find the file specified. (os error 2)",
);
}
#[test]
fn test_blanks() {
test_helper("blanks", &["-b", "--ignore-blanks"]);
}

View file

@ -98,7 +98,7 @@ impl RandomFile {
let to_write = std::cmp::min(remaining_size, buffer.len());
let buf = &mut buffer[..to_write];
rng.fill(buf);
writer.write(buf).unwrap();
writer.write_all(buf).unwrap();
remaining_size -= to_write;
}
@ -179,6 +179,7 @@ fn test_split_bytes_prime_part_size() {
let mut fns = glob.collect();
// glob.collect() is not guaranteed to return in sorted order, so we sort.
fns.sort();
#[allow(clippy::needless_range_loop)]
for i in 0..5 {
assert_eq!(glob.directory.metadata(&fns[i]).len(), 1753);
}
@ -246,9 +247,9 @@ fn test_filter() {
assert!(
glob.collate().iter().find(|&&c| {
// is not i
c != ('i' as u8)
c != (b'i')
// is not newline
&& c != ('\n' as u8)
&& c != (b'\n')
}) == None
);
}
@ -271,7 +272,7 @@ fn test_filter_with_env_var_set() {
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
assert_eq!(glob.collate(), at.read_bytes(name));
assert!(env::var("FILE").unwrap_or("var was unset".to_owned()) == env_var_value);
assert!(env::var("FILE").unwrap_or_else(|_| "var was unset".to_owned()) == env_var_value);
}
#[test]

View file

@ -97,13 +97,13 @@ fn test_invalid_option() {
}
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
const NORMAL_FMTSTR: &'static str =
const NORMAL_FMTSTR: &str =
"%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s %u %U %x %X %y %Y %z %Z"; // avoid "%w %W" (birth/creation) due to `stat` limitations and linux kernel & rust version capability variations
#[cfg(any(target_os = "linux"))]
const DEV_FMTSTR: &'static str =
const DEV_FMTSTR: &str =
"%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (%t/%T) %u %U %w %W %x %X %y %Y %z %Z";
#[cfg(target_os = "linux")]
const FS_FMTSTR: &'static str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions
const FS_FMTSTR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions
#[test]
#[cfg(target_os = "linux")]
@ -140,7 +140,7 @@ fn test_terse_normal_format() {
assert!(!v_expect.is_empty());
// uu_stat does not support selinux
if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(":") {
if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(':') {
// assume last element contains: `SELinux security context string`
v_expect.pop();
}
@ -222,7 +222,7 @@ fn test_symlinks() {
let mut tested: bool = false;
// arbitrarily chosen symlinks with hope that the CI environment provides at least one of them
for file in vec![
for file in &[
"/bin/sh",
"/bin/sudoedit",
"/usr/bin/ex",

View file

@ -5,9 +5,9 @@ use crate::common::util::*;
use std::char::from_digit;
use std::io::Write;
static FOOBAR_TXT: &'static str = "foobar.txt";
static FOOBAR_2_TXT: &'static str = "foobar2.txt";
static FOOBAR_WITH_NULL_TXT: &'static str = "foobar_with_null.txt";
static FOOBAR_TXT: &str = "foobar.txt";
static FOOBAR_2_TXT: &str = "foobar2.txt";
static FOOBAR_WITH_NULL_TXT: &str = "foobar_with_null.txt";
#[test]
fn test_stdin_default() {
@ -153,8 +153,8 @@ fn test_follow_with_pid() {
#[test]
fn test_single_big_args() {
const FILE: &'static str = "single_big_args.txt";
const EXPECTED_FILE: &'static str = "single_big_args_expected.txt";
const FILE: &str = "single_big_args.txt";
const EXPECTED_FILE: &str = "single_big_args_expected.txt";
const LINES: usize = 1_000_000;
const N_ARG: usize = 100_000;
@ -162,13 +162,13 @@ fn test_single_big_args() {
let mut big_input = at.make_file(FILE);
for i in 0..LINES {
write!(&mut big_input, "Line {}\n", i).expect("Could not write to FILE");
writeln!(&mut big_input, "Line {}", i).expect("Could not write to FILE");
}
big_input.flush().expect("Could not flush FILE");
let mut big_expected = at.make_file(EXPECTED_FILE);
for i in (LINES - N_ARG)..LINES {
write!(&mut big_expected, "Line {}\n", i).expect("Could not write to EXPECTED_FILE");
writeln!(&mut big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE");
}
big_expected.flush().expect("Could not flush EXPECTED_FILE");
@ -201,8 +201,8 @@ fn test_bytes_stdin() {
#[test]
fn test_bytes_big() {
const FILE: &'static str = "test_bytes_big.txt";
const EXPECTED_FILE: &'static str = "test_bytes_big_expected.txt";
const FILE: &str = "test_bytes_big.txt";
const EXPECTED_FILE: &str = "test_bytes_big_expected.txt";
const BYTES: usize = 1_000_000;
const N_ARG: usize = 100_000;
@ -257,10 +257,10 @@ fn test_parse_size() {
for &(c, exp) in &suffixes {
let s = format!("2{}B", c);
assert_eq!(Ok(2 * (1000 as u64).pow(exp)), parse_size(&s));
assert_eq!(Ok(2 * (1000_u64).pow(exp)), parse_size(&s));
let s = format!("2{}", c);
assert_eq!(Ok(2 * (1024 as u64).pow(exp)), parse_size(&s));
assert_eq!(Ok(2 * (1024_u64).pow(exp)), parse_size(&s));
}
// Sizes that are too big.
@ -273,8 +273,8 @@ fn test_parse_size() {
#[test]
fn test_lines_with_size_suffix() {
const FILE: &'static str = "test_lines_with_size_suffix.txt";
const EXPECTED_FILE: &'static str = "test_lines_with_size_suffix_expected.txt";
const FILE: &str = "test_lines_with_size_suffix.txt";
const EXPECTED_FILE: &str = "test_lines_with_size_suffix_expected.txt";
const LINES: usize = 3_000;
const N_ARG: usize = 2 * 1024;

View file

@ -401,8 +401,8 @@ fn get_dstswitch_hour() -> Option<String> {
for _i in 0..(366 * 24) {
if is_dst_switch_hour(ts) {
let mut tm = time::at(ts);
tm.tm_hour = tm.tm_hour + 1;
let s = time::strftime("%Y%m%d%H%M", &tm).unwrap().to_string();
tm.tm_hour += 1;
let s = time::strftime("%Y%m%d%H%M", &tm).unwrap();
return Some(s);
}
ts = ts + time::Duration::hours(1);
@ -415,10 +415,7 @@ fn test_touch_mtime_dst_fails() {
let (_at, mut ucmd) = at_and_ucmd!();
let file = "test_touch_set_mtime_dst_fails";
match get_dstswitch_hour() {
Some(s) => {
if let Some(s) = get_dstswitch_hour() {
ucmd.args(&["-m", "-t", &s, file]).fails();
}
None => (),
}
}

View file

@ -1,8 +1,8 @@
use crate::common::util::*;
use std::io::{Seek, SeekFrom, Write};
static TFILE1: &'static str = "truncate_test_1";
static TFILE2: &'static str = "truncate_test_2";
static TFILE1: &str = "truncate_test_1";
static TFILE2: &str = "truncate_test_2";
#[test]
fn test_increase_file_size() {
@ -262,3 +262,11 @@ fn test_reference_file_not_found() {
.fails()
.stderr_contains("cannot stat 'a': No such file or directory");
}
#[test]
fn test_reference_with_size_file_not_found() {
new_ucmd!()
.args(&["-r", "a", "-s", "+1", "b"])
.fails()
.stderr_contains("cannot stat 'a': No such file or directory");
}

View file

@ -1,10 +1,10 @@
use crate::common::util::*;
static INPUT: &'static str = "sorted.txt";
static OUTPUT: &'static str = "sorted-output.txt";
static SKIP_CHARS: &'static str = "skip-chars.txt";
static SKIP_FIELDS: &'static str = "skip-fields.txt";
static SORTED_ZERO_TERMINATED: &'static str = "sorted-zero-terminated.txt";
static INPUT: &str = "sorted.txt";
static OUTPUT: &str = "sorted-output.txt";
static SKIP_CHARS: &str = "skip-chars.txt";
static SKIP_FIELDS: &str = "skip-fields.txt";
static SORTED_ZERO_TERMINATED: &str = "sorted-zero-terminated.txt";
#[test]
fn test_stdin_default() {

View file

@ -1,27 +1,23 @@
use crate::common::util::*;
use std::env;
#[test]
fn test_users_noarg() {
new_ucmd!().succeeds();
}
#[test]
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
fn test_users_check_name() {
let result = TestScenario::new(util_name!()).ucmd_keepenv().succeeds();
#[cfg(target_os = "linux")]
let util_name = util_name!();
#[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!());
// Expectation: USER is often set
let key = "USER";
let expected = TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.succeeds()
.stdout_move_str();
match env::var(key) {
Err(e) => println!("Key {} isn't set. Found {}", &key, e),
Ok(username) =>
// Check if "users" contains the name of the user
{
println!("username found {}", &username);
// println!("result.stdout {}", &result.stdout);
if !result.stdout_str().is_empty() {
result.stdout_contains(&username);
}
}
}
new_ucmd!().succeeds().stdout_is(&expected);
}

View file

@ -3,7 +3,7 @@ use crate::common::util::*;
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_count() {
for opt in vec!["-q", "--count"] {
for opt in &["-q", "--count"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -14,7 +14,7 @@ fn test_count() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_boot() {
for opt in vec!["-b", "--boot"] {
for opt in &["-b", "--boot"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -25,7 +25,7 @@ fn test_boot() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_heading() {
for opt in vec!["-H", "--heading"] {
for opt in &["-H", "--heading"] {
// allow whitespace variation
// * minor whitespace differences occur between platform built-in outputs;
// specifically number of TABs between "TIME" and "COMMENT" may be variant
@ -42,7 +42,7 @@ fn test_heading() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_short() {
for opt in vec!["-s", "--short"] {
for opt in &["-s", "--short"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -53,7 +53,7 @@ fn test_short() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_login() {
for opt in vec!["-l", "--login"] {
for opt in &["-l", "--login"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -64,7 +64,7 @@ fn test_login() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_m() {
for opt in vec!["-m"] {
for opt in &["-m"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -75,7 +75,7 @@ fn test_m() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_process() {
for opt in vec!["-p", "--process"] {
for opt in &["-p", "--process"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -85,7 +85,7 @@ fn test_process() {
#[test]
fn test_runlevel() {
for opt in vec!["-r", "--runlevel"] {
for opt in &["-r", "--runlevel"] {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
new_ucmd!()
.arg(opt)
@ -100,7 +100,7 @@ fn test_runlevel() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_time() {
for opt in vec!["-t", "--time"] {
for opt in &["-t", "--time"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -117,7 +117,7 @@ fn test_mesg() {
// same as -T
// --writable
// same as -T
for opt in vec!["-T", "-w", "--mesg", "--message", "--writable"] {
for opt in &["-T", "-w", "--mesg", "--message", "--writable"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -147,7 +147,7 @@ fn test_too_many_args() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_users() {
for opt in vec!["-u", "--users"] {
for opt in &["-u", "--users"] {
let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str();
let expect = expected_result(&[opt]);
println!("actual: {:?}", actual);
@ -172,18 +172,17 @@ fn test_users() {
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_lookup() {
for opt in vec!["--lookup"] {
let opt = "--lookup";
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(&[opt]));
}
}
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
#[test]
fn test_dead() {
for opt in vec!["-d", "--dead"] {
for opt in &["-d", "--dead"] {
new_ucmd!()
.arg(opt)
.succeeds()
@ -222,7 +221,7 @@ fn test_all() {
return;
}
for opt in vec!["-a", "--all"] {
for opt in &["-a", "--all"] {
new_ucmd!()
.arg(opt)
.succeeds()

View file

@ -1,7 +1,4 @@
#![allow(dead_code)]
#[cfg(not(windows))]
use libc;
use pretty_assertions::assert_eq;
use std::env;
#[cfg(not(windows))]
@ -16,7 +13,6 @@ use std::os::windows::fs::{symlink_dir, symlink_file};
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Stdio};
use std::rc::Rc;
use std::str::from_utf8;
use std::thread::sleep;
use std::time::Duration;
use tempfile::TempDir;
@ -40,7 +36,7 @@ static NO_STDIN_MEANINGLESS: &str = "Setting this flag has no effect if there is
/// Test if the program is running under CI
pub fn is_ci() -> bool {
std::env::var("CI")
.unwrap_or(String::from("false"))
.unwrap_or_else(|_| String::from("false"))
.eq_ignore_ascii_case("true")
}
@ -62,54 +58,54 @@ pub struct CmdResult {
/// see [`success`]
success: bool,
/// captured standard output after running the Command
stdout: String,
stdout: Vec<u8>,
/// captured standard error after running the Command
stderr: String,
stderr: Vec<u8>,
}
impl CmdResult {
/// Returns a reference to the program's standard output as a slice of bytes
pub fn stdout(&self) -> &[u8] {
&self.stdout.as_bytes()
&self.stdout
}
/// Returns the program's standard output as a string slice
pub fn stdout_str(&self) -> &str {
&self.stdout
std::str::from_utf8(&self.stdout).unwrap()
}
/// Returns the program's standard output as a string
/// consumes self
pub fn stdout_move_str(self) -> String {
self.stdout
String::from_utf8(self.stdout).unwrap()
}
/// Returns the program's standard output as a vec of bytes
/// consumes self
pub fn stdout_move_bytes(self) -> Vec<u8> {
Vec::from(self.stdout)
self.stdout
}
/// Returns a reference to the program's standard error as a slice of bytes
pub fn stderr(&self) -> &[u8] {
&self.stderr.as_bytes()
&self.stderr
}
/// Returns the program's standard error as a string slice
pub fn stderr_str(&self) -> &str {
&self.stderr
std::str::from_utf8(&self.stderr).unwrap()
}
/// Returns the program's standard error as a string
/// consumes self
pub fn stderr_move_str(self) -> String {
self.stderr
String::from_utf8(self.stderr).unwrap()
}
/// Returns the program's standard error as a vec of bytes
/// consumes self
pub fn stderr_move_bytes(self) -> Vec<u8> {
Vec::from(self.stderr)
self.stderr
}
/// Returns the program's exit code
@ -202,21 +198,21 @@ impl CmdResult {
/// passed in value, trailing whitespace are kept to force strict comparison (#1235)
/// stdout_only is a better choice unless stderr may or will be non-empty
pub fn stdout_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
assert_eq!(self.stdout, String::from(msg.as_ref()));
assert_eq!(self.stdout_str(), String::from(msg.as_ref()));
self
}
/// Like `stdout_is` but newlines are normalized to `\n`.
pub fn normalized_newlines_stdout_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
let msg = msg.as_ref().replace("\r\n", "\n");
assert_eq!(self.stdout.replace("\r\n", "\n"), msg);
assert_eq!(self.stdout_str().replace("\r\n", "\n"), msg);
self
}
/// asserts that the command resulted in stdout stream output,
/// whose bytes equal those of the passed in slice
pub fn stdout_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
assert_eq!(self.stdout.as_bytes(), msg.as_ref());
assert_eq!(self.stdout, msg.as_ref());
self
}
@ -231,7 +227,7 @@ impl CmdResult {
/// stderr_only is a better choice unless stdout may or will be non-empty
pub fn stderr_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
assert_eq!(
self.stderr.trim_end(),
self.stderr_str().trim_end(),
String::from(msg.as_ref()).trim_end()
);
self
@ -240,7 +236,7 @@ impl CmdResult {
/// asserts that the command resulted in stderr stream output,
/// whose bytes equal those of the passed in slice
pub fn stderr_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
assert_eq!(self.stderr.as_bytes(), msg.as_ref());
assert_eq!(self.stderr, msg.as_ref());
self
}
@ -465,7 +461,7 @@ impl AtPath {
.append(true)
.open(self.plus(name))
.unwrap();
f.write(contents.as_bytes())
f.write_all(contents.as_bytes())
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
}
@ -778,7 +774,7 @@ impl UCommand {
if self.has_run {
panic!("{}", ALREADY_RUN);
}
self.comm_string.push_str(" ");
self.comm_string.push(' ');
self.comm_string
.push_str(arg.as_ref().to_str().unwrap_or_default());
self.raw.arg(arg.as_ref());
@ -798,7 +794,7 @@ impl UCommand {
.accept_any();
for s in strings {
self.comm_string.push_str(" ");
self.comm_string.push(' ');
self.comm_string.push_str(&s);
}
@ -854,9 +850,9 @@ impl UCommand {
log_info("run", &self.comm_string);
let mut child = self
.raw
.stdin(self.stdin.take().unwrap_or_else(|| Stdio::piped()))
.stdout(self.stdout.take().unwrap_or_else(|| Stdio::piped()))
.stderr(self.stderr.take().unwrap_or_else(|| Stdio::piped()))
.stdin(self.stdin.take().unwrap_or_else(Stdio::piped))
.stdout(self.stdout.take().unwrap_or_else(Stdio::piped))
.stderr(self.stderr.take().unwrap_or_else(Stdio::piped))
.spawn()
.unwrap();
@ -886,8 +882,8 @@ impl UCommand {
tmpd: self.tmpd.clone(),
code: prog.status.code(),
success: prog.status.success(),
stdout: from_utf8(&prog.stdout).unwrap().to_string(),
stderr: from_utf8(&prog.stderr).unwrap().to_string(),
stdout: prog.stdout,
stderr: prog.stderr,
}
}
@ -930,10 +926,7 @@ pub fn read_size(child: &mut Child, size: usize) -> String {
}
pub fn vec_of_size(n: usize) -> Vec<u8> {
let mut result = Vec::new();
for _ in 0..n {
result.push('a' as u8);
}
let result = vec![b'a'; n];
assert_eq!(result.len(), n);
result
}

5
tests/fixtures/sort/blanks.expected vendored Normal file
View file

@ -0,0 +1,5 @@
a
b
x
x
z

View file

@ -0,0 +1,15 @@
a
_
___
b
_
_
x
_
__________
x
_
___
z
_
__

5
tests/fixtures/sort/blanks.txt vendored Normal file
View file

@ -0,0 +1,5 @@
b
a
z
x
x

View file

@ -6,8 +6,15 @@
-12e-5555.5
0b10 // binary not supported
0x10 // hexadecimal not supported, but it should be
55e-20
55e-20.10
5.5.5.5
10E
64e+
99e-
1000EDKLD
10000K78
+100000
@ -15,5 +22,7 @@
100E6
100E6
10e10e10e10
13e+10
45e+10.5
50e10
50e10

View file

@ -22,12 +22,33 @@
^ no match for key
^ no match for key
> -12e-5555.5
_________
______________
0b10 // binary not supported
_
____________________________
0x10 // hexadecimal not supported, but it should be
_
___________________________________________________
55e-20
______
______
55e-20.10
______
_________
5.5.5.5
___
_______
10E
__
___
64e+
__
____
99e-
__
____
1000EDKLD
____
_________
@ -49,6 +70,12 @@ _____
10e10e10e10
_____
___________
13e+10
______
______
45e+10.5
______
________
50e10
_____
_____

View file

@ -4,16 +4,25 @@
+100000
10000K78
0x10 // hexadecimal not supported, but it should be
10E
0b10 // binary not supported
64e+
99e-
45e+10.5
1000EDKLD
13e+10
100E6
50e10
-12e-5555.5
+100000
10e10e10e10
5.5.5.5
55e-20
55e-20.10

View file

@ -0,0 +1,3 @@
cab
abc
bca

View file

@ -0,0 +1,9 @@
>cab
__
____
>abc
__
____
>bca
__
____

3
tests/fixtures/sort/keys_blanks.txt vendored Normal file
View file

@ -0,0 +1,3 @@
abc
cab
bca

View file

@ -0,0 +1,2 @@
1a
1A

View file

@ -0,0 +1,6 @@
1a
_
___
1A
_
__

View file

@ -0,0 +1,2 @@
1a
1A

View file

@ -0,0 +1 @@
a b c

View file

@ -0,0 +1,3 @@
a b c
^ no match for key
_____

View file

@ -0,0 +1 @@
a b c

Some files were not shown because too many files have changed in this diff Show more