Merge branch 'master' into pr

This commit is contained in:
Terts Diepraam 2021-05-31 15:23:06 +02:00
commit 7690dc018f
76 changed files with 1318 additions and 938 deletions

View file

@ -84,7 +84,7 @@ jobs:
- name: Install `rust` toolchain - name: Install `rust` toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: nightly
default: true default: true
profile: minimal # minimal component installation (ie, no documentation) profile: minimal # minimal component installation (ie, no documentation)
components: clippy components: clippy
@ -94,7 +94,7 @@ jobs:
run: | run: |
# `clippy` testing # `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> # * 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 --all-targets ${{ 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: min_version:
name: MinRustV # Minimum supported rust version name: MinRustV # Minimum supported rust version
@ -614,3 +614,20 @@ jobs:
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }} flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
name: codecov-umbrella name: codecov-umbrella
fail_ci_if_error: false 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

View file

@ -1,8 +1,17 @@
# https://pre-commit.com
repos: repos:
- repo: https://github.com/doublify/pre-commit-rust - repo: local
rev: v1.0
hooks: hooks:
- id: cargo-check - id: rust-linting
- id: clippy name: Rust linting
- id: fmt description: Run cargo fmt on files included in the commit.
entry: cargo +nightly fmt --
pass_filenames: true
types: [file, rust]
language: system
- id: rust-clippy
name: Rust clippy
description: Run cargo clippy on files included in the commit.
entry: cargo +nightly clippy --all-targets --all-features --
pass_filenames: false
types: [file, rust]
language: system

462
Cargo.lock generated
View file

@ -43,12 +43,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "array-init"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.4.12" version = "0.4.12"
@ -134,15 +128,8 @@ dependencies = [
"lazy_static", "lazy_static",
"memchr 2.4.0", "memchr 2.4.0",
"regex-automata", "regex-automata",
"serde",
] ]
[[package]]
name = "bumpalo"
version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
[[package]] [[package]]
name = "byte-tools" name = "byte-tools"
version = "0.2.0" version = "0.2.0"
@ -155,20 +142,11 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 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]] [[package]]
name = "cc" name = "cc"
version = "1.0.67" version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -244,6 +222,7 @@ dependencies = [
name = "coreutils" name = "coreutils"
version = "0.0.6" version = "0.0.6"
dependencies = [ dependencies = [
"atty",
"chrono", "chrono",
"conv", "conv",
"filetime", "filetime",
@ -285,7 +264,6 @@ dependencies = [
"uu_expand", "uu_expand",
"uu_expr", "uu_expr",
"uu_factor", "uu_factor",
"uu_factor_benches",
"uu_false", "uu_false",
"uu_fmt", "uu_fmt",
"uu_fold", "uu_fold",
@ -465,42 +443,6 @@ dependencies = [
"unicode-xid 0.0.4", "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]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.1" version = "0.5.1"
@ -524,9 +466,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.4" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94" checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"crossbeam-utils", "crossbeam-utils",
@ -537,35 +479,37 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.4" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278" checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [ dependencies = [
"autocfg",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"lazy_static", "lazy_static",
] ]
[[package]] [[package]]
name = "csv" name = "crossterm"
version = "1.1.6" version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" checksum = "7c36c10130df424b2f3552fcc2ddcd9b28a27b1e54b358b45874f88d1ca6888c"
dependencies = [ dependencies = [
"bstr", "bitflags",
"csv-core", "crossterm_winapi",
"itoa", "lazy_static",
"ryu", "libc",
"serde", "mio",
"parking_lot",
"signal-hook",
"winapi 0.3.9",
] ]
[[package]] [[package]]
name = "csv-core" name = "crossterm_winapi"
version = "0.1.10" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" checksum = "0da8964ace4d3e4a044fd027919b2237000b24315a37c916f61809f1ff2140b9"
dependencies = [ dependencies = [
"memchr 2.4.0", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -794,6 +738,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec" checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec"
[[package]]
name = "instant"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
"cfg-if 1.0.0",
]
[[package]] [[package]]
name = "ioctl-sys" name = "ioctl-sys"
version = "0.5.2" version = "0.5.2"
@ -809,15 +762,6 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.0" version = "0.10.0"
@ -827,21 +771,6 @@ dependencies = [
"either", "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]] [[package]]
name = "kernel32-sys" name = "kernel32-sys"
version = "0.2.2" version = "0.2.2"
@ -873,6 +802,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "lock_api"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
dependencies = [
"scopeguard",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.14" version = "0.4.14"
@ -926,13 +864,35 @@ checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.6.3" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d" checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "mio"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7"
dependencies = [
"libc",
"log",
"miow",
"ntapi",
"winapi 0.3.9",
]
[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.13.1" version = "0.13.1"
@ -964,6 +924,26 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "ntapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [
"winapi 0.3.9",
]
[[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]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"
@ -1033,12 +1013,6 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]] [[package]]
name = "ouroboros" name = "ouroboros"
version = "0.9.3" version = "0.9.3"
@ -1071,6 +1045,31 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "parking_lot"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
dependencies = [
"cfg-if 1.0.0",
"instant",
"libc",
"redox_syscall 0.2.8",
"smallvec 1.6.1",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "0.1.18" version = "0.1.18"
@ -1090,15 +1089,6 @@ dependencies = [
"proc-macro-hack", "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]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.19" version = "0.3.19"
@ -1115,34 +1105,6 @@ dependencies = [
"winapi 0.3.9", "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]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.10" version = "0.2.10"
@ -1454,21 +1416,6 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" 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]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.6" version = "1.0.6"
@ -1490,16 +1437,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [ dependencies = [
"semver-parser 0.7.0", "semver-parser",
]
[[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",
] ]
[[package]] [[package]]
@ -1508,53 +1446,6 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 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]] [[package]]
name = "sha1" name = "sha1"
version = "0.6.0" version = "0.6.0"
@ -1586,6 +1477,26 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "signal-hook"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
dependencies = [
"libc",
"mio",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "0.6.14" version = "0.6.14"
@ -1595,6 +1506,12 @@ dependencies = [
"maybe-uninit", "maybe-uninit",
] ]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.3.19" version = "0.3.19"
@ -1717,18 +1634,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.24" version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.24" version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.9", "quote 1.0.9",
@ -1745,28 +1662,12 @@ dependencies = [
"winapi 0.3.9", "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]] [[package]]
name = "typenum" name = "typenum"
version = "1.13.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.7.1" version = "1.7.1"
@ -2053,6 +1954,8 @@ name = "uu_expr"
version = "0.0.6" version = "0.0.6"
dependencies = [ dependencies = [
"libc", "libc",
"num-bigint",
"num-traits",
"onig", "onig",
"uucore", "uucore",
"uucore_procs", "uucore_procs",
@ -2068,22 +1971,11 @@ dependencies = [
"paste", "paste",
"quickcheck", "quickcheck",
"rand 0.7.3", "rand 0.7.3",
"smallvec", "smallvec 0.6.14",
"uucore", "uucore",
"uucore_procs", "uucore_procs",
] ]
[[package]]
name = "uu_factor_benches"
version = "0.0.0"
dependencies = [
"array-init",
"criterion",
"rand 0.7.3",
"rand_chacha 0.2.2",
"uu_factor",
]
[[package]] [[package]]
name = "uu_false" name = "uu_false"
version = "0.0.6" version = "0.0.6"
@ -2306,7 +2198,9 @@ dependencies = [
name = "uu_more" name = "uu_more"
version = "0.0.6" version = "0.0.6"
dependencies = [ dependencies = [
"atty",
"clap", "clap",
"crossterm",
"nix 0.13.1", "nix 0.13.1",
"redox_syscall 0.1.57", "redox_syscall 0.1.57",
"redox_termios", "redox_termios",
@ -2576,7 +2470,7 @@ dependencies = [
"ouroboros", "ouroboros",
"rand 0.7.3", "rand 0.7.3",
"rayon", "rayon",
"semver 0.9.0", "semver",
"tempfile", "tempfile",
"unicode-width", "unicode-width",
"uucore", "uucore",
@ -2924,70 +2818,6 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.74"
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",
]
[[package]] [[package]]
name = "wild" name = "wild"
version = "2.0.4" version = "2.0.4"

View file

@ -327,7 +327,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" } 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" } 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 # * pinned transitive dependencies
@ -350,6 +351,7 @@ time = "0.1"
unindent = "0.1" unindent = "0.1"
uucore = { version=">=0.0.8", package="uucore", path="src/uucore", features=["entries"] } uucore = { version=">=0.0.8", package="uucore", path="src/uucore", features=["entries"] }
walkdir = "2.2" walkdir = "2.2"
atty = "0.2.14"
[target.'cfg(unix)'.dev-dependencies] [target.'cfg(unix)'.dev-dependencies]
rust-users = { version="0.10", package="users" } rust-users = { version="0.10", package="users" }

View file

@ -21,7 +21,7 @@ if changes are not reflected in the report then run `cargo clean` and run the a
### Using Stable Rust ### Using Stable Rust
If you are using stable version of Rust that doesn't enable code coverage instrumentation by default If you are using stable version of Rust that doesn't enable code coverage instrumentation by default
then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above. then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above.
@ -36,3 +36,7 @@ To use the provided hook:
2. Run `pre-commit install` while in the repository directory 2. Run `pre-commit install` while in the repository directory
Your git commits will then automatically be checked. If a check fails, an error message will explain why, and your commit will be canceled. You can then make the suggested changes, and run `git commit ...` again. Your git commits will then automatically be checked. If a check fails, an error message will explain why, and your commit will be canceled. You can then make the suggested changes, and run `git commit ...` again.
### Using Clippy
The `msrv` key in the clippy configuration file `clippy.toml` is used to disable lints pertaining to newer features by specifying the minimum supported Rust version (MSRV). However, this key is only supported on `nightly`. To invoke clippy without errors, use `cargo +nightly clippy`. In order to also check tests and non-default crate features, use `cargo +nightly clippy --all-targets --all-features`.

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 { fn strip_suffix(name: &str, suffix: &str) -> String {
if name == suffix { if name == suffix {
return name.to_owned(); return name.to_owned();

View file

@ -669,8 +669,8 @@ impl Options {
} }
}, },
backup: backup_mode, backup: backup_mode,
backup_suffix: backup_suffix, backup_suffix,
overwrite: overwrite, overwrite,
no_target_dir, no_target_dir,
preserve_attributes, preserve_attributes,
recursive, recursive,
@ -1089,7 +1089,7 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu
} }
#[cfg(not(windows))] #[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<()> { fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
match std::os::unix::fs::symlink(source, dest).context(context) { match std::os::unix::fs::symlink(source, dest).context(context) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
@ -1108,7 +1108,7 @@ fn context_for(src: &Path, dest: &Path) -> String {
/// Implements a simple backup copy for the destination file. /// Implements a simple backup copy for the destination file.
/// TODO: for the backup, should this function be replaced by `copy_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)?; fs::copy(dest, &backup_path)?;
Ok(backup_path.into()) Ok(backup_path.into())
} }

View file

@ -483,10 +483,11 @@ where
/// Shrink the buffer so that its length is equal to the set size, returning an iterator for /// Shrink the buffer so that its length is equal to the set size, returning an iterator for
/// the elements that were too much. /// the elements that were too much.
fn shrink_buffer_to_size(&mut self) -> impl Iterator<Item = String> + '_ { fn shrink_buffer_to_size(&mut self) -> impl Iterator<Item = String> + '_ {
let mut shrink_offset = 0; let shrink_offset = if self.buffer.len() > self.size {
if self.buffer.len() > self.size { self.buffer.len() - self.size
shrink_offset = self.buffer.len() - self.size; } else {
} 0
};
self.buffer self.buffer
.drain(..shrink_offset) .drain(..shrink_offset)
.map(|(_, line)| line.unwrap()) .map(|(_, line)| line.unwrap())

View file

@ -16,6 +16,8 @@ path = "src/expr.rs"
[dependencies] [dependencies]
libc = "0.2.42" libc = "0.2.42"
num-bigint = "0.4.0"
num-traits = "0.2.14"
onig = "~4.3.2" onig = "~4.3.2"
uucore = { version=">=0.0.8", package="uucore", path="../../uucore" } uucore = { version=">=0.0.8", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } 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 // spell-checker:ignore (ToDO) binop binops ints paren prec
use num_bigint::BigInt;
use num_traits::{One, Zero};
use onig::{Regex, RegexOptions, Syntax}; use onig::{Regex, RegexOptions, Syntax};
use crate::tokens::Token; use crate::tokens::Token;
@ -39,20 +41,17 @@ impl AstNode {
for _ in 0..depth { for _ in 0..depth {
print!("\t",); print!("\t",);
} }
match *self { match self {
AstNode::Leaf { AstNode::Leaf { token_idx, value } => println!(
ref token_idx,
ref value,
} => println!(
"Leaf( {} ) at #{} ( evaluate -> {:?} )", "Leaf( {} ) at #{} ( evaluate -> {:?} )",
value, value,
token_idx, token_idx,
self.evaluate() self.evaluate()
), ),
AstNode::Node { AstNode::Node {
ref token_idx, token_idx,
ref op_type, op_type,
ref operands, operands,
} => { } => {
println!( println!(
"Node( {} ) at #{} (evaluate -> {:?})", "Node( {} ) at #{} (evaluate -> {:?})",
@ -81,36 +80,33 @@ impl AstNode {
}) })
} }
pub fn evaluate(&self) -> Result<String, String> { pub fn evaluate(&self) -> Result<String, String> {
match *self { match self {
AstNode::Leaf { ref value, .. } => Ok(value.clone()), AstNode::Leaf { value, .. } => Ok(value.clone()),
AstNode::Node { ref op_type, .. } => match self.operand_values() { AstNode::Node { op_type, .. } => match self.operand_values() {
Err(reason) => Err(reason), Err(reason) => Err(reason),
Ok(operand_values) => match op_type.as_ref() { Ok(operand_values) => match op_type.as_ref() {
"+" => infix_operator_two_ints( "+" => {
|a: i64, b: i64| checked_binop(|| a.checked_add(b), "+"), infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a + b), &operand_values)
&operand_values, }
), "-" => {
"-" => infix_operator_two_ints( infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a - b), &operand_values)
|a: i64, b: i64| checked_binop(|| a.checked_sub(b), "-"), }
&operand_values, "*" => {
), infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a * b), &operand_values)
"*" => infix_operator_two_ints( }
|a: i64, b: i64| checked_binop(|| a.checked_mul(b), "*"),
&operand_values,
),
"/" => infix_operator_two_ints( "/" => infix_operator_two_ints(
|a: i64, b: i64| { |a: BigInt, b: BigInt| {
if b == 0 { if b.is_zero() {
Err("division by zero".to_owned()) Err("division by zero".to_owned())
} else { } else {
checked_binop(|| a.checked_div(b), "/") Ok(a / b)
} }
}, },
&operand_values, &operand_values,
), ),
"%" => infix_operator_two_ints( "%" => infix_operator_two_ints(
|a: i64, b: i64| { |a: BigInt, b: BigInt| {
if b == 0 { if b.is_zero() {
Err("division by zero".to_owned()) Err("division by zero".to_owned())
} else { } else {
Ok(a % b) Ok(a % b)
@ -119,32 +115,32 @@ impl AstNode {
&operand_values, &operand_values,
), ),
"=" => infix_operator_two_ints_or_two_strings( "=" => 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)), |a: &String, b: &String| Ok(bool_as_string(a == b)),
&operand_values, &operand_values,
), ),
"!=" => infix_operator_two_ints_or_two_strings( "!=" => 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)), |a: &String, b: &String| Ok(bool_as_string(a != b)),
&operand_values, &operand_values,
), ),
"<" => infix_operator_two_ints_or_two_strings( "<" => 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)), |a: &String, b: &String| Ok(bool_as_string(a < b)),
&operand_values, &operand_values,
), ),
">" => infix_operator_two_ints_or_two_strings( ">" => 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)), |a: &String, b: &String| Ok(bool_as_string(a > b)),
&operand_values, &operand_values,
), ),
"<=" => infix_operator_two_ints_or_two_strings( "<=" => 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)), |a: &String, b: &String| Ok(bool_as_string(a <= b)),
&operand_values, &operand_values,
), ),
">=" => infix_operator_two_ints_or_two_strings( ">=" => 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)), |a: &String, b: &String| Ok(bool_as_string(a >= b)),
&operand_values, &operand_values,
), ),
@ -161,7 +157,7 @@ impl AstNode {
} }
} }
pub fn operand_values(&self) -> Result<Vec<String>, String> { 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()); let mut out = Vec::with_capacity(operands.len());
for operand in operands { for operand in operands {
match operand.evaluate() { 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 let Ok(debug_var) = env::var("EXPR_DEBUG_AST") {
if debug_var == "1" { if debug_var == "1" {
println!("EXPR_DEBUG_AST"); println!("EXPR_DEBUG_AST");
match *result { match result {
Ok(ref ast) => ast.debug_dump(), Ok(ast) => ast.debug_dump(),
Err(ref reason) => println!("\terr: {:?}", reason), Err(reason) => println!("\terr: {:?}", reason),
} }
} }
} }
@ -304,7 +300,7 @@ fn push_token_to_either_stack(
out_stack: &mut TokenStack, out_stack: &mut TokenStack,
op_stack: &mut TokenStack, op_stack: &mut TokenStack,
) -> Result<(), String> { ) -> Result<(), String> {
let result = match *token { let result = match token {
Token::Value { .. } => { Token::Value { .. } => {
out_stack.push((token_idx, token.clone())); out_stack.push((token_idx, token.clone()));
Ok(()) 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> fn infix_operator_two_ints<F>(f: F, values: &[String]) -> Result<String, String>
where where
F: Fn(i64, i64) -> Result<i64, String>, F: Fn(BigInt, BigInt) -> Result<BigInt, String>,
{ {
assert!(values.len() == 2); assert!(values.len() == 2);
if let Ok(left) = values[0].parse::<i64>() { if let Ok(left) = values[0].parse::<BigInt>() {
if let Ok(right) = values[1].parse::<i64>() { if let Ok(right) = values[1].parse::<BigInt>() {
return match f(left, right) { return f(left, right).map(|big_int| big_int.to_string());
Ok(result) => Ok(result.to_string()),
Err(reason) => Err(reason),
};
} }
} }
Err("Expected an integer operand".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], values: &[String],
) -> Result<String, String> ) -> Result<String, String>
where where
FI: Fn(i64, i64) -> Result<i64, String>, FI: Fn(BigInt, BigInt) -> Result<u8, String>,
FS: Fn(&String, &String) -> Result<String, String>, FS: Fn(&String, &String) -> Result<String, String>,
{ {
assert!(values.len() == 2); assert!(values.len() == 2);
if let (Some(a_int), Some(b_int)) = if let (Some(a_int), Some(b_int)) = (
(values[0].parse::<i64>().ok(), values[1].parse::<i64>().ok()) values[0].parse::<BigInt>().ok(),
{ values[1].parse::<BigInt>().ok(),
) {
match fi(a_int, b_int) { match fi(a_int, b_int) {
Ok(result) => Ok(result.to_string()), Ok(result) => Ok(result.to_string()),
Err(reason) => Err(reason), Err(reason) => Err(reason),
@ -541,7 +528,7 @@ fn prefix_operator_substr(values: &[String]) -> String {
subj.chars().skip(idx).take(len).collect() subj.chars().skip(idx).take(len).collect()
} }
fn bool_as_int(b: bool) -> i64 { fn bool_as_int(b: bool) -> u8 {
if b { if b {
1 1
} else { } else {
@ -559,8 +546,8 @@ fn value_as_bool(s: &str) -> bool {
if s.is_empty() { if s.is_empty() {
return false; return false;
} }
match s.parse::<i64>() { match s.parse::<BigInt>() {
Ok(n) => n != 0, Ok(n) => n.is_one(),
Err(_) => true, Err(_) => true,
} }
} }

View file

@ -18,6 +18,8 @@
// spell-checker:ignore (ToDO) paren // spell-checker:ignore (ToDO) paren
use num_bigint::BigInt;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Token { pub enum Token {
Value { Value {
@ -51,14 +53,14 @@ impl Token {
} }
fn is_infix_plus(&self) -> bool { fn is_infix_plus(&self) -> bool {
match *self { match self {
Token::InfixOp { ref value, .. } => value == "+", Token::InfixOp { value, .. } => value == "+",
_ => false, _ => false,
} }
} }
fn is_a_number(&self) -> bool { fn is_a_number(&self) -> bool {
match *self { match self {
Token::Value { ref value, .. } => value.parse::<i64>().is_ok(), Token::Value { value, .. } => value.parse::<BigInt>().is_ok(),
_ => false, _ => false,
} }
} }
@ -142,7 +144,7 @@ fn push_token_if_not_escaped(acc: &mut Vec<(usize, Token)>, tok_idx: usize, toke
// Smells heuristics... :( // Smells heuristics... :(
let prev_is_plus = match acc.last() { let prev_is_plus = match acc.last() {
None => false, 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 should_use_as_escaped = if prev_is_plus && acc.len() >= 2 {
let pre_prev = &acc[acc.len() - 2]; let pre_prev = &acc[acc.len() - 2];

View file

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

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 num_end = 0usize;
let mut has_num = false; let mut has_num = false;
let mut last_char = 0 as char; let mut last_char = 0 as char;
while let Some((n, c)) = chars.next() { for (n, c) in &mut chars {
if c.is_numeric() { if c.is_numeric() {
has_num = true; has_num = true;
num_end = n; num_end = n;
@ -109,7 +109,7 @@ pub fn parse_num(src: &str) -> Result<(usize, bool), ParseError> {
let mut num_end = 0usize; let mut num_end = 0usize;
let mut last_char = 0 as char; let mut last_char = 0 as char;
let mut num_count = 0usize; let mut num_count = 0usize;
while let Some((n, c)) = chars.next() { for (n, c) in &mut chars {
if c.is_numeric() { if c.is_numeric() {
num_end = n; num_end = n;
num_count += 1; 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. /// 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<(), ()> { fn copy(from: &Path, to: &Path, b: &Behavior) -> Result<(), ()> {
if b.compare && !need_copy(from, to, b) { if b.compare && !need_copy(from, to, b) {
return Ok(()); return Ok(());

View file

@ -218,6 +218,7 @@ struct LongFormat {
} }
impl Config { impl Config {
#[allow(clippy::cognitive_complexity)]
fn from(options: clap::ArgMatches) -> Config { fn from(options: clap::ArgMatches) -> Config {
let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) { let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) {
( (
@ -1222,7 +1223,7 @@ fn list(locs: Vec<String>, config: Config) -> i32 {
sort_entries(&mut dirs, &config); sort_entries(&mut dirs, &config);
for dir in dirs { for dir in dirs {
if locs.len() > 1 { if locs.len() > 1 || config.recursive {
let _ = writeln!(out, "\n{}:", dir.p_buf.display()); let _ = writeln!(out, "\n{}:", dir.p_buf.display());
} }
enter_directory(&dir, &config, &mut out); enter_directory(&dir, &config, &mut out);
@ -1614,7 +1615,7 @@ fn display_date(metadata: &Metadata, config: &Config) -> String {
Some(time) => { Some(time) => {
//Date is recent if from past 6 months //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. //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 { match config.time_style {
TimeStyle::FullIso => time.format("%Y-%m-%d %H:%M:%S.%f %z"), 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 md.mode() & ((S_IXUSR | S_IXGRP | S_IXOTH) as u32) != 0
} }
#[allow(clippy::clippy::collapsible_else_if)]
fn classify_file(path: &PathData) -> Option<char> { fn classify_file(path: &PathData) -> Option<char> {
let file_type = path.file_type()?; let file_type = path.file_type()?;

View file

@ -18,6 +18,8 @@ path = "src/more.rs"
clap = "2.33" clap = "2.33"
uucore = { version = ">=0.0.7", package = "uucore", path = "../../uucore" } uucore = { version = ">=0.0.7", package = "uucore", path = "../../uucore" }
uucore_procs = { version = ">=0.0.5", package = "uucore_procs", path = "../../uucore_procs" } uucore_procs = { version = ">=0.0.5", package = "uucore_procs", path = "../../uucore_procs" }
crossterm = ">=0.19"
atty = "0.2.14"
[target.'cfg(target_os = "redox")'.dependencies] [target.'cfg(target_os = "redox")'.dependencies]
redox_termios = "0.1" redox_termios = "0.1"

View file

@ -10,150 +10,395 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use std::fs::File; use std::{
use std::io::{stdin, stdout, BufRead, BufReader, Read, Write}; convert::TryInto,
fs::File,
io::{stdin, stdout, BufReader, Read, Stdout, Write},
path::Path,
time::Duration,
};
#[cfg(all(unix, not(target_os = "fuchsia")))] #[cfg(all(unix, not(target_os = "fuchsia")))]
extern crate nix; extern crate nix;
#[cfg(all(unix, not(target_os = "fuchsia")))]
use nix::sys::termios::{self, LocalFlags, SetArg};
use uucore::InvalidEncodingHandling;
#[cfg(target_os = "redox")] use clap::{App, Arg};
extern crate redox_termios; use crossterm::{
#[cfg(target_os = "redox")] event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
extern crate syscall; execute, queue,
style::Attribute,
terminal,
};
use clap::{App, Arg, ArgMatches}; pub mod options {
pub const SILENT: &str = "silent";
static VERSION: &str = env!("CARGO_PKG_VERSION"); pub const LOGICAL: &str = "logical";
static ABOUT: &str = "A file perusal filter for CRT viewing."; pub const NO_PAUSE: &str = "no-pause";
pub const PRINT_OVER: &str = "print-over";
mod options { pub const CLEAN_PRINT: &str = "clean-print";
pub const FILE: &str = "file"; pub const SQUEEZE: &str = "squeeze";
pub const PLAIN: &str = "plain";
pub const LINES: &str = "lines";
pub const NUMBER: &str = "number";
pub const PATTERN: &str = "pattern";
pub const FROM_LINE: &str = "from-line";
pub const FILES: &str = "files";
} }
fn get_usage() -> String { const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";
format!("{} [options] <file>...", executable!())
}
pub fn uumain(args: impl uucore::Args) -> i32 { pub fn uumain(args: impl uucore::Args) -> i32 {
let usage = get_usage();
let args = args
.collect_str(InvalidEncodingHandling::ConvertLossy)
.accept_any();
let matches = App::new(executable!()) let matches = App::new(executable!())
.version(VERSION) .about("A file perusal filter for CRT viewing.")
.usage(usage.as_str()) .version(env!("CARGO_PKG_VERSION"))
.about(ABOUT) // The commented arguments below are unimplemented:
/*
.arg( .arg(
Arg::with_name(options::FILE) Arg::with_name(options::SILENT)
.number_of_values(1) .short("d")
.multiple(true), .long(options::SILENT)
.help("Display help instead of ringing bell"),
)
.arg(
Arg::with_name(options::LOGICAL)
.short("f")
.long(options::LOGICAL)
.help("Count logical rather than screen lines"),
)
.arg(
Arg::with_name(options::NO_PAUSE)
.short("l")
.long(options::NO_PAUSE)
.help("Suppress pause after form feed"),
)
.arg(
Arg::with_name(options::PRINT_OVER)
.short("c")
.long(options::PRINT_OVER)
.help("Do not scroll, display text and clean line ends"),
)
.arg(
Arg::with_name(options::CLEAN_PRINT)
.short("p")
.long(options::CLEAN_PRINT)
.help("Do not scroll, clean screen and display text"),
)
.arg(
Arg::with_name(options::SQUEEZE)
.short("s")
.long(options::SQUEEZE)
.help("Squeeze multiple blank lines into one"),
)
.arg(
Arg::with_name(options::PLAIN)
.short("u")
.long(options::PLAIN)
.help("Suppress underlining and bold"),
)
.arg(
Arg::with_name(options::LINES)
.short("n")
.long(options::LINES)
.value_name("number")
.takes_value(true)
.help("The number of lines per screenful"),
)
.arg(
Arg::with_name(options::NUMBER)
.allow_hyphen_values(true)
.long(options::NUMBER)
.required(false)
.takes_value(true)
.help("Same as --lines"),
)
.arg(
Arg::with_name(options::FROM_LINE)
.short("F")
.allow_hyphen_values(true)
.required(false)
.takes_value(true)
.value_name("number")
.help("Display file beginning from line number"),
)
.arg(
Arg::with_name(options::PATTERN)
.short("P")
.allow_hyphen_values(true)
.required(false)
.takes_value(true)
.help("Display file beginning from pattern match"),
)
*/
.arg(
Arg::with_name(options::FILES)
.required(false)
.multiple(true)
.help("Path to the files to be read"),
) )
.get_matches_from(args); .get_matches_from(args);
// FixME: fail without panic for now; but `more` should work with no arguments (ie, for piped input) let mut buff = String::new();
if let None | Some("-") = matches.value_of(options::FILE) { if let Some(filenames) = matches.values_of(options::FILES) {
show_usage_error!("Reading from stdin isn't supported yet."); let mut stdout = setup_term();
return 1; let length = filenames.len();
} for (idx, fname) in filenames.enumerate() {
let fname = Path::new(fname);
if let Some(x) = matches.value_of(options::FILE) { if fname.is_dir() {
let path = std::path::Path::new(x); terminal::disable_raw_mode().unwrap();
if path.is_dir() { show_usage_error!("'{}' is a directory.", fname.display());
show_usage_error!("'{}' is a directory.", x); return 1;
return 1; }
if !fname.exists() {
terminal::disable_raw_mode().unwrap();
show_error!(
"cannot open {}: No such file or directory",
fname.display()
);
return 1;
}
if length > 1 {
buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", fname.to_str().unwrap()));
}
let mut reader = BufReader::new(File::open(fname).unwrap());
reader.read_to_string(&mut buff).unwrap();
let is_last = idx + 1 == length;
more(&buff, &mut stdout, is_last);
buff.clear();
} }
reset_term(&mut stdout);
} else if atty::isnt(atty::Stream::Stdin) {
stdin().read_to_string(&mut buff).unwrap();
let mut stdout = setup_term();
more(&buff, &mut stdout, true);
reset_term(&mut stdout);
} else {
show_usage_error!("bad usage");
} }
more(matches);
0 0
} }
#[cfg(all(unix, not(target_os = "fuchsia")))] #[cfg(not(target_os = "fuchsia"))]
fn setup_term() -> termios::Termios { fn setup_term() -> std::io::Stdout {
let mut term = termios::tcgetattr(0).unwrap(); let stdout = stdout();
// Unset canonical mode, so we get characters immediately terminal::enable_raw_mode().unwrap();
term.local_flags.remove(LocalFlags::ICANON); stdout
// Disable local echo
term.local_flags.remove(LocalFlags::ECHO);
termios::tcsetattr(0, SetArg::TCSADRAIN, &term).unwrap();
term
} }
#[cfg(any(windows, target_os = "fuchsia"))] #[cfg(target_os = "fuchsia")]
#[inline(always)] #[inline(always)]
fn setup_term() -> usize { fn setup_term() -> usize {
0 0
} }
#[cfg(target_os = "redox")] #[cfg(not(target_os = "fuchsia"))]
fn setup_term() -> redox_termios::Termios { fn reset_term(stdout: &mut std::io::Stdout) {
let mut term = redox_termios::Termios::default(); terminal::disable_raw_mode().unwrap();
let fd = syscall::dup(0, b"termios").unwrap(); // Clear the prompt
syscall::read(fd, &mut term).unwrap(); queue!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
term.local_flags &= !redox_termios::ICANON; // Move cursor to the beginning without printing new line
term.local_flags &= !redox_termios::ECHO; print!("\r");
syscall::write(fd, &term).unwrap(); stdout.flush().unwrap();
let _ = syscall::close(fd);
term
} }
#[cfg(all(unix, not(target_os = "fuchsia")))] #[cfg(target_os = "fuchsia")]
fn reset_term(term: &mut termios::Termios) {
term.local_flags.insert(LocalFlags::ICANON);
term.local_flags.insert(LocalFlags::ECHO);
termios::tcsetattr(0, SetArg::TCSADRAIN, &term).unwrap();
}
#[cfg(any(windows, target_os = "fuchsia"))]
#[inline(always)] #[inline(always)]
fn reset_term(_: &mut usize) {} fn reset_term(_: &mut usize) {}
#[cfg(any(target_os = "redox"))] fn more(buff: &str, mut stdout: &mut Stdout, is_last: bool) {
fn reset_term(term: &mut redox_termios::Termios) { let (cols, rows) = terminal::size().unwrap();
let fd = syscall::dup(0, b"termios").unwrap(); let lines = break_buff(buff, usize::from(cols));
syscall::read(fd, term).unwrap(); let line_count: u16 = lines.len().try_into().unwrap();
term.local_flags |= redox_termios::ICANON;
term.local_flags |= redox_termios::ECHO;
syscall::write(fd, &term).unwrap();
let _ = syscall::close(fd);
}
fn more(matches: ArgMatches) { let mut upper_mark = 0;
let mut f: Box<dyn BufRead> = match matches.value_of(options::FILE) { let mut lines_left = line_count.saturating_sub(upper_mark + rows);
None | Some("-") => Box::new(BufReader::new(stdin())),
Some(filename) => Box::new(BufReader::new(File::open(filename).unwrap())),
};
let mut buffer = [0; 1024];
let mut term = setup_term(); draw(
&mut upper_mark,
rows,
&mut stdout,
lines.clone(),
line_count,
);
let mut end = false; // Specifies whether we have reached the end of the file and should
while let Ok(sz) = f.read(&mut buffer) { // return on the next keypress. However, we immediately return when
if sz == 0 { // this is the last file.
break; let mut to_be_done = false;
} if lines_left == 0 && is_last {
stdout().write_all(&buffer[0..sz]).unwrap(); if is_last {
for byte in std::io::stdin().bytes() { return;
match byte.unwrap() { } else {
b' ' => break, to_be_done = true;
b'q' | 27 => {
end = true;
break;
}
_ => (),
}
}
if end {
break;
} }
} }
loop {
if event::poll(Duration::from_millis(10)).unwrap() {
match event::read().unwrap() {
Event::Key(KeyEvent {
code: KeyCode::Char('q'),
modifiers: KeyModifiers::NONE,
})
| Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
}) => {
reset_term(&mut stdout);
std::process::exit(0);
}
Event::Key(KeyEvent {
code: KeyCode::Down,
modifiers: KeyModifiers::NONE,
})
| Event::Key(KeyEvent {
code: KeyCode::Char(' '),
modifiers: KeyModifiers::NONE,
}) => {
upper_mark = upper_mark.saturating_add(rows.saturating_sub(1));
}
Event::Key(KeyEvent {
code: KeyCode::Up,
modifiers: KeyModifiers::NONE,
}) => {
upper_mark = upper_mark.saturating_sub(rows.saturating_sub(1));
}
_ => continue,
}
lines_left = line_count.saturating_sub(upper_mark + rows);
draw(
&mut upper_mark,
rows,
&mut stdout,
lines.clone(),
line_count,
);
reset_term(&mut term); if lines_left == 0 {
println!(); if to_be_done || is_last {
return
}
to_be_done = true;
}
}
}
}
fn draw(
upper_mark: &mut u16,
rows: u16,
mut stdout: &mut std::io::Stdout,
lines: Vec<String>,
lc: u16,
) {
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
let (up_mark, lower_mark) = calc_range(*upper_mark, rows, lc);
// Reduce the row by 1 for the prompt
let displayed_lines = lines
.iter()
.skip(up_mark.into())
.take(usize::from(rows.saturating_sub(1)));
for line in displayed_lines {
stdout
.write_all(format!("\r{}\n", line).as_bytes())
.unwrap();
}
make_prompt_and_flush(&mut stdout, lower_mark, lc);
*upper_mark = up_mark;
}
// Break the lines on the cols of the terminal
fn break_buff(buff: &str, cols: usize) -> Vec<String> {
let mut lines = Vec::new();
for l in buff.lines() {
lines.append(&mut break_line(l, cols));
}
lines
}
fn break_line(mut line: &str, cols: usize) -> Vec<String> {
let breaks = (line.len() / cols).saturating_add(1);
let mut lines = Vec::with_capacity(breaks);
// TODO: Use unicode width instead of the length in bytes.
if line.len() < cols {
lines.push(line.to_string());
return lines;
}
for _ in 1..=breaks {
let (line1, line2) = line.split_at(cols);
lines.push(line1.to_string());
if line2.len() < cols {
lines.push(line2.to_string());
break;
}
line = line2;
}
lines
}
// Calculate upper_mark based on certain parameters
fn calc_range(mut upper_mark: u16, rows: u16, line_count: u16) -> (u16, u16) {
let mut lower_mark = upper_mark.saturating_add(rows);
if lower_mark >= line_count {
upper_mark = line_count.saturating_sub(rows);
lower_mark = line_count;
} else {
lower_mark = lower_mark.saturating_sub(1)
}
(upper_mark, lower_mark)
}
// Make a prompt similar to original more
fn make_prompt_and_flush(stdout: &mut Stdout, lower_mark: u16, lc: u16) {
write!(
stdout,
"\r{}--More--({}%){}",
Attribute::Reverse,
((lower_mark as f64 / lc as f64) * 100.0).round() as u16,
Attribute::Reset
)
.unwrap();
stdout.flush().unwrap();
}
#[cfg(test)]
mod tests {
use super::{break_line, calc_range};
// It is good to test the above functions
#[test]
fn test_calc_range() {
assert_eq!((0, 24), calc_range(0, 25, 100));
assert_eq!((50, 74), calc_range(50, 25, 100));
assert_eq!((75, 100), calc_range(85, 25, 100));
}
#[test]
fn test_break_lines_long() {
let mut test_string = String::with_capacity(100);
for _ in 0..200 {
test_string.push('#');
}
let lines = break_line(&test_string, 80);
assert_eq!(
(80, 80, 40),
(lines[0].len(), lines[1].len(), lines[2].len())
);
}
#[test]
fn test_break_lines_short() {
let mut test_string = String::with_capacity(100);
for _ in 0..20 {
test_string.push('#');
}
let lines = break_line(&test_string, 80);
assert_eq!(20, lines[0].len());
}
} }

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@
Most of the time when sorting is spent comparing lines. The comparison functions however differ based 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. 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 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. list that we should improve / make sure not to regress.

View file

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

View file

@ -108,7 +108,7 @@ const POSITIVE: char = '+';
// available memory into consideration, instead of relying on this constant only. // available memory into consideration, instead of relying on this constant only.
static DEFAULT_BUF_SIZE: usize = 1_000_000_000; // 1 GB 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 { enum SortMode {
Numeric, Numeric,
HumanNumeric, HumanNumeric,
@ -118,6 +118,21 @@ enum SortMode {
Random, Random,
Default, 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)] #[derive(Clone)]
pub struct GlobalSettings { pub struct GlobalSettings {
mode: SortMode, mode: SortMode,
@ -211,7 +226,7 @@ impl Default for GlobalSettings {
} }
} }
} }
#[derive(Clone)] #[derive(Clone, PartialEq, Debug)]
struct KeySettings { struct KeySettings {
mode: SortMode, mode: SortMode,
ignore_blanks: bool, ignore_blanks: bool,
@ -221,6 +236,60 @@ struct KeySettings {
reverse: bool, 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 { impl From<&GlobalSettings> for KeySettings {
fn from(settings: &GlobalSettings) -> Self { fn from(settings: &GlobalSettings) -> Self {
Self { Self {
@ -234,6 +303,12 @@ impl From<&GlobalSettings> for KeySettings {
} }
} }
impl Default for KeySettings {
fn default() -> Self {
Self::from(&GlobalSettings::default())
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum NumCache { enum NumCache {
AsF64(GeneralF64ParseResult), AsF64(GeneralF64ParseResult),
@ -296,10 +371,10 @@ impl<'a> Line<'a> {
fn print(&self, writer: &mut impl Write, settings: &GlobalSettings) { fn print(&self, writer: &mut impl Write, settings: &GlobalSettings) {
if settings.zero_terminated && !settings.debug { if settings.zero_terminated && !settings.debug {
crash_if_err!(1, writer.write_all(self.line.as_bytes())); 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 { } else if !settings.debug {
crash_if_err!(1, writer.write_all(self.line.as_bytes())); 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 { } else {
crash_if_err!(1, self.print_debug(settings, writer)); crash_if_err!(1, self.print_debug(settings, writer));
} }
@ -412,14 +487,18 @@ impl<'a> Line<'a> {
} }
} }
} }
if !(settings.mode == SortMode::Random if settings.mode != SortMode::Random
|| settings.stable && !settings.stable
|| settings.unique && !settings.unique
|| !(settings.dictionary_order && (settings.dictionary_order
|| settings.ignore_blanks || settings.ignore_blanks
|| settings.ignore_case || settings.ignore_case
|| settings.ignore_non_printing || 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. // A last resort comparator is in use, underline the whole line.
if self.line.is_empty() { if self.line.is_empty() {
@ -483,7 +562,7 @@ fn tokenize_with_separator(line: &str, separator: char) -> Vec<Field> {
tokens tokens
} }
#[derive(Clone)] #[derive(Clone, PartialEq, Debug)]
struct KeyPosition { struct KeyPosition {
/// 1-indexed, 0 is invalid. /// 1-indexed, 0 is invalid.
field: usize, field: usize,
@ -493,87 +572,45 @@ struct KeyPosition {
} }
impl 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_and_char = key.split('.');
let mut field = field_and_char
let field = field_and_char
.next() .next()
.unwrap_or_else(|| crash!(1, "invalid key `{}`", key)); .ok_or_else(|| format!("invalid key `{}`", key))?;
let mut char = field_and_char.next(); let 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];
}
let field = field let field = field
.parse() .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 { 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| { let char = char.map_or(Ok(default_char_index), |char| {
crash!( char.parse()
1, .map_err(|e| format!("failed to parse character index `{}`: {}", char, e))
"failed to parse character index for key `{}`: {}", })?;
key,
e Ok(Self {
)
})
});
Self {
field, field,
char, char,
ignore_blanks, 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 { struct FieldSelector {
from: KeyPosition, from: KeyPosition,
to: Option<KeyPosition>, to: Option<KeyPosition>,
@ -583,20 +620,120 @@ struct FieldSelector {
is_default_selection: bool, is_default_selection: bool,
} }
impl FieldSelector { impl Default for FieldSelector {
fn new(from: KeyPosition, to: Option<KeyPosition>, settings: KeySettings) -> Self { fn default() -> Self {
Self { Self {
is_default_selection: from.field == 1 from: Default::default(),
&& from.char == 1 to: None,
&& to.is_none() settings: Default::default(),
&& !matches!( needs_tokens: false,
settings.mode, is_default_selection: true,
SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric }
), }
needs_tokens: from.field != 1 || from.char == 0 || to.is_some(), }
from,
to, impl FieldSelector {
settings, /// 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()
&& !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,
})
} }
} }
@ -900,7 +1037,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.long(OPT_SEPARATOR) .long(OPT_SEPARATOR)
.help("custom separator for -k") .help("custom separator for -k")
.takes_value(true)) .takes_value(true))
.arg(Arg::with_name(OPT_ZERO_TERMINATED) .arg(
Arg::with_name(OPT_ZERO_TERMINATED)
.short("z") .short("z")
.long(OPT_ZERO_TERMINATED) .long(OPT_ZERO_TERMINATED)
.help("line delimiter is NUL, not newline"), .help("line delimiter is NUL, not newline"),
@ -1053,43 +1191,27 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if matches.is_present(OPT_KEY) { if matches.is_present(OPT_KEY) {
for key in &matches.args[OPT_KEY].vals { for key in &matches.args[OPT_KEY].vals {
let key = key.to_string_lossy(); settings
let mut from_to = key.split(','); .selectors
let mut key_settings = KeySettings::from(&settings); .push(FieldSelector::parse(&key.to_string_lossy(), &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);
} }
} }
if !settings.stable || !matches.is_present(OPT_KEY) { if !matches.is_present(OPT_KEY) {
// add a default selector matching the whole line // add a default selector matching the whole line
let key_settings = KeySettings::from(&settings); let key_settings = KeySettings::from(&settings);
settings.selectors.push(FieldSelector::new( settings.selectors.push(
KeyPosition { FieldSelector::new(
field: 1, KeyPosition {
char: 1, field: 1,
ignore_blanks: key_settings.ignore_blanks, char: 1,
}, ignore_blanks: key_settings.ignore_blanks,
None, },
key_settings, None,
)); key_settings,
)
.unwrap(),
);
} }
exec(&files, &settings) exec(&files, &settings)
@ -1437,7 +1559,7 @@ mod tests {
fn test_get_hash() { fn test_get_hash() {
let a = "Ted".to_string(); let a = "Ted".to_string();
assert_eq!(2646829031758483623, get_hash(&a)); assert_eq!(2_646_829_031_758_483_623, get_hash(&a));
} }
#[test] #[test]

View file

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

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) { if matches.is_present(options::FILE_SYSTEM) {
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
syncfs(files); syncfs(files);

View file

@ -265,11 +265,10 @@ impl Parser {
fn boolop(&mut self, op: Symbol) { fn boolop(&mut self, op: Symbol) {
if op == Symbol::BoolOp(OsString::from("-a")) { if op == Symbol::BoolOp(OsString::from("-a")) {
self.term(); self.term();
self.stack.push(op);
} else { } else {
self.expr(); self.expr();
self.stack.push(op);
} }
self.stack.push(op);
} }
/// Parse a (possible) unary argument test (string length or file /// 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) || matches.is_present(options::sources::CURRENT)
{ {
let timestamp = if matches.is_present(options::sources::DATE) { 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 { } else {
parse_timestamp( parse_timestamp(matches.value_of(options::sources::CURRENT).unwrap())
matches
.value_of(options::sources::CURRENT)
.unwrap()
.as_ref(),
)
}; };
(timestamp, timestamp) (timestamp, timestamp)
} else { } else {

View file

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

View file

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

View file

@ -179,7 +179,7 @@ impl MountInfo {
/* for Irix 6.5 */ /* for Irix 6.5 */
| "ignore" => self.dummy = true, | "ignore" => self.dummy = true,
_ => self.dummy = self.fs_type == "none" _ => 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 // set MountInfo::remote
#[cfg(windows)] #[cfg(windows)]

View file

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

View file

@ -146,15 +146,16 @@ pub trait Args: Iterator<Item = OsString> + Sized {
InvalidEncodingHandling::Ignore => s.is_ok(), InvalidEncodingHandling::Ignore => s.is_ok(),
_ => true, _ => true,
}) })
.map(|s| match s.is_ok() { .map(|s| match s {
true => s.unwrap(), Ok(v) => v,
false => s.unwrap_err(), Err(e) => e,
}) })
.collect(); .collect();
match full_conversion { if full_conversion {
true => ConversionResult::Complete(result_vector), ConversionResult::Complete(result_vector)
false => ConversionResult::Lossy(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 { if let Some(suffix) = supplied_suffix {
String::from(suffix) String::from(suffix)
} else { } else {
env::var("SIMPLE_BACKUP_SUFFIX").unwrap_or("~".to_owned()) env::var("SIMPLE_BACKUP_SUFFIX").unwrap_or_else(|_| "~".to_owned())
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -39,7 +39,7 @@ mod test_passgrp {
#[test] #[test]
fn test_usr2uid() { fn test_usr2uid() {
assert_eq!(0, usr2uid("root").unwrap()); assert_eq!(0, usr2uid("root").unwrap());
assert!(usr2uid("88888888").is_err()); assert!(usr2uid("88_888_888").is_err());
assert!(usr2uid("auserthatdoesntexist").is_err()); assert!(usr2uid("auserthatdoesntexist").is_err());
} }
@ -50,14 +50,14 @@ mod test_passgrp {
} else { } else {
assert_eq!(0, grp2gid("wheel").unwrap()); assert_eq!(0, grp2gid("wheel").unwrap());
} }
assert!(grp2gid("88888888").is_err()); assert!(grp2gid("88_888_888").is_err());
assert!(grp2gid("agroupthatdoesntexist").is_err()); assert!(grp2gid("agroupthatdoesntexist").is_err());
} }
#[test] #[test]
fn test_uid2usr() { fn test_uid2usr() {
assert_eq!("root", uid2usr(0).unwrap()); assert_eq!("root", uid2usr(0).unwrap());
assert!(uid2usr(88888888).is_err()); assert!(uid2usr(88_888_888).is_err());
} }
#[test] #[test]
@ -67,7 +67,7 @@ mod test_passgrp {
} else { } else {
assert_eq!("wheel", gid2grp(0).unwrap()); 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 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 cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: 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); 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 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 cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: 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); assert_eq!(bytes_cnt, 2058);
} }

View file

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

View file

@ -108,7 +108,7 @@ fn test_cp_multiple_files() {
#[test] #[test]
// FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590 // 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() { fn test_cp_recurse() {
let (at, mut ucmd) = at_and_ucmd!(); let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("-r") ucmd.arg("-r")
@ -132,7 +132,7 @@ fn test_cp_with_dirs_t() {
#[test] #[test]
// FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590 // 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() { fn test_cp_with_dirs() {
let scene = TestScenario::new(util_name!()); let scene = TestScenario::new(util_name!());
let at = &scene.fixtures; let at = &scene.fixtures;

View file

@ -1,13 +1,13 @@
use crate::common::util::*; use crate::common::util::*;
static INPUT: &'static str = "lists.txt"; static INPUT: &str = "lists.txt";
struct TestedSequence<'b> { struct TestedSequence<'b> {
name: &'b str, name: &'b str,
sequence: &'b str, sequence: &'b str,
} }
static EXAMPLE_SEQUENCES: &'static [TestedSequence<'static>] = &[ static EXAMPLE_SEQUENCES: &[TestedSequence] = &[
TestedSequence { TestedSequence {
name: "singular", name: "singular",
sequence: "2", 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: "", name: "",
sequence: "9-,6-7,-2,4", sequence: "9-,6-7,-2,4",
}; };
#[test] #[test]
fn test_byte_sequence() { fn test_byte_sequence() {
for param in vec!["-b", "--bytes"] { for &param in &["-b", "--bytes"] {
for example_seq in EXAMPLE_SEQUENCES { for example_seq in EXAMPLE_SEQUENCES {
new_ucmd!() new_ucmd!()
.args(&[param, example_seq.sequence, INPUT]) .args(&[param, example_seq.sequence, INPUT])
@ -53,7 +53,7 @@ fn test_byte_sequence() {
#[test] #[test]
fn test_char_sequence() { fn test_char_sequence() {
for param in vec!["-c", "--characters"] { for &param in &["-c", "--characters"] {
for example_seq in EXAMPLE_SEQUENCES { 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. //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!() new_ucmd!()
@ -66,7 +66,7 @@ fn test_char_sequence() {
#[test] #[test]
fn test_field_sequence() { fn test_field_sequence() {
for param in vec!["-f", "--fields"] { for &param in &["-f", "--fields"] {
for example_seq in EXAMPLE_SEQUENCES { for example_seq in EXAMPLE_SEQUENCES {
new_ucmd!() new_ucmd!()
.args(&[param, example_seq.sequence, INPUT]) .args(&[param, example_seq.sequence, INPUT])
@ -78,7 +78,7 @@ fn test_field_sequence() {
#[test] #[test]
fn test_specify_delimiter() { fn test_specify_delimiter() {
for param in vec!["-d", "--delimiter"] { for &param in &["-d", "--delimiter"] {
new_ucmd!() new_ucmd!()
.args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT]) .args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT])
.succeeds() .succeeds()
@ -122,7 +122,7 @@ fn test_zero_terminated() {
#[test] #[test]
fn test_only_delimited() { fn test_only_delimited() {
for param in vec!["-s", "--only-delimited"] { for param in &["-s", "--only-delimited"] {
new_ucmd!() new_ucmd!()
.args(&["-d_", param, "-f", "1"]) .args(&["-d_", param, "-f", "1"])
.pipe_in("91\n82\n7_3") .pipe_in("91\n82\n7_3")

View file

@ -187,7 +187,7 @@ fn test_du_d_flag() {
// TODO: gnu `du` doesn't use trailing "/" here // TODO: gnu `du` doesn't use trailing "/" here
// result.stdout_str(), result_reference.stdout_str() // result.stdout_str(), result_reference.stdout_str()
result.stdout_str().trim_end_matches("/\n"), result.stdout_str().trim_end_matches("/\n"),
result_reference.stdout_str().trim_end_matches("\n") result_reference.stdout_str().trim_end_matches('\n')
); );
return; return;
} }

View file

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

View file

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

View file

@ -1,6 +1,6 @@
use crate::common::util::*; use crate::common::util::*;
static INPUT: &'static str = "lorem_ipsum.txt"; static INPUT: &str = "lorem_ipsum.txt";
#[test] #[test]
fn test_stdin_default() { 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(ancestor2));
assert!(at.dir_exists(target_dir)); assert!(at.dir_exists(target_dir));
assert_ne!(0o40700 as u32, at.metadata(ancestor1).permissions().mode()); assert_ne!(0o40_700_u32, at.metadata(ancestor1).permissions().mode());
assert_ne!(0o40700 as u32, at.metadata(ancestor2).permissions().mode()); assert_ne!(0o40_700_u32, at.metadata(ancestor2).permissions().mode());
// Expected mode only on the target_dir. // 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] #[test]
@ -184,7 +184,7 @@ fn test_install_mode_numeric() {
assert!(at.file_exists(file)); assert!(at.file_exists(file));
assert!(at.file_exists(dest_file)); assert!(at.file_exists(dest_file));
let permissions = at.metadata(dest_file).permissions(); 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"; let mode_arg = "-m 0333";
at.mkdir(dir2); at.mkdir(dir2);
@ -195,7 +195,7 @@ fn test_install_mode_numeric() {
assert!(at.file_exists(file)); assert!(at.file_exists(file));
assert!(at.file_exists(dest_file)); assert!(at.file_exists(dest_file));
let permissions = at.metadata(dest_file).permissions(); let permissions = at.metadata(dest_file).permissions();
assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions)); assert_eq!(0o100_333_u32, PermissionsExt::mode(&permissions));
} }
#[test] #[test]
@ -213,7 +213,7 @@ fn test_install_mode_symbolic() {
assert!(at.file_exists(file)); assert!(at.file_exists(file));
assert!(at.file_exists(dest_file)); assert!(at.file_exists(dest_file));
let permissions = at.metadata(dest_file).permissions(); let permissions = at.metadata(dest_file).permissions();
assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions)); assert_eq!(0o100_003_u32, PermissionsExt::mode(&permissions));
} }
#[test] #[test]
@ -251,7 +251,7 @@ fn test_install_mode_directories() {
assert!(at.dir_exists(component)); assert!(at.dir_exists(component));
let permissions = at.metadata(component).permissions(); let permissions = at.metadata(component).permissions();
assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions)); assert_eq!(0o040_333_u32, PermissionsExt::mode(&permissions));
} }
#[test] #[test]

View file

@ -51,6 +51,7 @@ fn test_ls_a() {
.unwrap(), .unwrap(),
); );
#[allow(clippy::trivial_regex)]
let re_pwd = Regex::new(r"^\.\n").unwrap(); let re_pwd = Regex::new(r"^\.\n").unwrap();
// Using the present working directory // Using the present working directory
@ -124,7 +125,7 @@ fn test_ls_width() {
for option in &["-w 100", "-w=100", "--width=100", "--width 100"] { for option in &["-w 100", "-w=100", "--width=100", "--width 100"] {
scene scene
.ucmd() .ucmd()
.args(&option.split(" ").collect::<Vec<_>>()) .args(&option.split(' ').collect::<Vec<_>>())
.succeeds() .succeeds()
.stdout_only("test-width-1 test-width-2 test-width-3 test-width-4\n"); .stdout_only("test-width-1 test-width-2 test-width-3 test-width-4\n");
} }
@ -132,7 +133,7 @@ fn test_ls_width() {
for option in &["-w 50", "-w=50", "--width=50", "--width 50"] { for option in &["-w 50", "-w=50", "--width=50", "--width 50"] {
scene scene
.ucmd() .ucmd()
.args(&option.split(" ").collect::<Vec<_>>()) .args(&option.split(' ').collect::<Vec<_>>())
.succeeds() .succeeds()
.stdout_only("test-width-1 test-width-3\ntest-width-2 test-width-4\n"); .stdout_only("test-width-1 test-width-3\ntest-width-2 test-width-4\n");
} }
@ -149,7 +150,7 @@ fn test_ls_width() {
] { ] {
scene scene
.ucmd() .ucmd()
.args(&option.split(" ").collect::<Vec<_>>()) .args(&option.split(' ').collect::<Vec<_>>())
.succeeds() .succeeds()
.stdout_only("test-width-1\ntest-width-2\ntest-width-3\ntest-width-4\n"); .stdout_only("test-width-1\ntest-width-2\ntest-width-3\ntest-width-4\n");
} }
@ -163,7 +164,7 @@ fn test_ls_width() {
for option in &["-w 1a", "-w=1a", "--width=1a", "--width 1a"] { for option in &["-w 1a", "-w=1a", "--width=1a", "--width 1a"] {
scene scene
.ucmd() .ucmd()
.args(&option.split(" ").collect::<Vec<_>>()) .args(&option.split(' ').collect::<Vec<_>>())
.fails() .fails()
.stderr_only("ls: invalid line width: 1a"); .stderr_only("ls: invalid line width: 1a");
} }
@ -417,7 +418,7 @@ fn test_ls_long_formats() {
] { ] {
let result = scene let result = scene
.ucmd() .ucmd()
.args(&arg.split(" ").collect::<Vec<_>>()) .args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats") .arg("test-long-formats")
.succeeds(); .succeeds();
assert!(re_two.is_match(result.stdout_str())); assert!(re_two.is_match(result.stdout_str()));
@ -427,7 +428,7 @@ fn test_ls_long_formats() {
let result = scene let result = scene
.ucmd() .ucmd()
.arg("-n") .arg("-n")
.args(&arg.split(" ").collect::<Vec<_>>()) .args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats") .arg("test-long-formats")
.succeeds(); .succeeds();
assert!(re_two_num.is_match(result.stdout_str())); assert!(re_two_num.is_match(result.stdout_str()));
@ -446,7 +447,7 @@ fn test_ls_long_formats() {
] { ] {
let result = scene let result = scene
.ucmd() .ucmd()
.args(&arg.split(" ").collect::<Vec<_>>()) .args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats") .arg("test-long-formats")
.succeeds(); .succeeds();
assert!(re_one.is_match(result.stdout_str())); assert!(re_one.is_match(result.stdout_str()));
@ -456,7 +457,7 @@ fn test_ls_long_formats() {
let result = scene let result = scene
.ucmd() .ucmd()
.arg("-n") .arg("-n")
.args(&arg.split(" ").collect::<Vec<_>>()) .args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats") .arg("test-long-formats")
.succeeds(); .succeeds();
assert!(re_one_num.is_match(result.stdout_str())); assert!(re_one_num.is_match(result.stdout_str()));
@ -478,7 +479,7 @@ fn test_ls_long_formats() {
] { ] {
let result = scene let result = scene
.ucmd() .ucmd()
.args(&arg.split(" ").collect::<Vec<_>>()) .args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats") .arg("test-long-formats")
.succeeds(); .succeeds();
assert!(re_zero.is_match(result.stdout_str())); assert!(re_zero.is_match(result.stdout_str()));
@ -488,7 +489,7 @@ fn test_ls_long_formats() {
let result = scene let result = scene
.ucmd() .ucmd()
.arg("-n") .arg("-n")
.args(&arg.split(" ").collect::<Vec<_>>()) .args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats") .arg("test-long-formats")
.succeeds(); .succeeds();
assert!(re_zero.is_match(result.stdout_str())); assert!(re_zero.is_match(result.stdout_str()));
@ -898,6 +899,12 @@ fn test_ls_recursive() {
scene.ucmd().arg("a").succeeds(); scene.ucmd().arg("a").succeeds();
scene.ucmd().arg("a/a").succeeds(); scene.ucmd().arg("a/a").succeeds();
scene
.ucmd()
.arg("z")
.arg("-R")
.succeeds()
.stdout_contains(&"z:");
let result = scene let result = scene
.ucmd() .ucmd()
.arg("--color=never") .arg("--color=never")
@ -1063,7 +1070,7 @@ fn test_ls_indicator_style() {
for opt in options { for opt in options {
scene scene
.ucmd() .ucmd()
.arg(format!("{}", opt)) .arg(opt.to_string())
.succeeds() .succeeds()
.stdout_contains(&"/"); .stdout_contains(&"/");
} }
@ -1085,7 +1092,10 @@ fn test_ls_indicator_style() {
{ {
use self::unix_socket::UnixListener; use self::unix_socket::UnixListener;
let dir = tempfile::Builder::new().prefix("unix_socket").tempdir().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 socket_path = dir.path().join("sock");
let _listener = UnixListener::bind(&socket_path).expect("failed to create socket"); let _listener = UnixListener::bind(&socket_path).expect("failed to create socket");

View file

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

View file

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

View file

@ -2,15 +2,22 @@ use crate::common::util::*;
#[test] #[test]
fn test_more_no_arg() { fn test_more_no_arg() {
// stderr = more: Reading from stdin isn't supported yet. // Reading from stdin is now supported, so this must succeed
new_ucmd!().fails(); if atty::is(atty::Stream::Stdout) {
new_ucmd!().succeeds();
} else {}
} }
#[test] #[test]
fn test_more_dir_arg() { fn test_more_dir_arg() {
let result = new_ucmd!().arg(".").run(); // Run the test only if there's a valud terminal, else do nothing
result.failure(); // Maybe we could capture the error, i.e. "Device not found" in that case
const EXPECTED_ERROR_MESSAGE: &str = // but I am leaving this for later
"more: '.' is a directory.\nTry 'more --help' for more information."; if atty::is(atty::Stream::Stdout) {
assert_eq!(result.stderr_str().trim(), EXPECTED_ERROR_MESSAGE); let result = new_ucmd!().arg(".").run();
result.failure();
const EXPECTED_ERROR_MESSAGE: &str =
"more: '.' is a directory.\nTry 'more --help' for more information.";
assert_eq!(result.stderr_str().trim(), EXPECTED_ERROR_MESSAGE);
} else {}
} }

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
use crate::common::util::*; use crate::common::util::*;
static GIBBERISH: &'static str = "supercalifragilisticexpialidocious"; static GIBBERISH: &str = "supercalifragilisticexpialidocious";
#[test] #[test]
fn test_canonicalize() { 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> { fn convert_path<'a>(path: &'a str) -> Cow<'a, str> {
#[cfg(windows)] #[cfg(windows)]
return path.replace("/", "\\").into(); return path.replace("/", "\\").into();

View file

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

View file

@ -288,7 +288,7 @@ fn test_dictionary_order() {
#[test] #[test]
fn test_dictionary_order2() { fn test_dictionary_order2() {
for non_dictionary_order2_param in vec!["-d"] { for non_dictionary_order2_param in &["-d"] {
new_ucmd!() new_ucmd!()
.pipe_in("a👦🏻aa b\naaaa b") .pipe_in("a👦🏻aa b\naaaa b")
.arg(non_dictionary_order2_param) .arg(non_dictionary_order2_param)
@ -299,7 +299,7 @@ fn test_dictionary_order2() {
#[test] #[test]
fn test_non_printing_chars() { fn test_non_printing_chars() {
for non_printing_chars_param in vec!["-i"] { for non_printing_chars_param in &["-i"] {
new_ucmd!() new_ucmd!()
.pipe_in("a👦🏻aa\naaaa") .pipe_in("a👦🏻aa\naaaa")
.arg(non_printing_chars_param) .arg(non_printing_chars_param)
@ -361,7 +361,7 @@ fn test_mixed_floats_ints_chars_numeric_stable() {
#[test] #[test]
fn test_numeric_floats_and_ints2() { 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"; let input = "1.444\n8.013\n1\n-8\n1.04\n-1";
new_ucmd!() new_ucmd!()
.arg(numeric_sort_param) .arg(numeric_sort_param)
@ -373,7 +373,7 @@ fn test_numeric_floats_and_ints2() {
#[test] #[test]
fn test_numeric_floats2() { 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"; let input = "1.444\n8.013\n1.58590\n-8.90880\n1.040000000\n-.05";
new_ucmd!() new_ucmd!()
.arg(numeric_sort_param) .arg(numeric_sort_param)
@ -426,7 +426,7 @@ fn test_default_unsorted_ints2() {
#[test] #[test]
fn test_numeric_unique_ints2() { 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"; let input = "9\n9\n8\n1\n";
new_ucmd!() new_ucmd!()
.arg(numeric_unique_sort_param) .arg(numeric_unique_sort_param)
@ -471,7 +471,7 @@ fn test_keys_invalid_field() {
new_ucmd!() new_ucmd!()
.args(&["-k", "1."]) .args(&["-k", "1."])
.fails() .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] #[test]
@ -479,7 +479,7 @@ fn test_keys_invalid_field_option() {
new_ucmd!() new_ucmd!()
.args(&["-k", "1.1x"]) .args(&["-k", "1.1x"])
.fails() .fails()
.stderr_only("sort: invalid option for key: `x`"); .stderr_only("sort: failed to parse key `1.1x`: invalid option: `x`");
} }
#[test] #[test]
@ -487,7 +487,7 @@ fn test_keys_invalid_field_zero() {
new_ucmd!() new_ucmd!()
.args(&["-k", "0.1"]) .args(&["-k", "0.1"])
.fails() .fails()
.stderr_only("sort: field index was 0"); .stderr_only("sort: failed to parse key `0.1`: field index can not be 0");
} }
#[test] #[test]
@ -495,7 +495,7 @@ fn test_keys_invalid_char_zero() {
new_ucmd!() new_ucmd!()
.args(&["-k", "1.0"]) .args(&["-k", "1.0"])
.fails() .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] #[test]
@ -586,6 +586,47 @@ fn test_keys_negative_size_match() {
test_helper("keys_negative_size", &["-k 3,1"]); 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] #[test]
fn test_zero_terminated() { fn test_zero_terminated() {
test_helper("zero-terminated", &["-z"]); test_helper("zero-terminated", &["-z"]);
@ -707,10 +748,9 @@ fn test_dictionary_and_nonprinting_conflicts() {
.succeeds(); .succeeds();
} }
for conflicting_arg in &conflicting_args { for conflicting_arg in &conflicting_args {
// FIXME: this should ideally fail.
new_ucmd!() new_ucmd!()
.args(&["-k", &format!("1{},1{}", restricted_arg, conflicting_arg)]) .args(&["-k", &format!("1{},1{}", restricted_arg, conflicting_arg)])
.succeeds(); .fails();
} }
} }
} }
@ -737,3 +777,8 @@ fn test_nonexistent_file() {
"sort: cannot read: \"nonexistent.txt\": The system cannot find the file specified. (os error 2)", "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 to_write = std::cmp::min(remaining_size, buffer.len());
let buf = &mut buffer[..to_write]; let buf = &mut buffer[..to_write];
rng.fill(buf); rng.fill(buf);
writer.write(buf).unwrap(); writer.write_all(buf).unwrap();
remaining_size -= to_write; remaining_size -= to_write;
} }
@ -179,6 +179,7 @@ fn test_split_bytes_prime_part_size() {
let mut fns = glob.collect(); let mut fns = glob.collect();
// glob.collect() is not guaranteed to return in sorted order, so we sort. // glob.collect() is not guaranteed to return in sorted order, so we sort.
fns.sort(); fns.sort();
#[allow(clippy::needless_range_loop)]
for i in 0..5 { for i in 0..5 {
assert_eq!(glob.directory.metadata(&fns[i]).len(), 1753); assert_eq!(glob.directory.metadata(&fns[i]).len(), 1753);
} }
@ -246,9 +247,9 @@ fn test_filter() {
assert!( assert!(
glob.collate().iter().find(|&&c| { glob.collate().iter().find(|&&c| {
// is not i // is not i
c != ('i' as u8) c != (b'i')
// is not newline // is not newline
&& c != ('\n' as u8) && c != (b'\n')
}) == None }) == None
); );
} }
@ -271,7 +272,7 @@ fn test_filter_with_env_var_set() {
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$"); let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
assert_eq!(glob.collate(), at.read_bytes(name)); 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] #[test]

View file

@ -97,13 +97,13 @@ fn test_invalid_option() {
} }
#[cfg(any(target_os = "linux", target_vendor = "apple"))] #[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 "%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"))] #[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"; "%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")] #[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] #[test]
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
@ -140,7 +140,7 @@ fn test_terse_normal_format() {
assert!(!v_expect.is_empty()); assert!(!v_expect.is_empty());
// uu_stat does not support selinux // 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` // assume last element contains: `SELinux security context string`
v_expect.pop(); v_expect.pop();
} }
@ -222,7 +222,7 @@ fn test_symlinks() {
let mut tested: bool = false; let mut tested: bool = false;
// arbitrarily chosen symlinks with hope that the CI environment provides at least one of them // 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/sh",
"/bin/sudoedit", "/bin/sudoedit",
"/usr/bin/ex", "/usr/bin/ex",

View file

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

View file

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

View file

@ -1,8 +1,8 @@
use crate::common::util::*; use crate::common::util::*;
use std::io::{Seek, SeekFrom, Write}; use std::io::{Seek, SeekFrom, Write};
static TFILE1: &'static str = "truncate_test_1"; static TFILE1: &str = "truncate_test_1";
static TFILE2: &'static str = "truncate_test_2"; static TFILE2: &str = "truncate_test_2";
#[test] #[test]
fn test_increase_file_size() { fn test_increase_file_size() {

View file

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

View file

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

View file

@ -1,7 +1,4 @@
#![allow(dead_code)] #![allow(dead_code)]
#[cfg(not(windows))]
use libc;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use std::env; use std::env;
#[cfg(not(windows))] #[cfg(not(windows))]
@ -39,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 /// Test if the program is running under CI
pub fn is_ci() -> bool { pub fn is_ci() -> bool {
std::env::var("CI") std::env::var("CI")
.unwrap_or(String::from("false")) .unwrap_or_else(|_| String::from("false"))
.eq_ignore_ascii_case("true") .eq_ignore_ascii_case("true")
} }
@ -478,7 +475,7 @@ impl AtPath {
.append(true) .append(true)
.open(self.plus(name)) .open(self.plus(name))
.unwrap(); .unwrap();
f.write(contents.as_bytes()) f.write_all(contents.as_bytes())
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e)); .unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
} }
@ -791,7 +788,7 @@ impl UCommand {
if self.has_run { if self.has_run {
panic!("{}", ALREADY_RUN); panic!("{}", ALREADY_RUN);
} }
self.comm_string.push_str(" "); self.comm_string.push(' ');
self.comm_string self.comm_string
.push_str(arg.as_ref().to_str().unwrap_or_default()); .push_str(arg.as_ref().to_str().unwrap_or_default());
self.raw.arg(arg.as_ref()); self.raw.arg(arg.as_ref());
@ -811,7 +808,7 @@ impl UCommand {
.accept_any(); .accept_any();
for s in strings { for s in strings {
self.comm_string.push_str(" "); self.comm_string.push(' ');
self.comm_string.push_str(&s); self.comm_string.push_str(&s);
} }
@ -867,9 +864,9 @@ impl UCommand {
log_info("run", &self.comm_string); log_info("run", &self.comm_string);
let mut child = self let mut child = self
.raw .raw
.stdin(self.stdin.take().unwrap_or_else(|| Stdio::piped())) .stdin(self.stdin.take().unwrap_or_else(Stdio::piped))
.stdout(self.stdout.take().unwrap_or_else(|| Stdio::piped())) .stdout(self.stdout.take().unwrap_or_else(Stdio::piped))
.stderr(self.stderr.take().unwrap_or_else(|| Stdio::piped())) .stderr(self.stderr.take().unwrap_or_else(Stdio::piped))
.spawn() .spawn()
.unwrap(); .unwrap();
@ -948,10 +945,7 @@ pub fn read_size(child: &mut Child, size: usize) -> String {
} }
pub fn vec_of_size(n: usize) -> Vec<u8> { pub fn vec_of_size(n: usize) -> Vec<u8> {
let mut result = Vec::new(); let result = vec![b'a'; n];
for _ in 0..n {
result.push('a' as u8);
}
assert_eq!(result.len(), n); assert_eq!(result.len(), n);
result 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

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

View file

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

View file

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