mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-31 13:07:46 +00:00
Merge branch 'master' into implement-more
This commit is contained in:
commit
fe42808e9b
146 changed files with 6701 additions and 4057 deletions
26
tests/benches/factor/Cargo.toml
Normal file
26
tests/benches/factor/Cargo.toml
Normal file
|
@ -0,0 +1,26 @@
|
|||
[package]
|
||||
name = "uu_factor_benches"
|
||||
version = "0.0.0"
|
||||
authors = ["nicoo <nicoo@debian.org>"]
|
||||
license = "MIT"
|
||||
description = "Benchmarks for the uu_factor integer factorization tool"
|
||||
homepage = "https://github.com/uutils/coreutils"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
uu_factor = { path = "../../../src/uu/factor" }
|
||||
|
||||
[dev-dependencies]
|
||||
array-init = "2.0.0"
|
||||
criterion = "0.3"
|
||||
rand = "0.7"
|
||||
rand_chacha = "0.2.2"
|
||||
|
||||
|
||||
[[bench]]
|
||||
name = "gcd"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "table"
|
||||
harness = false
|
29
tests/benches/factor/benches/gcd.rs
Normal file
29
tests/benches/factor/benches/gcd.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use uu_factor::numeric;
|
||||
|
||||
fn gcd(c: &mut Criterion) {
|
||||
let inputs = {
|
||||
// Deterministic RNG; use an explicitely-named RNG to guarantee stability
|
||||
use rand::{RngCore, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
const SEED: u64 = 0xa_b4d_1dea_dead_cafe;
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(SEED);
|
||||
|
||||
std::iter::repeat_with(move || (rng.next_u64(), rng.next_u64()))
|
||||
};
|
||||
|
||||
let mut group = c.benchmark_group("gcd");
|
||||
for (n, m) in inputs.take(10) {
|
||||
group.bench_with_input(
|
||||
BenchmarkId::from_parameter(format!("{}_{}", n, m)),
|
||||
&(n, m),
|
||||
|b, &(n, m)| {
|
||||
b.iter(|| numeric::gcd(n, m));
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish()
|
||||
}
|
||||
|
||||
criterion_group!(benches, gcd);
|
||||
criterion_main!(benches);
|
78
tests/benches/factor/benches/table.rs
Normal file
78
tests/benches/factor/benches/table.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use array_init::array_init;
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
use std::convert::TryInto;
|
||||
use uu_factor::{table::*, Factors};
|
||||
|
||||
fn table(c: &mut Criterion) {
|
||||
#[cfg(target_os = "linux")]
|
||||
check_personality();
|
||||
|
||||
const INPUT_SIZE: usize = 128;
|
||||
assert!(
|
||||
INPUT_SIZE % CHUNK_SIZE == 0,
|
||||
"INPUT_SIZE ({}) is not divisible by CHUNK_SIZE ({})",
|
||||
INPUT_SIZE,
|
||||
CHUNK_SIZE
|
||||
);
|
||||
let inputs = {
|
||||
// Deterministic RNG; use an explicitely-named RNG to guarantee stability
|
||||
use rand::{RngCore, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
const SEED: u64 = 0xdead_bebe_ea75_cafe;
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(SEED);
|
||||
|
||||
std::iter::repeat_with(move || array_init::<_, _, INPUT_SIZE>(|_| rng.next_u64()))
|
||||
};
|
||||
|
||||
let mut group = c.benchmark_group("table");
|
||||
group.throughput(Throughput::Elements(INPUT_SIZE as _));
|
||||
for a in inputs.take(10) {
|
||||
let a_str = format!("{:?}", a);
|
||||
group.bench_with_input(BenchmarkId::new("factor_chunk", &a_str), &a, |b, &a| {
|
||||
b.iter(|| {
|
||||
let mut n_s = a.clone();
|
||||
let mut f_s: [_; INPUT_SIZE] = array_init(|_| Factors::one());
|
||||
for (n_s, f_s) in n_s.chunks_mut(CHUNK_SIZE).zip(f_s.chunks_mut(CHUNK_SIZE)) {
|
||||
factor_chunk(n_s.try_into().unwrap(), f_s.try_into().unwrap())
|
||||
}
|
||||
})
|
||||
});
|
||||
group.bench_with_input(BenchmarkId::new("factor", &a_str), &a, |b, &a| {
|
||||
b.iter(|| {
|
||||
let mut n_s = a.clone();
|
||||
let mut f_s: [_; INPUT_SIZE] = array_init(|_| Factors::one());
|
||||
for (n, f) in n_s.iter_mut().zip(f_s.iter_mut()) {
|
||||
factor(n, f)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
group.finish()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn check_personality() {
|
||||
use std::fs;
|
||||
const ADDR_NO_RANDOMIZE: u64 = 0x0040000;
|
||||
const PERSONALITY_PATH: &'static str = "/proc/self/personality";
|
||||
|
||||
let p_string = fs::read_to_string(PERSONALITY_PATH)
|
||||
.expect(&format!("Couldn't read '{}'", PERSONALITY_PATH))
|
||||
.strip_suffix("\n")
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
|
||||
let personality = u64::from_str_radix(&p_string, 16).expect(&format!(
|
||||
"Expected a hex value for personality, got '{:?}'",
|
||||
p_string
|
||||
));
|
||||
if personality & ADDR_NO_RANDOMIZE == 0 {
|
||||
eprintln!(
|
||||
"WARNING: Benchmarking with ASLR enabled (personality is {:x}), results might not be reproducible.",
|
||||
personality
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(benches, table);
|
||||
criterion_main!(benches);
|
|
@ -98,7 +98,7 @@ fn test_wrap_bad_arg() {
|
|||
.arg(wrap_param)
|
||||
.arg("b")
|
||||
.fails()
|
||||
.stderr_only("base32: error: Invalid wrap size: ‘b’: invalid digit found in string\n");
|
||||
.stderr_only("base32: Invalid wrap size: ‘b’: invalid digit found in string\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ fn test_base32_extra_operand() {
|
|||
.arg("a.txt")
|
||||
.arg("a.txt")
|
||||
.fails()
|
||||
.stderr_only("base32: error: extra operand ‘a.txt’");
|
||||
.stderr_only("base32: extra operand ‘a.txt’");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -117,5 +117,5 @@ fn test_base32_file_not_found() {
|
|||
new_ucmd!()
|
||||
.arg("a.txt")
|
||||
.fails()
|
||||
.stderr_only("base32: error: a.txt: No such file or directory");
|
||||
.stderr_only("base32: a.txt: No such file or directory");
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ fn test_wrap_bad_arg() {
|
|||
.arg(wrap_param)
|
||||
.arg("b")
|
||||
.fails()
|
||||
.stderr_only("base64: error: Invalid wrap size: ‘b’: invalid digit found in string\n");
|
||||
.stderr_only("base64: Invalid wrap size: ‘b’: invalid digit found in string\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ fn test_base64_extra_operand() {
|
|||
.arg("a.txt")
|
||||
.arg("a.txt")
|
||||
.fails()
|
||||
.stderr_only("base64: error: extra operand ‘a.txt’");
|
||||
.stderr_only("base64: extra operand ‘a.txt’");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -107,5 +107,5 @@ fn test_base64_file_not_found() {
|
|||
new_ucmd!()
|
||||
.arg("a.txt")
|
||||
.fails()
|
||||
.stderr_only("base64: error: a.txt: No such file or directory");
|
||||
.stderr_only("base64: a.txt: No such file or directory");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::common::util::*;
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
use std::ffi::OsStr;
|
||||
|
||||
#[test]
|
||||
|
@ -108,7 +109,7 @@ fn test_no_args() {
|
|||
fn test_no_args_output() {
|
||||
new_ucmd!()
|
||||
.fails()
|
||||
.stderr_is("basename: error: missing operand\nTry 'basename --help' for more information.");
|
||||
.stderr_is("basename: missing operand\nTry 'basename --help' for more information.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -118,11 +119,13 @@ fn test_too_many_args() {
|
|||
|
||||
#[test]
|
||||
fn test_too_many_args_output() {
|
||||
new_ucmd!().args(&["a", "b", "c"]).fails().stderr_is(
|
||||
"basename: error: extra operand 'c'\nTry 'basename --help' for more information.",
|
||||
);
|
||||
new_ucmd!()
|
||||
.args(&["a", "b", "c"])
|
||||
.fails()
|
||||
.stderr_is("basename: extra operand 'c'\nTry 'basename --help' for more information.");
|
||||
}
|
||||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
fn test_invalid_utf8_args(os_str: &OsStr) {
|
||||
let test_vec = vec![os_str.to_os_string()];
|
||||
new_ucmd!().args(&test_vec).succeeds().stdout_is("fo<EFBFBD>o\n");
|
||||
|
|
|
@ -347,7 +347,13 @@ fn test_squeeze_blank_before_numbering() {
|
|||
#[cfg(unix)]
|
||||
fn test_dev_random() {
|
||||
let mut buf = [0; 2048];
|
||||
let mut proc = new_ucmd!().args(&["/dev/random"]).run_no_wait();
|
||||
#[cfg(target_os = "linux")]
|
||||
const DEV_RANDOM: &str = "/dev/urandom";
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
const DEV_RANDOM: &str = "/dev/random";
|
||||
|
||||
let mut proc = new_ucmd!().args(&[DEV_RANDOM]).run_no_wait();
|
||||
let mut proc_stdout = proc.stdout.take().unwrap();
|
||||
proc_stdout.read_exact(&mut buf).unwrap();
|
||||
|
||||
|
@ -395,14 +401,14 @@ fn test_dev_full_show_all() {
|
|||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
#[ignore]
|
||||
fn test_domain_socket() {
|
||||
use std::io::prelude::*;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::thread;
|
||||
use tempdir::TempDir;
|
||||
use unix_socket::UnixListener;
|
||||
|
||||
let dir = TempDir::new("unix_socket").expect("failed to create dir");
|
||||
let dir = tempfile::Builder::new().prefix("unix_socket").tempdir().expect("failed to create dir");
|
||||
let socket_path = dir.path().join("sock");
|
||||
let listener = UnixListener::bind(&socket_path).expect("failed to create socket");
|
||||
|
||||
|
|
|
@ -282,6 +282,26 @@ fn test_chmod_reference_file() {
|
|||
run_single_test(&tests[0], at, ucmd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_permission_denied() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.mkdir("d/");
|
||||
at.mkdir("d/no-x");
|
||||
at.mkdir("d/no-x/y");
|
||||
|
||||
scene.ucmd().arg("u=rw").arg("d/no-x").succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-R")
|
||||
.arg("o=r")
|
||||
.arg("d")
|
||||
.fails()
|
||||
.stderr_is("chmod: 'd/no-x/y': Permission denied");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chmod_recursive() {
|
||||
let _guard = UMASK_MUTEX.lock();
|
||||
|
@ -338,7 +358,7 @@ fn test_chmod_preserve_root() {
|
|||
.arg("755")
|
||||
.arg("/")
|
||||
.fails()
|
||||
.stderr_contains(&"chmod: error: it is dangerous to operate recursively on '/'");
|
||||
.stderr_contains(&"chmod: it is dangerous to operate recursively on '/'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -21,7 +21,7 @@ fn test_enter_chroot_fails() {
|
|||
|
||||
assert!(result
|
||||
.stderr_str()
|
||||
.starts_with("chroot: error: cannot chroot to jail: Operation not permitted (os error 1)"));
|
||||
.starts_with("chroot: cannot chroot to jail: Operation not permitted (os error 1)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -32,7 +32,7 @@ fn test_no_such_directory() {
|
|||
|
||||
ucmd.arg("a")
|
||||
.fails()
|
||||
.stderr_is("chroot: error: cannot change root directory to `a`: no such directory");
|
||||
.stderr_is("chroot: cannot change root directory to `a`: no such directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -43,9 +43,7 @@ fn test_invalid_user_spec() {
|
|||
|
||||
let result = ucmd.arg("a").arg("--userspec=ARABA:").fails();
|
||||
|
||||
assert!(result
|
||||
.stderr_str()
|
||||
.starts_with("chroot: error: invalid userspec"));
|
||||
assert!(result.stderr_str().starts_with("chroot: invalid userspec"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -66,7 +66,7 @@ fn test_invalid_file() {
|
|||
.arg(folder_name)
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cksum: error: 'asdf' No such file or directory");
|
||||
.stderr_contains("cksum: 'asdf' No such file or directory");
|
||||
|
||||
// Then check when the file is of an invalid type
|
||||
at.mkdir(folder_name);
|
||||
|
@ -74,7 +74,7 @@ fn test_invalid_file() {
|
|||
.arg(folder_name)
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cksum: error: 'asdf' Is a directory");
|
||||
.stderr_contains("cksum: 'asdf' Is a directory");
|
||||
}
|
||||
|
||||
// Make sure crc is correct for files larger than 32 bytes
|
||||
|
|
|
@ -214,8 +214,8 @@ fn test_cp_arg_symlink() {
|
|||
fn test_cp_arg_no_clobber() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg("--no-clobber")
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.arg("--no-clobber")
|
||||
.succeeds();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "How are you?\n");
|
||||
|
@ -305,7 +305,39 @@ fn test_cp_arg_backup() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg("--backup")
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.arg("-b")
|
||||
.succeeds();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_arg_backup_with_other_args() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.arg("-vbL")
|
||||
.succeeds();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_arg_backup_arg_first() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds();
|
||||
|
||||
|
@ -321,6 +353,7 @@ fn test_cp_arg_suffix() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg("-b")
|
||||
.arg("--suffix")
|
||||
.arg(".bak")
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
|
@ -333,6 +366,207 @@ fn test_cp_arg_suffix() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_custom_backup_suffix_via_env() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let suffix = "super-suffix-of-the-century";
|
||||
|
||||
ucmd.arg("-b")
|
||||
.env("SIMPLE_BACKUP_SUFFIX", suffix)
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}{}", TEST_HOW_ARE_YOU_SOURCE, suffix)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_numbered_with_t() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=t")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_numbered() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=numbered")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_existing() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=existing")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_nil() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=nil")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_numbered_if_existing_backup_existing() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let existing_backup = &*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE);
|
||||
at.touch(existing_backup);
|
||||
|
||||
ucmd.arg("--backup=existing")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(TEST_HOW_ARE_YOU_SOURCE));
|
||||
assert!(at.file_exists(existing_backup));
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}.~2~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_numbered_if_existing_backup_nil() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let existing_backup = &*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE);
|
||||
|
||||
at.touch(existing_backup);
|
||||
ucmd.arg("--backup=nil")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(TEST_HOW_ARE_YOU_SOURCE));
|
||||
assert!(at.file_exists(existing_backup));
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}.~2~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_simple() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=simple")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_never() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=never")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_none() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=none")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert!(!at.file_exists(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_off() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup=off")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert!(!at.file_exists(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_backup_no_clobber_conflicting_options() {
|
||||
let (_, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup")
|
||||
.arg("--no-clobber")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.fails()
|
||||
.stderr_is("cp: options --backup and --no-clobber are mutually exclusive\nTry 'cp --help' for more information.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_deref_conflicting_options() {
|
||||
new_ucmd!()
|
||||
|
|
|
@ -208,7 +208,7 @@ fn test_up_to_match_repeat_over() {
|
|||
ucmd.args(&["numbers50.txt", "/9$/", "{50}"])
|
||||
.fails()
|
||||
.stdout_is("16\n29\n30\n30\n30\n6\n")
|
||||
.stderr_is("csplit: error: '/9$/': match not found on repetition 5");
|
||||
.stderr_is("csplit: '/9$/': match not found on repetition 5");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -219,7 +219,7 @@ fn test_up_to_match_repeat_over() {
|
|||
ucmd.args(&["numbers50.txt", "/9$/", "{50}", "-k"])
|
||||
.fails()
|
||||
.stdout_is("16\n29\n30\n30\n30\n6\n")
|
||||
.stderr_is("csplit: error: '/9$/': match not found on repetition 5");
|
||||
.stderr_is("csplit: '/9$/': match not found on repetition 5");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -365,7 +365,7 @@ fn test_option_keep() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-k", "numbers50.txt", "/20/", "/nope/"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/nope/': match not found")
|
||||
.stderr_is("csplit: '/nope/': match not found")
|
||||
.stdout_is("48\n93\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -541,7 +541,7 @@ fn test_up_to_match_context_overflow() {
|
|||
ucmd.args(&["numbers50.txt", "/45/+10"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/45/+10': line number out of range");
|
||||
.stderr_is("csplit: '/45/+10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -552,7 +552,7 @@ fn test_up_to_match_context_overflow() {
|
|||
ucmd.args(&["numbers50.txt", "/45/+10", "-k"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/45/+10': line number out of range");
|
||||
.stderr_is("csplit: '/45/+10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -567,7 +567,7 @@ fn test_skip_to_match_context_underflow() {
|
|||
ucmd.args(&["numbers50.txt", "%5%-10"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '%5%-10': line number out of range");
|
||||
.stderr_is("csplit: '%5%-10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -578,7 +578,7 @@ fn test_skip_to_match_context_underflow() {
|
|||
ucmd.args(&["numbers50.txt", "%5%-10", "-k"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '%5%-10': line number out of range");
|
||||
.stderr_is("csplit: '%5%-10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -592,7 +592,7 @@ fn test_skip_to_match_context_overflow() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%45%+10"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%45%+10': line number out of range");
|
||||
.stderr_only("csplit: '%45%+10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -602,7 +602,7 @@ fn test_skip_to_match_context_overflow() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%45%+10", "-k"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%45%+10': line number out of range");
|
||||
.stderr_only("csplit: '%45%+10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -616,7 +616,7 @@ fn test_up_to_no_match1() {
|
|||
ucmd.args(&["numbers50.txt", "/4/", "/nope/"])
|
||||
.fails()
|
||||
.stdout_is("6\n135\n")
|
||||
.stderr_is("csplit: error: '/nope/': match not found");
|
||||
.stderr_is("csplit: '/nope/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -627,7 +627,7 @@ fn test_up_to_no_match1() {
|
|||
ucmd.args(&["numbers50.txt", "/4/", "/nope/", "-k"])
|
||||
.fails()
|
||||
.stdout_is("6\n135\n")
|
||||
.stderr_is("csplit: error: '/nope/': match not found");
|
||||
.stderr_is("csplit: '/nope/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -643,7 +643,7 @@ fn test_up_to_no_match2() {
|
|||
ucmd.args(&["numbers50.txt", "/4/", "/nope/", "{50}"])
|
||||
.fails()
|
||||
.stdout_is("6\n135\n")
|
||||
.stderr_is("csplit: error: '/nope/': match not found");
|
||||
.stderr_is("csplit: '/nope/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -654,7 +654,7 @@ fn test_up_to_no_match2() {
|
|||
ucmd.args(&["numbers50.txt", "/4/", "/nope/", "{50}", "-k"])
|
||||
.fails()
|
||||
.stdout_is("6\n135\n")
|
||||
.stderr_is("csplit: error: '/nope/': match not found");
|
||||
.stderr_is("csplit: '/nope/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -670,7 +670,7 @@ fn test_up_to_no_match3() {
|
|||
ucmd.args(&["numbers50.txt", "/0$/", "{50}"])
|
||||
.fails()
|
||||
.stdout_is("18\n30\n30\n30\n30\n3\n")
|
||||
.stderr_is("csplit: error: '/0$/': match not found on repetition 5");
|
||||
.stderr_is("csplit: '/0$/': match not found on repetition 5");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -681,7 +681,7 @@ fn test_up_to_no_match3() {
|
|||
ucmd.args(&["numbers50.txt", "/0$/", "{50}", "-k"])
|
||||
.fails()
|
||||
.stdout_is("18\n30\n30\n30\n30\n3\n")
|
||||
.stderr_is("csplit: error: '/0$/': match not found on repetition 5");
|
||||
.stderr_is("csplit: '/0$/': match not found on repetition 5");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -701,7 +701,7 @@ fn test_up_to_no_match4() {
|
|||
ucmd.args(&["numbers50.txt", "/nope/", "/4/"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/nope/': match not found");
|
||||
.stderr_is("csplit: '/nope/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -712,7 +712,7 @@ fn test_up_to_no_match4() {
|
|||
ucmd.args(&["numbers50.txt", "/nope/", "/4/", "-k"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/nope/': match not found");
|
||||
.stderr_is("csplit: '/nope/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -741,7 +741,7 @@ fn test_up_to_no_match6() {
|
|||
ucmd.args(&["numbers50.txt", "/nope/-5"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/nope/-5': match not found");
|
||||
.stderr_is("csplit: '/nope/-5': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -752,7 +752,7 @@ fn test_up_to_no_match6() {
|
|||
ucmd.args(&["numbers50.txt", "/nope/-5", "-k"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/nope/-5': match not found");
|
||||
.stderr_is("csplit: '/nope/-5': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -767,7 +767,7 @@ fn test_up_to_no_match7() {
|
|||
ucmd.args(&["numbers50.txt", "/nope/+5"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/nope/+5': match not found");
|
||||
.stderr_is("csplit: '/nope/+5': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -778,7 +778,7 @@ fn test_up_to_no_match7() {
|
|||
ucmd.args(&["numbers50.txt", "/nope/+5", "-k"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/nope/+5': match not found");
|
||||
.stderr_is("csplit: '/nope/+5': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -792,7 +792,7 @@ fn test_skip_to_no_match1() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%nope%"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%nope%': match not found");
|
||||
.stderr_only("csplit: '%nope%': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -805,7 +805,7 @@ fn test_skip_to_no_match2() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%nope%", "{50}"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%nope%': match not found");
|
||||
.stderr_only("csplit: '%nope%': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -818,7 +818,7 @@ fn test_skip_to_no_match3() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%0$%", "{50}"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%0$%': match not found on repetition 5");
|
||||
.stderr_only("csplit: '%0$%': match not found on repetition 5");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -831,7 +831,7 @@ fn test_skip_to_no_match4() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%nope%", "/4/"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%nope%': match not found");
|
||||
.stderr_only("csplit: '%nope%': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -858,7 +858,7 @@ fn test_skip_to_no_match6() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%nope%-5"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%nope%-5': match not found");
|
||||
.stderr_only("csplit: '%nope%-5': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -871,7 +871,7 @@ fn test_skip_to_no_match7() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%nope%+5"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%nope%+5': match not found");
|
||||
.stderr_only("csplit: '%nope%+5': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -884,7 +884,7 @@ fn test_no_match() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "%nope%"])
|
||||
.fails()
|
||||
.stderr_only("csplit: error: '%nope%': match not found");
|
||||
.stderr_only("csplit: '%nope%': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -895,7 +895,7 @@ fn test_no_match() {
|
|||
ucmd.args(&["numbers50.txt", "/nope/"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '/nope/': match not found");
|
||||
.stderr_is("csplit: '/nope/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -992,7 +992,7 @@ fn test_too_small_linenum_repeat() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "/20/", "10", "{*}"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '10': line number out of range on repetition 5")
|
||||
.stderr_is("csplit: '10': line number out of range on repetition 5")
|
||||
.stdout_is("48\n0\n0\n30\n30\n30\n3\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1003,7 +1003,7 @@ fn test_too_small_linenum_repeat() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "/20/", "10", "{*}", "-k"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '10': line number out of range on repetition 5")
|
||||
.stderr_is("csplit: '10': line number out of range on repetition 5")
|
||||
.stdout_is("48\n0\n0\n30\n30\n30\n3\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1025,7 +1025,7 @@ fn test_linenum_out_of_range1() {
|
|||
ucmd.args(&["numbers50.txt", "100"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '100': line number out of range");
|
||||
.stderr_is("csplit: '100': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1036,7 +1036,7 @@ fn test_linenum_out_of_range1() {
|
|||
ucmd.args(&["numbers50.txt", "100", "-k"])
|
||||
.fails()
|
||||
.stdout_is("141\n")
|
||||
.stderr_is("csplit: error: '100': line number out of range");
|
||||
.stderr_is("csplit: '100': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1051,7 +1051,7 @@ fn test_linenum_out_of_range2() {
|
|||
ucmd.args(&["numbers50.txt", "10", "100"])
|
||||
.fails()
|
||||
.stdout_is("18\n123\n")
|
||||
.stderr_is("csplit: error: '100': line number out of range");
|
||||
.stderr_is("csplit: '100': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1062,7 +1062,7 @@ fn test_linenum_out_of_range2() {
|
|||
ucmd.args(&["numbers50.txt", "10", "100", "-k"])
|
||||
.fails()
|
||||
.stdout_is("18\n123\n")
|
||||
.stderr_is("csplit: error: '100': line number out of range");
|
||||
.stderr_is("csplit: '100': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1078,7 +1078,7 @@ fn test_linenum_out_of_range3() {
|
|||
ucmd.args(&["numbers50.txt", "40", "{2}"])
|
||||
.fails()
|
||||
.stdout_is("108\n33\n")
|
||||
.stderr_is("csplit: error: '40': line number out of range on repetition 1");
|
||||
.stderr_is("csplit: '40': line number out of range on repetition 1");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1089,7 +1089,7 @@ fn test_linenum_out_of_range3() {
|
|||
ucmd.args(&["numbers50.txt", "40", "{2}", "-k"])
|
||||
.fails()
|
||||
.stdout_is("108\n33\n")
|
||||
.stderr_is("csplit: error: '40': line number out of range on repetition 1");
|
||||
.stderr_is("csplit: '40': line number out of range on repetition 1");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1105,7 +1105,7 @@ fn test_linenum_out_of_range4() {
|
|||
ucmd.args(&["numbers50.txt", "40", "{*}"])
|
||||
.fails()
|
||||
.stdout_is("108\n33\n")
|
||||
.stderr_is("csplit: error: '40': line number out of range on repetition 1");
|
||||
.stderr_is("csplit: '40': line number out of range on repetition 1");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1116,7 +1116,7 @@ fn test_linenum_out_of_range4() {
|
|||
ucmd.args(&["numbers50.txt", "40", "{*}", "-k"])
|
||||
.fails()
|
||||
.stdout_is("108\n33\n")
|
||||
.stderr_is("csplit: error: '40': line number out of range on repetition 1");
|
||||
.stderr_is("csplit: '40': line number out of range on repetition 1");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1132,7 +1132,7 @@ fn test_skip_to_match_negative_offset_before_a_match() {
|
|||
ucmd.args(&["numbers50.txt", "/20/-10", "/15/"])
|
||||
.fails()
|
||||
.stdout_is("18\n123\n")
|
||||
.stderr_is("csplit: error: '/15/': match not found");
|
||||
.stderr_is("csplit: '/15/': match not found");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
|
@ -1177,7 +1177,7 @@ fn test_corner_case2() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "/10/-5", "/10/"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/10/': match not found")
|
||||
.stderr_is("csplit: '/10/': match not found")
|
||||
.stdout_is("8\n133\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1191,7 +1191,7 @@ fn test_corner_case3() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "/15/-3", "14", "/15/"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/15/': match not found")
|
||||
.stderr_is("csplit: '/15/': match not found")
|
||||
.stdout_is("24\n6\n111\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1223,7 +1223,7 @@ fn test_up_to_match_context_underflow() {
|
|||
ucmd.args(&["numbers50.txt", "/5/-10"])
|
||||
.fails()
|
||||
.stdout_is("0\n141\n")
|
||||
.stderr_is("csplit: error: '/5/-10': line number out of range");
|
||||
.stderr_is("csplit: '/5/-10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -1234,7 +1234,7 @@ fn test_up_to_match_context_underflow() {
|
|||
ucmd.args(&["numbers50.txt", "/5/-10", "-k"])
|
||||
.fails()
|
||||
.stdout_is("0\n141\n")
|
||||
.stderr_is("csplit: error: '/5/-10': line number out of range");
|
||||
.stderr_is("csplit: '/5/-10': line number out of range");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("counting splits")
|
||||
|
@ -1251,7 +1251,7 @@ fn test_linenum_range_with_up_to_match1() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "10", "/12/-5"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/12/-5': line number out of range")
|
||||
.stderr_is("csplit: '/12/-5': line number out of range")
|
||||
.stdout_is("18\n0\n123\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1262,7 +1262,7 @@ fn test_linenum_range_with_up_to_match1() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "10", "/12/-5", "-k"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/12/-5': line number out of range")
|
||||
.stderr_is("csplit: '/12/-5': line number out of range")
|
||||
.stdout_is("18\n0\n123\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1281,7 +1281,7 @@ fn test_linenum_range_with_up_to_match2() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "10", "/12/-15"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/12/-15': line number out of range")
|
||||
.stderr_is("csplit: '/12/-15': line number out of range")
|
||||
.stdout_is("18\n0\n123\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1292,7 +1292,7 @@ fn test_linenum_range_with_up_to_match2() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "10", "/12/-15", "-k"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/12/-15': line number out of range")
|
||||
.stderr_is("csplit: '/12/-15': line number out of range")
|
||||
.stdout_is("18\n0\n123\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
@ -1310,7 +1310,7 @@ fn test_linenum_range_with_up_to_match3() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["numbers50.txt", "10", "/10/", "-k"])
|
||||
.fails()
|
||||
.stderr_is("csplit: error: '/10/': match not found")
|
||||
.stderr_is("csplit: '/10/': match not found")
|
||||
.stdout_is("18\n123\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
|
|
|
@ -149,11 +149,11 @@ fn test_directory_and_no_such_file() {
|
|||
ucmd.arg("-b1")
|
||||
.arg("some")
|
||||
.run()
|
||||
.stderr_is("cut: error: some: Is a directory\n");
|
||||
.stderr_is("cut: some: Is a directory\n");
|
||||
|
||||
new_ucmd!()
|
||||
.arg("-b1")
|
||||
.arg("some")
|
||||
.run()
|
||||
.stderr_is("cut: error: some: No such file or directory\n");
|
||||
.stderr_is("cut: some: No such file or directory\n");
|
||||
}
|
||||
|
|
|
@ -104,6 +104,29 @@ fn test_date_format_full_day() {
|
|||
.stdout_matches(&re);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_nano_seconds() {
|
||||
// %N nanoseconds (000000000..999999999)
|
||||
let re = Regex::new(r"^\d{1,9}$").unwrap();
|
||||
new_ucmd!().arg("+%N").succeeds().stdout_matches(&re);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_format_without_plus() {
|
||||
// [+FORMAT]
|
||||
new_ucmd!()
|
||||
.arg("%s")
|
||||
.fails()
|
||||
.stderr_contains("date: invalid date ‘%s’")
|
||||
.code_is(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_format_literal() {
|
||||
new_ucmd!().arg("+%%s").succeeds().stdout_is("%s\n");
|
||||
new_ucmd!().arg("+%%N").succeeds().stdout_is("%N\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
fn test_date_set_valid() {
|
||||
|
|
|
@ -27,7 +27,7 @@ fn test_df_output() {
|
|||
stdout_only("Filesystem Size Used Available Capacity Use% Mounted on \n");
|
||||
} else {
|
||||
new_ucmd!().arg("-H").arg("-total").succeeds().stdout_only(
|
||||
"Filesystem Size Used Available Use% Mounted on \n"
|
||||
"Filesystem Size Used Available Use% Mounted on \n",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,15 @@ fn _du_basics_subdir(s: &str) {
|
|||
fn _du_basics_subdir(s: &str) {
|
||||
assert_eq!(s, "0\tsubdir/deeper\n");
|
||||
}
|
||||
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_basics_subdir(s: &str) {
|
||||
assert_eq!(s, "8\tsubdir/deeper\n");
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
fn _du_basics_subdir(s: &str) {
|
||||
// MS-WSL linux has altered expected output
|
||||
if !uucore::os::is_wsl_1() {
|
||||
|
@ -68,7 +76,7 @@ fn test_du_basics_bad_name() {
|
|||
new_ucmd!()
|
||||
.arg("bad_name")
|
||||
.succeeds() // TODO: replace with ".fails()" once `du` is fixed
|
||||
.stderr_only("du: error: bad_name: No such file or directory\n");
|
||||
.stderr_only("du: bad_name: No such file or directory\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -100,7 +108,15 @@ fn _du_soft_link(s: &str) {
|
|||
fn _du_soft_link(s: &str) {
|
||||
assert_eq!(s, "8\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_soft_link(s: &str) {
|
||||
assert_eq!(s, "16\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
fn _du_soft_link(s: &str) {
|
||||
// MS-WSL linux has altered expected output
|
||||
if !uucore::os::is_wsl_1() {
|
||||
|
@ -113,11 +129,9 @@ fn _du_soft_link(s: &str) {
|
|||
#[test]
|
||||
fn test_du_hard_link() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let result_ln = scene.cmd("ln").arg(SUB_FILE).arg(SUB_LINK).run();
|
||||
if !result_ln.succeeded() {
|
||||
scene.ccmd("ln").arg(SUB_FILE).arg(SUB_LINK).succeeds();
|
||||
}
|
||||
at.hard_link(SUB_FILE, SUB_LINK);
|
||||
|
||||
let result = scene.ucmd().arg(SUB_DIR_LINKS).succeeds();
|
||||
|
||||
|
@ -141,7 +155,15 @@ fn _du_hard_link(s: &str) {
|
|||
fn _du_hard_link(s: &str) {
|
||||
assert_eq!(s, "8\tsubdir/links\n")
|
||||
}
|
||||
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_hard_link(s: &str) {
|
||||
assert_eq!(s, "16\tsubdir/links\n")
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
fn _du_hard_link(s: &str) {
|
||||
// MS-WSL linux has altered expected output
|
||||
if !uucore::os::is_wsl_1() {
|
||||
|
@ -181,7 +203,15 @@ fn _du_d_flag(s: &str) {
|
|||
fn _du_d_flag(s: &str) {
|
||||
assert_eq!(s, "8\t./subdir\n8\t./\n");
|
||||
}
|
||||
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_d_flag(s: &str) {
|
||||
assert_eq!(s, "28\t./subdir\n36\t./\n");
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
fn _du_d_flag(s: &str) {
|
||||
// MS-WSL linux has altered expected output
|
||||
if !uucore::os::is_wsl_1() {
|
||||
|
|
|
@ -17,11 +17,11 @@ fn test_complex_arithmetic() {
|
|||
.args(&["9223372036854775807", "+", "9223372036854775807"])
|
||||
.run();
|
||||
run.stdout_is("");
|
||||
run.stderr_is("expr: error: +: Numerical result out of range");
|
||||
run.stderr_is("expr: +: Numerical result out of range");
|
||||
|
||||
let run = new_ucmd!().args(&["9", "/", "0"]).run();
|
||||
run.stdout_is("");
|
||||
run.stderr_is("expr: error: division by zero");
|
||||
run.stderr_is("expr: division by zero");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -54,3 +54,32 @@ fn test_and() {
|
|||
|
||||
new_ucmd!().args(&["", "&", "1"]).run().stdout_is("0\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_substr() {
|
||||
new_ucmd!()
|
||||
.args(&["substr", "abc", "1", "1"])
|
||||
.succeeds()
|
||||
.stdout_only("a\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_substr() {
|
||||
new_ucmd!()
|
||||
.args(&["substr", "abc", "0", "1"])
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stdout_only("\n");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["substr", "abc", &(std::usize::MAX.to_string() + "0"), "1"])
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stdout_only("\n");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["substr", "abc", "0", &(std::usize::MAX.to_string() + "0")])
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stdout_only("\n");
|
||||
}
|
||||
|
|
|
@ -30,21 +30,19 @@ fn test_fmt_w_too_big() {
|
|||
//.stdout_is_fixture("call_graph.expected");
|
||||
assert_eq!(
|
||||
result.stderr_str().trim(),
|
||||
"fmt: error: invalid width: '2501': Numerical result out of range"
|
||||
"fmt: invalid width: '2501': Numerical result out of range"
|
||||
);
|
||||
}
|
||||
/* #[test]
|
||||
Fails for now, see https://github.com/uutils/coreutils/issues/1501
|
||||
#[test]
|
||||
fn test_fmt_w() {
|
||||
let result = new_ucmd!()
|
||||
.arg("-w")
|
||||
.arg("10")
|
||||
.arg("one-word-per-line.txt")
|
||||
.run();
|
||||
//.stdout_is_fixture("call_graph.expected");
|
||||
assert_eq!(result.stdout_str().trim(), "this is a file with one word per line");
|
||||
//.stdout_is_fixture("call_graph.expected");
|
||||
assert_eq!(
|
||||
result.stdout_str().trim(),
|
||||
"this is\na file\nwith one\nword per\nline"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
fmt is pretty broken in general, needs more works to have more tests
|
||||
*/
|
||||
|
|
|
@ -129,6 +129,15 @@ fn test_zero_terminated_syntax_2() {
|
|||
.stdout_is("x\0y");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_terminated_negative_lines() {
|
||||
new_ucmd!()
|
||||
.args(&["-z", "-n", "-1"])
|
||||
.pipe_in("x\0y\0z\0")
|
||||
.run()
|
||||
.stdout_is("x\0y\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_byte_syntax() {
|
||||
new_ucmd!()
|
||||
|
@ -162,6 +171,18 @@ fn test_no_such_file_or_directory() {
|
|||
.stderr_contains("cannot open 'no_such_file.toml' for reading: No such file or directory");
|
||||
}
|
||||
|
||||
/// Test that each non-existent files gets its own error message printed.
|
||||
#[test]
|
||||
fn test_multiple_nonexistent_files() {
|
||||
new_ucmd!()
|
||||
.args(&["bogusfile1", "bogusfile2"])
|
||||
.fails()
|
||||
.stdout_does_not_contain("==> bogusfile1 <==")
|
||||
.stderr_contains("cannot open 'bogusfile1' for reading: No such file or directory")
|
||||
.stdout_does_not_contain("==> bogusfile2 <==")
|
||||
.stderr_contains("cannot open 'bogusfile2' for reading: No such file or directory");
|
||||
}
|
||||
|
||||
// there was a bug not caught by previous tests
|
||||
// where for negative n > 3, the total amount of lines
|
||||
// was correct, but it would eat from the second line
|
||||
|
@ -196,3 +217,28 @@ fn test_obsolete_extras() {
|
|||
.succeeds()
|
||||
.stdout_is("==> standard input <==\n1\02\03\04\05\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_files() {
|
||||
new_ucmd!()
|
||||
.args(&["emptyfile.txt", "emptyfile.txt"])
|
||||
.succeeds()
|
||||
.stdout_is("==> emptyfile.txt <==\n\n==> emptyfile.txt <==\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_files_with_stdin() {
|
||||
new_ucmd!()
|
||||
.args(&["emptyfile.txt", "-", "emptyfile.txt"])
|
||||
.pipe_in("hello\n")
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"==> emptyfile.txt <==
|
||||
|
||||
==> standard input <==
|
||||
hello
|
||||
|
||||
==> emptyfile.txt <==
|
||||
",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::common::util::*;
|
|||
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
|
||||
// stderr: "whoami: cannot find name for user ID 1001"
|
||||
// Maybe: "adduser --uid 1001 username" can put things right?
|
||||
// stderr = id: error: Could not find uid 1001: No such id: 1001
|
||||
// stderr = id: Could not find uid 1001: No such id: 1001
|
||||
fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool {
|
||||
if !result.succeeded() {
|
||||
println!("result.stdout = {}", result.stdout_str());
|
||||
|
|
|
@ -301,7 +301,7 @@ fn test_install_target_new_file_with_group() {
|
|||
.arg(format!("{}/{}", dir, file))
|
||||
.run();
|
||||
|
||||
if is_ci() && result.stderr_str().contains("error: no such group:") {
|
||||
if is_ci() && result.stderr_str().contains("no such group:") {
|
||||
// In the CI, some server are failing to return the group.
|
||||
// As seems to be a configuration issue, ignoring it
|
||||
return;
|
||||
|
@ -328,7 +328,7 @@ fn test_install_target_new_file_with_owner() {
|
|||
.arg(format!("{}/{}", dir, file))
|
||||
.run();
|
||||
|
||||
if is_ci() && result.stderr_str().contains("error: no such user:") {
|
||||
if is_ci() && result.stderr_str().contains("no such user:") {
|
||||
// In the CI, some server are failing to return the user id.
|
||||
// As seems to be a configuration issue, ignoring it
|
||||
return;
|
||||
|
|
|
@ -148,7 +148,7 @@ fn multitab_character() {
|
|||
.arg("-t")
|
||||
.arg("э")
|
||||
.fails()
|
||||
.stderr_is("join: error: multi-character tab э");
|
||||
.stderr_is("join: multi-character tab э");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -211,7 +211,7 @@ fn empty_format() {
|
|||
.arg("-o")
|
||||
.arg("")
|
||||
.fails()
|
||||
.stderr_is("join: error: invalid file number in field spec: ''");
|
||||
.stderr_is("join: invalid file number in field spec: ''");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -23,7 +23,7 @@ fn test_link_no_circular() {
|
|||
|
||||
ucmd.args(&[link, link])
|
||||
.fails()
|
||||
.stderr_is("link: error: No such file or directory (os error 2)\n");
|
||||
.stderr_is("link: No such file or directory (os error 2)\n");
|
||||
assert!(!at.file_exists(link));
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ fn test_link_nonexistent_file() {
|
|||
|
||||
ucmd.args(&[file, link])
|
||||
.fails()
|
||||
.stderr_is("link: error: No such file or directory (os error 2)\n");
|
||||
.stderr_is("link: No such file or directory (os error 2)\n");
|
||||
assert!(!at.file_exists(file));
|
||||
assert!(!at.file_exists(link));
|
||||
}
|
||||
|
|
|
@ -409,7 +409,7 @@ fn test_symlink_missing_destination() {
|
|||
at.touch(file);
|
||||
|
||||
ucmd.args(&["-s", "-T", file]).fails().stderr_is(format!(
|
||||
"ln: error: missing destination file operand after '{}'",
|
||||
"ln: missing destination file operand after '{}'",
|
||||
file
|
||||
));
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ fn test_normal() {
|
|||
for (key, value) in env::vars() {
|
||||
println!("{}: {}", key, value);
|
||||
}
|
||||
if (is_ci() || uucore::os::is_wsl_1()) && result.stderr_str().contains("error: no login name") {
|
||||
if (is_ci() || uucore::os::is_wsl_1()) && result.stderr_str().contains("no login name") {
|
||||
// ToDO: investigate WSL failure
|
||||
// In the CI, some server are failing to return logname.
|
||||
// As seems to be a configuration issue, ignoring it
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::common::util::*;
|
|||
extern crate regex;
|
||||
use self::regex::Regex;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
@ -18,9 +19,7 @@ use std::path::PathBuf;
|
|||
#[cfg(not(windows))]
|
||||
use std::sync::Mutex;
|
||||
#[cfg(not(windows))]
|
||||
extern crate tempdir;
|
||||
#[cfg(not(windows))]
|
||||
use self::tempdir::TempDir;
|
||||
extern crate tempfile;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
lazy_static! {
|
||||
|
@ -166,7 +165,7 @@ fn test_ls_width() {
|
|||
.ucmd()
|
||||
.args(&option.split(" ").collect::<Vec<_>>())
|
||||
.fails()
|
||||
.stderr_only("ls: error: invalid line width: ‘1a’");
|
||||
.stderr_only("ls: invalid line width: ‘1a’");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,6 +307,50 @@ fn test_ls_long() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_long_total_size() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch(&at.plus_as_string("test-long"));
|
||||
at.append("test-long", "1");
|
||||
at.touch(&at.plus_as_string("test-long2"));
|
||||
at.append("test-long2", "2");
|
||||
|
||||
let expected_prints: HashMap<_, _> = if cfg!(unix) {
|
||||
[
|
||||
("long_vanilla", "total 8"),
|
||||
("long_human_readable", "total 8.0K"),
|
||||
("long_si", "total 8.2k"),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect()
|
||||
} else {
|
||||
[
|
||||
("long_vanilla", "total 2"),
|
||||
("long_human_readable", "total 2"),
|
||||
("long_si", "total 2"),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect()
|
||||
};
|
||||
|
||||
for arg in &["-l", "--long", "--format=long", "--format=verbose"] {
|
||||
let result = scene.ucmd().arg(arg).succeeds();
|
||||
result.stdout_contains(expected_prints["long_vanilla"]);
|
||||
|
||||
for arg2 in &["-h", "--human-readable", "--si"] {
|
||||
let result = scene.ucmd().arg(arg).arg(arg2).succeeds();
|
||||
result.stdout_contains(if *arg2 == "--si" {
|
||||
expected_prints["long_si"]
|
||||
} else {
|
||||
expected_prints["long_human_readable"]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_long_formats() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
@ -640,7 +683,7 @@ fn test_ls_styles() {
|
|||
at.touch("test");
|
||||
|
||||
let re_full = Regex::new(
|
||||
r"[a-z-]* \d* \w* \w* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d* \+\d{4} test\n",
|
||||
r"[a-z-]* \d* \w* \w* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d* (\+|\-)\d{4} test\n",
|
||||
)
|
||||
.unwrap();
|
||||
let re_long =
|
||||
|
@ -830,7 +873,7 @@ fn test_ls_files_dirs() {
|
|||
.ucmd()
|
||||
.arg("doesntexist")
|
||||
.fails()
|
||||
.stderr_contains(&"error: 'doesntexist': No such file or directory");
|
||||
.stderr_contains(&"'doesntexist': No such file or directory");
|
||||
|
||||
// One exists, the other doesn't
|
||||
scene
|
||||
|
@ -838,7 +881,7 @@ fn test_ls_files_dirs() {
|
|||
.arg("a")
|
||||
.arg("doesntexist")
|
||||
.fails()
|
||||
.stderr_contains(&"error: 'doesntexist': No such file or directory")
|
||||
.stderr_contains(&"'doesntexist': No such file or directory")
|
||||
.stdout_contains(&"a:");
|
||||
}
|
||||
|
||||
|
@ -1042,7 +1085,7 @@ fn test_ls_indicator_style() {
|
|||
{
|
||||
use self::unix_socket::UnixListener;
|
||||
|
||||
let dir = TempDir::new("unix_socket").expect("failed to create dir");
|
||||
let dir = tempfile::Builder::new().prefix("unix_socket").tempdir().expect("failed to create dir");
|
||||
let socket_path = dir.path().join("sock");
|
||||
let _listener = UnixListener::bind(&socket_path).expect("failed to create socket");
|
||||
|
||||
|
@ -1921,3 +1964,48 @@ fn test_ls_sort_extension() {
|
|||
expected,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_path() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file1 = "file1";
|
||||
let file2 = "file2";
|
||||
let dir = "dir";
|
||||
let path = &format!("{}/{}", dir, file2);
|
||||
|
||||
at.mkdir(dir);
|
||||
at.touch(file1);
|
||||
at.touch(path);
|
||||
|
||||
let expected_stdout = &format!("{}\n", path);
|
||||
scene.ucmd().arg(path).run().stdout_is(expected_stdout);
|
||||
|
||||
let expected_stdout = &format!("./{}\n", path);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(format!("./{}", path))
|
||||
.run()
|
||||
.stdout_is(expected_stdout);
|
||||
|
||||
let abs_path = format!("{}/{}", at.as_string(), path);
|
||||
let expected_stdout = if cfg!(windows) {
|
||||
format!("\'{}\'\n", abs_path)
|
||||
} else {
|
||||
format!("{}\n", abs_path)
|
||||
};
|
||||
scene.ucmd().arg(&abs_path).run().stdout_is(expected_stdout);
|
||||
|
||||
let expected_stdout = if cfg!(windows) {
|
||||
format!("{} {}\n", path, file1)
|
||||
} else {
|
||||
format!("{}\n{}\n", path, file1)
|
||||
};
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(file1)
|
||||
.arg(path)
|
||||
.run()
|
||||
.stdout_is(expected_stdout);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@ use crate::common::util::*;
|
|||
|
||||
#[test]
|
||||
fn test_create_fifo_missing_operand() {
|
||||
new_ucmd!()
|
||||
.fails()
|
||||
.stderr_is("mkfifo: error: missing operand");
|
||||
new_ucmd!().fails().stderr_is("mkfifo: missing operand");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -43,5 +41,5 @@ fn test_create_one_fifo_already_exists() {
|
|||
.arg("abcdef")
|
||||
.arg("abcdef")
|
||||
.fails()
|
||||
.stderr_is("mkfifo: error: cannot create fifo 'abcdef': File exists");
|
||||
.stderr_is("mkfifo: cannot create fifo 'abcdef': File exists");
|
||||
}
|
||||
|
|
|
@ -1 +1,124 @@
|
|||
// ToDO: add tests
|
||||
use crate::common::util::*;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_mknod_help() {
|
||||
new_ucmd!()
|
||||
.arg("--help")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_contains("USAGE:");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_version() {
|
||||
assert!(new_ucmd!()
|
||||
.arg("--version")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_str()
|
||||
.starts_with("mknod"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_fifo_default_writable() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().arg("test_file").arg("p").succeeds();
|
||||
assert!(ts.fixtures.is_fifo("test_file"));
|
||||
assert!(!ts.fixtures.metadata("test_file").permissions().readonly());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_fifo_mnemonic_usage() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().arg("test_file").arg("pipe").succeeds();
|
||||
assert!(ts.fixtures.is_fifo("test_file"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_fifo_read_only() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd()
|
||||
.arg("-m")
|
||||
.arg("a=r")
|
||||
.arg("test_file")
|
||||
.arg("p")
|
||||
.succeeds();
|
||||
assert!(ts.fixtures.is_fifo("test_file"));
|
||||
assert!(ts.fixtures.metadata("test_file").permissions().readonly());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_fifo_invalid_extra_operand() {
|
||||
new_ucmd!()
|
||||
.arg("test_file")
|
||||
.arg("p")
|
||||
.arg("1")
|
||||
.arg("2")
|
||||
.fails()
|
||||
.stderr_contains(&"Fifos do not have major and minor device numbers");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_character_device_requires_major_and_minor() {
|
||||
new_ucmd!()
|
||||
.arg("test_file")
|
||||
.arg("c")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stderr_contains(&"Special files require major and minor device numbers.");
|
||||
new_ucmd!()
|
||||
.arg("test_file")
|
||||
.arg("c")
|
||||
.arg("1")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stderr_contains(&"Special files require major and minor device numbers.");
|
||||
new_ucmd!()
|
||||
.arg("test_file")
|
||||
.arg("c")
|
||||
.arg("1")
|
||||
.arg("c")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stderr_contains(&"Invalid value for '<MINOR>'");
|
||||
new_ucmd!()
|
||||
.arg("test_file")
|
||||
.arg("c")
|
||||
.arg("c")
|
||||
.arg("1")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stderr_contains(&"Invalid value for '<MAJOR>'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_invalid_arg() {
|
||||
new_ucmd!()
|
||||
.arg("--foo")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.no_stdout()
|
||||
.stderr_contains(&"Found argument '--foo' which wasn't expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_mknod_invalid_mode() {
|
||||
new_ucmd!()
|
||||
.arg("--mode")
|
||||
.arg("rw")
|
||||
.arg("test_file")
|
||||
.arg("p")
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.status_code(1)
|
||||
.stderr_contains(&"invalid mode");
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ fn test_mktemp_mktemp_t() {
|
|||
.arg(TEST_TEMPLATE8)
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("error: suffix cannot contain any path separators");
|
||||
.stderr_contains("suffix cannot contain any path separators");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -251,6 +251,40 @@ fn test_mv_simple_backup() {
|
|||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_simple_backup_with_file_extension() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_simple_backup_file_a.txt";
|
||||
let file_b = "test_mv_simple_backup_file_b.txt";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
ucmd.arg("-b")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_arg_backup_arg_first() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_simple_backup_file_a";
|
||||
let file_b = "test_mv_simple_backup_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
ucmd.arg("--backup").arg(file_a).arg(file_b).succeeds();
|
||||
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_custom_backup_suffix() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -293,7 +327,7 @@ fn test_mv_custom_backup_suffix_via_env() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_numbering() {
|
||||
fn test_mv_backup_numbered_with_t() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_backup_numbering_file_a";
|
||||
let file_b = "test_mv_backup_numbering_file_b";
|
||||
|
@ -311,6 +345,25 @@ fn test_mv_backup_numbering() {
|
|||
assert!(at.file_exists(&format!("{}.~1~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_numbered() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_backup_numbering_file_a";
|
||||
let file_b = "test_mv_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
ucmd.arg("--backup=numbered")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}.~1~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_existing() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -330,6 +383,67 @@ fn test_mv_backup_existing() {
|
|||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_nil() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_backup_numbering_file_a";
|
||||
let file_b = "test_mv_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
ucmd.arg("--backup=nil")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_numbered_if_existing_backup_existing() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_backup_numbering_file_a";
|
||||
let file_b = "test_mv_backup_numbering_file_b";
|
||||
let file_b_backup = "test_mv_backup_numbering_file_b.~1~";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
at.touch(file_b_backup);
|
||||
ucmd.arg("--backup=existing")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(file_b_backup));
|
||||
assert!(at.file_exists(&*format!("{}.~2~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_numbered_if_existing_backup_nil() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_backup_numbering_file_a";
|
||||
let file_b = "test_mv_backup_numbering_file_b";
|
||||
let file_b_backup = "test_mv_backup_numbering_file_b.~1~";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
at.touch(file_b_backup);
|
||||
ucmd.arg("--backup=nil")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(file_b_backup));
|
||||
assert!(at.file_exists(&*format!("{}.~2~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_simple() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -349,6 +463,25 @@ fn test_mv_backup_simple() {
|
|||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_never() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_backup_numbering_file_a";
|
||||
let file_b = "test_mv_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
ucmd.arg("--backup=never")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_none() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -369,17 +502,14 @@ fn test_mv_backup_none() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_existing_backup() {
|
||||
fn test_mv_backup_off() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_existing_backup_file_a";
|
||||
let file_b = "test_mv_existing_backup_file_b";
|
||||
let file_b_backup = "test_mv_existing_backup_file_b.~1~";
|
||||
let resulting_backup = "test_mv_existing_backup_file_b.~2~";
|
||||
let file_a = "test_mv_backup_numbering_file_a";
|
||||
let file_b = "test_mv_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
at.touch(file_b_backup);
|
||||
ucmd.arg("--backup=nil")
|
||||
ucmd.arg("--backup=off")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
|
@ -387,8 +517,19 @@ fn test_mv_existing_backup() {
|
|||
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(file_b_backup));
|
||||
assert!(at.file_exists(resulting_backup));
|
||||
assert!(!at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_backup_no_clobber_conflicting_options() {
|
||||
let (_, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--backup")
|
||||
.arg("--no-clobber")
|
||||
.arg("file1")
|
||||
.arg("file2")
|
||||
.fails()
|
||||
.stderr_is("mv: options --backup and --no-clobber are mutually exclusive\nTry 'mv --help' for more information.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -472,7 +613,7 @@ fn test_mv_overwrite_nonempty_dir() {
|
|||
at.touch(dummy);
|
||||
// Not same error as GNU; the error message is a rust builtin
|
||||
// TODO: test (and implement) correct error message (or at least decide whether to do so)
|
||||
// Current: "mv: error: couldn't rename path (Directory not empty; from=a; to=b)"
|
||||
// Current: "mv: couldn't rename path (Directory not empty; from=a; to=b)"
|
||||
// GNU: "mv: cannot move ‘a’ to ‘b’: Directory not empty"
|
||||
|
||||
// Verbose output for the move should not be shown on failure
|
||||
|
@ -539,7 +680,7 @@ fn test_mv_errors() {
|
|||
.arg(dir)
|
||||
.fails()
|
||||
.stderr_is(format!(
|
||||
"mv: error: cannot overwrite directory ‘{}’ with non-directory\n",
|
||||
"mv: cannot overwrite directory ‘{}’ with non-directory\n",
|
||||
dir
|
||||
));
|
||||
|
||||
|
@ -587,6 +728,24 @@ fn test_mv_verbose() {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_permission_error() {
|
||||
let scene = TestScenario::new("mkdir");
|
||||
let folder1 = "bar";
|
||||
let folder2 = "foo";
|
||||
let folder_to_move = "bar/foo";
|
||||
scene.ucmd().arg("-m444").arg(folder1).succeeds();
|
||||
scene.ucmd().arg("-m777").arg(folder2).succeeds();
|
||||
|
||||
scene
|
||||
.cmd_keepenv(util_name!())
|
||||
.arg(folder2)
|
||||
.arg(folder_to_move)
|
||||
.run()
|
||||
.stderr_str()
|
||||
.ends_with("Permission denied");
|
||||
}
|
||||
|
||||
// Todo:
|
||||
|
||||
// $ at.touch a b
|
||||
|
|
|
@ -25,7 +25,7 @@ fn test_adjustment_with_no_command_should_error() {
|
|||
new_ucmd!()
|
||||
.args(&["-n", "19"])
|
||||
.run()
|
||||
.stderr_is("nice: error: A command must be given with an adjustment.\nTry \"nice --help\" for more information.\n");
|
||||
.stderr_is("nice: A command must be given with an adjustment.\nTry \"nice --help\" for more information.\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -281,6 +281,7 @@ fn test_leading_whitespace_in_free_argument_should_imply_padding() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_should_calculate_implicit_padding_per_free_argument() {
|
||||
new_ucmd!()
|
||||
.args(&["--from=auto", " 1Ki", " 2K"])
|
||||
|
|
|
@ -20,42 +20,37 @@ fn test_long_format() {
|
|||
let ulogin = "root";
|
||||
let pw: Passwd = Passwd::locate(ulogin).unwrap();
|
||||
let real_name = pw.user_info().replace("&", &pw.name().capitalize());
|
||||
new_ucmd!().arg("-l").arg(ulogin).run().stdout_is(format!(
|
||||
"Login name: {:<28}In real life: {}\nDirectory: {:<29}Shell: {}\n\n",
|
||||
ulogin,
|
||||
real_name,
|
||||
pw.user_dir(),
|
||||
pw.user_shell()
|
||||
));
|
||||
new_ucmd!()
|
||||
.arg("-l")
|
||||
.arg(ulogin)
|
||||
.succeeds()
|
||||
.stdout_is(format!(
|
||||
"Login name: {:<28}In real life: {}\nDirectory: {:<29}Shell: {}\n\n",
|
||||
ulogin,
|
||||
real_name,
|
||||
pw.user_dir(),
|
||||
pw.user_shell()
|
||||
));
|
||||
|
||||
new_ucmd!().arg("-lb").arg(ulogin).run().stdout_is(format!(
|
||||
"Login name: {:<28}In real life: {1}\n\n",
|
||||
ulogin, real_name
|
||||
));
|
||||
new_ucmd!()
|
||||
.arg("-lb")
|
||||
.arg(ulogin)
|
||||
.succeeds()
|
||||
.stdout_is(format!(
|
||||
"Login name: {:<28}In real life: {1}\n\n",
|
||||
ulogin, real_name
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_long_format_multiple_users() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let args = ["-l", "root", "root", "root"];
|
||||
|
||||
let expected = scene
|
||||
.cmd_keepenv(util_name!())
|
||||
.env("LANGUAGE", "C")
|
||||
.arg("-l")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
.succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-l")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_is(expected.stdout_str());
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -64,46 +59,53 @@ fn test_long_format_wo_user() {
|
|||
new_ucmd!().arg("-l").fails().code_is(1);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_short_format_i() {
|
||||
// allow whitespace variation
|
||||
// * minor whitespace differences occur between platform built-in outputs; specifically, the number of trailing TABs may be variant
|
||||
let args = ["-i"];
|
||||
let actual = TestScenario::new(util_name!())
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
let actual = new_ucmd!().args(&args).succeeds().stdout_move_str();
|
||||
let expect = expected_result(&args);
|
||||
let v_actual: Vec<&str> = actual.split_whitespace().collect();
|
||||
let v_expect: Vec<&str> = expect.split_whitespace().collect();
|
||||
assert_eq!(v_actual, v_expect);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_short_format_q() {
|
||||
// allow whitespace variation
|
||||
// * minor whitespace differences occur between platform built-in outputs; specifically, the number of trailing TABs may be variant
|
||||
let args = ["-q"];
|
||||
let actual = TestScenario::new(util_name!())
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
let actual = new_ucmd!().args(&args).succeeds().stdout_move_str();
|
||||
let expect = expected_result(&args);
|
||||
let v_actual: Vec<&str> = actual.split_whitespace().collect();
|
||||
let v_expect: Vec<&str> = expect.split_whitespace().collect();
|
||||
assert_eq!(v_actual, v_expect);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_no_flag() {
|
||||
let actual = new_ucmd!().succeeds().stdout_move_str();
|
||||
let expect = expected_result(&[]);
|
||||
let v_actual: Vec<&str> = actual.split_whitespace().collect();
|
||||
let v_expect: Vec<&str> = expect.split_whitespace().collect();
|
||||
assert_eq!(v_actual, v_expect);
|
||||
}
|
||||
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
fn expected_result(args: &[&str]) -> String {
|
||||
TestScenario::new(util_name!())
|
||||
.cmd_keepenv(util_name!())
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(target_vendor = "apple")]
|
||||
let util_name = format!("g{}", util_name!());
|
||||
|
||||
TestScenario::new(&util_name)
|
||||
.cmd_keepenv(util_name)
|
||||
.env("LANGUAGE", "C")
|
||||
.args(args)
|
||||
.run()
|
||||
.succeeds()
|
||||
.stdout_move_str()
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ fn test_relpath_no_from_with_d() {
|
|||
at.mkdir_all(to);
|
||||
|
||||
// d is part of subpath -> expect relative path
|
||||
let mut result_stdout = scene
|
||||
let _result_stdout = scene
|
||||
.ucmd()
|
||||
.arg(to)
|
||||
.arg(&format!("-d{}", pwd))
|
||||
|
@ -163,10 +163,10 @@ fn test_relpath_no_from_with_d() {
|
|||
.stdout_move_str();
|
||||
// relax rules for windows test environment
|
||||
#[cfg(not(windows))]
|
||||
assert!(Path::new(&result_stdout).is_relative());
|
||||
assert!(Path::new(&_result_stdout).is_relative());
|
||||
|
||||
// d is not part of subpath -> expect absolut path
|
||||
result_stdout = scene
|
||||
let result_stdout = scene
|
||||
.ucmd()
|
||||
.arg(to)
|
||||
.arg("-dnon_existing")
|
||||
|
|
|
@ -258,7 +258,7 @@ fn test_rm_no_operand() {
|
|||
let mut ucmd = new_ucmd!();
|
||||
|
||||
ucmd.fails()
|
||||
.stderr_is("rm: error: missing an argument\nrm: error: for help, try 'rm --help'\n");
|
||||
.stderr_is("rm: missing an argument\nrm: for help, try 'rm --help'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -39,7 +39,7 @@ fn test_rmdir_nonempty_directory_no_parents() {
|
|||
assert!(at.file_exists(file));
|
||||
|
||||
ucmd.arg(dir).fails().stderr_is(
|
||||
"rmdir: error: failed to remove 'test_rmdir_nonempty_no_parents': Directory not \
|
||||
"rmdir: failed to remove 'test_rmdir_nonempty_no_parents': Directory not \
|
||||
empty\n",
|
||||
);
|
||||
|
||||
|
@ -59,9 +59,9 @@ fn test_rmdir_nonempty_directory_with_parents() {
|
|||
assert!(at.file_exists(file));
|
||||
|
||||
ucmd.arg("-p").arg(dir).fails().stderr_is(
|
||||
"rmdir: error: failed to remove 'test_rmdir_nonempty/with/parents': Directory not \
|
||||
empty\nrmdir: error: failed to remove 'test_rmdir_nonempty/with': Directory not \
|
||||
empty\nrmdir: error: failed to remove 'test_rmdir_nonempty': Directory not \
|
||||
"rmdir: failed to remove 'test_rmdir_nonempty/with/parents': Directory not \
|
||||
empty\nrmdir: failed to remove 'test_rmdir_nonempty/with': Directory not \
|
||||
empty\nrmdir: failed to remove 'test_rmdir_nonempty': Directory not \
|
||||
empty\n",
|
||||
);
|
||||
|
||||
|
|
|
@ -1,48 +1,79 @@
|
|||
use crate::common::util::*;
|
||||
|
||||
fn test_helper(file_name: &str, args: &str) {
|
||||
new_ucmd!()
|
||||
.arg(format!("{}.txt", file_name))
|
||||
.args(&args.split(' ').collect::<Vec<&str>>())
|
||||
.succeeds()
|
||||
.stdout_is_fixture(format!("{}.expected", file_name));
|
||||
fn test_helper(file_name: &str, possible_args: &[&str]) {
|
||||
for args in possible_args {
|
||||
new_ucmd!()
|
||||
.arg(format!("{}.txt", file_name))
|
||||
.args(&args.split(' ').collect::<Vec<&str>>())
|
||||
.succeeds()
|
||||
.stdout_is_fixture(format!("{}.expected", file_name));
|
||||
|
||||
new_ucmd!()
|
||||
.arg(format!("{}.txt", file_name))
|
||||
.arg("--debug")
|
||||
.args(&args.split(' ').collect::<Vec<&str>>())
|
||||
.succeeds()
|
||||
.stdout_is_fixture(format!("{}.expected.debug", file_name));
|
||||
new_ucmd!()
|
||||
.arg(format!("{}.txt", file_name))
|
||||
.arg("--debug")
|
||||
.args(&args.split(' ').collect::<Vec<&str>>())
|
||||
.succeeds()
|
||||
.stdout_is_fixture(format!("{}.expected.debug", file_name));
|
||||
}
|
||||
}
|
||||
|
||||
// FYI, the initialization size of our Line struct is 96 bytes.
|
||||
//
|
||||
// At very small buffer sizes, with that overhead we are certainly going
|
||||
// to overrun our buffer way, way, way too quickly because of these excess
|
||||
// bytes for the struct.
|
||||
//
|
||||
// For instance, seq 0..20000 > ...text = 108894 bytes
|
||||
// But overhead is 1920000 + 108894 = 2028894 bytes
|
||||
//
|
||||
// Or kjvbible-random.txt = 4332506 bytes, but minimum size of its
|
||||
// 99817 lines in memory * 96 bytes = 9582432 bytes
|
||||
//
|
||||
// Here, we test 108894 bytes with a 50K buffer
|
||||
//
|
||||
#[test]
|
||||
fn test_larger_than_specified_segment() {
|
||||
fn test_buffer_sizes() {
|
||||
let buffer_sizes = [
|
||||
"0", "50K", "50k", "1M", "100M", "1000G", "10T", "500E", "1Y",
|
||||
];
|
||||
for buffer_size in &buffer_sizes {
|
||||
new_ucmd!()
|
||||
.arg("-n")
|
||||
.arg("-S")
|
||||
.arg(buffer_size)
|
||||
.arg("ext_sort.txt")
|
||||
.succeeds()
|
||||
.stdout_is_fixture("ext_sort.expected");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_buffer_size() {
|
||||
let buffer_sizes = ["asd", "100f"];
|
||||
for invalid_buffer_size in &buffer_sizes {
|
||||
new_ucmd!()
|
||||
.arg("-S")
|
||||
.arg(invalid_buffer_size)
|
||||
.fails()
|
||||
.stderr_only(format!(
|
||||
"sort: failed to parse buffer size `{}`: invalid digit found in string",
|
||||
invalid_buffer_size
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ext_sort_stable() {
|
||||
new_ucmd!()
|
||||
.arg("-n")
|
||||
.arg("--stable")
|
||||
.arg("-S")
|
||||
.arg("50K")
|
||||
.arg("ext_sort.txt")
|
||||
.arg("0M")
|
||||
.arg("ext_stable.txt")
|
||||
.succeeds()
|
||||
.stdout_is_fixture(format!("{}", "ext_sort.expected"));
|
||||
.stdout_only_fixture("ext_stable.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extsort_zero_terminated() {
|
||||
new_ucmd!()
|
||||
.arg("-z")
|
||||
.arg("-S")
|
||||
.arg("10K")
|
||||
.arg("zero-terminated.txt")
|
||||
.succeeds()
|
||||
.stdout_is_fixture("zero-terminated.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_months_whitespace() {
|
||||
test_helper("months-whitespace", "-M");
|
||||
test_helper("months-whitespace", &["-M", "--month-sort", "--sort=month"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -56,7 +87,10 @@ fn test_version_empty_lines() {
|
|||
|
||||
#[test]
|
||||
fn test_human_numeric_whitespace() {
|
||||
test_helper("human-numeric-whitespace", "-h");
|
||||
test_helper(
|
||||
"human-numeric-whitespace",
|
||||
&["-h", "--human-numeric-sort", "--sort=human-numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
// This tests where serde often fails when reading back JSON
|
||||
|
@ -73,12 +107,18 @@ fn test_extsort_as64_bailout() {
|
|||
|
||||
#[test]
|
||||
fn test_multiple_decimals_general() {
|
||||
test_helper("multiple_decimals_general", "-g")
|
||||
test_helper(
|
||||
"multiple_decimals_general",
|
||||
&["-g", "--general-numeric-sort", "--sort=general-numeric"],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_decimals_numeric() {
|
||||
test_helper("multiple_decimals_numeric", "-n")
|
||||
test_helper(
|
||||
"multiple_decimals_numeric",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -88,7 +128,7 @@ fn test_check_zero_terminated_failure() {
|
|||
.arg("-c")
|
||||
.arg("zero-terminated.txt")
|
||||
.fails()
|
||||
.stdout_is("sort: disorder in line 0\n");
|
||||
.stdout_is("sort: zero-terminated.txt:2: disorder: ../../fixtures/du\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -157,72 +197,93 @@ fn test_random_shuffle_contains_two_runs_not_the_same() {
|
|||
|
||||
#[test]
|
||||
fn test_numeric_floats_and_ints() {
|
||||
test_helper("numeric_floats_and_ints", "-n");
|
||||
test_helper(
|
||||
"numeric_floats_and_ints",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_floats() {
|
||||
test_helper("numeric_floats", "-n");
|
||||
test_helper(
|
||||
"numeric_floats",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_floats_with_nan() {
|
||||
test_helper("numeric_floats_with_nan", "-n");
|
||||
test_helper(
|
||||
"numeric_floats_with_nan",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_unfixed_floats() {
|
||||
test_helper("numeric_unfixed_floats", "-n");
|
||||
test_helper(
|
||||
"numeric_unfixed_floats",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_fixed_floats() {
|
||||
test_helper("numeric_fixed_floats", "-n");
|
||||
test_helper(
|
||||
"numeric_fixed_floats",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_unsorted_ints() {
|
||||
test_helper("numeric_unsorted_ints", "-n");
|
||||
test_helper(
|
||||
"numeric_unsorted_ints",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_human_block_sizes() {
|
||||
test_helper("human_block_sizes", "-h");
|
||||
test_helper(
|
||||
"human_block_sizes",
|
||||
&["-h", "--human-numeric-sort", "--sort=human-numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_month_default() {
|
||||
test_helper("month_default", "-M");
|
||||
test_helper("month_default", &["-M", "--month-sort", "--sort=month"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_month_stable() {
|
||||
test_helper("month_stable", "-Ms");
|
||||
test_helper("month_stable", &["-Ms"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_unsorted_ints() {
|
||||
test_helper("default_unsorted_ints", "");
|
||||
test_helper("default_unsorted_ints", &[""]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_unique_ints() {
|
||||
test_helper("numeric_unsorted_ints_unique", "-nu");
|
||||
test_helper("numeric_unsorted_ints_unique", &["-nu"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version() {
|
||||
test_helper("version", "-V");
|
||||
test_helper("version", &["-V"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ignore_case() {
|
||||
test_helper("ignore_case", "-f");
|
||||
test_helper("ignore_case", &["-f"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dictionary_order() {
|
||||
test_helper("dictionary_order", "-d");
|
||||
test_helper("dictionary_order", &["-d"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -249,47 +310,53 @@ fn test_non_printing_chars() {
|
|||
|
||||
#[test]
|
||||
fn test_exponents_positive_general_fixed() {
|
||||
test_helper("exponents_general", "-g");
|
||||
test_helper("exponents_general", &["-g"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exponents_positive_numeric() {
|
||||
test_helper("exponents-positive-numeric", "-n");
|
||||
test_helper(
|
||||
"exponents-positive-numeric",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_months_dedup() {
|
||||
test_helper("months-dedup", "-Mu");
|
||||
test_helper("months-dedup", &["-Mu"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mixed_floats_ints_chars_numeric() {
|
||||
test_helper("mixed_floats_ints_chars_numeric", "-n");
|
||||
test_helper(
|
||||
"mixed_floats_ints_chars_numeric",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mixed_floats_ints_chars_numeric_unique() {
|
||||
test_helper("mixed_floats_ints_chars_numeric_unique", "-nu");
|
||||
test_helper("mixed_floats_ints_chars_numeric_unique", &["-nu"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_words_unique() {
|
||||
test_helper("words_unique", "-u");
|
||||
test_helper("words_unique", &["-u"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_unique() {
|
||||
test_helper("numeric_unique", "-nu");
|
||||
test_helper("numeric_unique", &["-nu"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mixed_floats_ints_chars_numeric_reverse() {
|
||||
test_helper("mixed_floats_ints_chars_numeric_unique_reverse", "-nur");
|
||||
test_helper("mixed_floats_ints_chars_numeric_unique_reverse", &["-nur"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mixed_floats_ints_chars_numeric_stable() {
|
||||
test_helper("mixed_floats_ints_chars_numeric_stable", "-ns");
|
||||
test_helper("mixed_floats_ints_chars_numeric_stable", &["-ns"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -318,12 +385,15 @@ fn test_numeric_floats2() {
|
|||
|
||||
#[test]
|
||||
fn test_numeric_floats_with_nan2() {
|
||||
test_helper("numeric-floats-with-nan2", "-n");
|
||||
test_helper(
|
||||
"numeric-floats-with-nan2",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_human_block_sizes2() {
|
||||
for human_numeric_sort_param in vec!["-h", "--human-numeric-sort"] {
|
||||
for human_numeric_sort_param in &["-h", "--human-numeric-sort", "--sort=human-numeric"] {
|
||||
let input = "8981K\n909991M\n-8T\n21G\n0.8M";
|
||||
new_ucmd!()
|
||||
.arg(human_numeric_sort_param)
|
||||
|
@ -335,7 +405,7 @@ fn test_human_block_sizes2() {
|
|||
|
||||
#[test]
|
||||
fn test_month_default2() {
|
||||
for month_sort_param in vec!["-M", "--month-sort"] {
|
||||
for month_sort_param in &["-M", "--month-sort", "--sort=month"] {
|
||||
let input = "JAn\nMAY\n000may\nJun\nFeb";
|
||||
new_ucmd!()
|
||||
.arg(month_sort_param)
|
||||
|
@ -368,32 +438,32 @@ fn test_numeric_unique_ints2() {
|
|||
|
||||
#[test]
|
||||
fn test_keys_open_ended() {
|
||||
test_helper("keys_open_ended", "-k 2.3");
|
||||
test_helper("keys_open_ended", &["-k 2.3"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_closed_range() {
|
||||
test_helper("keys_closed_range", "-k 2.2,2.2");
|
||||
test_helper("keys_closed_range", &["-k 2.2,2.2"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_multiple_ranges() {
|
||||
test_helper("keys_multiple_ranges", "-k 2,2 -k 3,3");
|
||||
test_helper("keys_multiple_ranges", &["-k 2,2 -k 3,3"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_no_field_match() {
|
||||
test_helper("keys_no_field_match", "-k 4,4");
|
||||
test_helper("keys_no_field_match", &["-k 4,4"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_no_char_match() {
|
||||
test_helper("keys_no_char_match", "-k 1.2");
|
||||
test_helper("keys_no_char_match", &["-k 1.2"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_custom_separator() {
|
||||
test_helper("keys_custom_separator", "-k 2.2,2.2 -t x");
|
||||
test_helper("keys_custom_separator", &["-k 2.2,2.2 -t x"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -401,7 +471,7 @@ fn test_keys_invalid_field() {
|
|||
new_ucmd!()
|
||||
.args(&["-k", "1."])
|
||||
.fails()
|
||||
.stderr_only("sort: error: failed to parse character index for key `1.`: cannot parse integer from empty string");
|
||||
.stderr_only("sort: failed to parse character index for key `1.`: cannot parse integer from empty string");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -409,7 +479,7 @@ fn test_keys_invalid_field_option() {
|
|||
new_ucmd!()
|
||||
.args(&["-k", "1.1x"])
|
||||
.fails()
|
||||
.stderr_only("sort: error: invalid option for key: `x`");
|
||||
.stderr_only("sort: invalid option for key: `x`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -417,14 +487,15 @@ fn test_keys_invalid_field_zero() {
|
|||
new_ucmd!()
|
||||
.args(&["-k", "0.1"])
|
||||
.fails()
|
||||
.stderr_only("sort: error: field index was 0");
|
||||
.stderr_only("sort: field index was 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_invalid_char_zero() {
|
||||
new_ucmd!().args(&["-k", "1.0"]).fails().stderr_only(
|
||||
"sort: error: invalid character index 0 in `1.0` for the start position of a field",
|
||||
);
|
||||
new_ucmd!()
|
||||
.args(&["-k", "1.0"])
|
||||
.fails()
|
||||
.stderr_only("sort: invalid character index 0 in `1.0` for the start position of a field");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -505,7 +576,7 @@ aaaa
|
|||
|
||||
#[test]
|
||||
fn test_zero_terminated() {
|
||||
test_helper("zero-terminated", "-z");
|
||||
test_helper("zero-terminated", &["-z"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -544,6 +615,18 @@ fn test_merge_unique() {
|
|||
.stdout_only_fixture("merge_ints_interleaved.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_stable() {
|
||||
new_ucmd!()
|
||||
.arg("-m")
|
||||
.arg("--stable")
|
||||
.arg("-n")
|
||||
.arg("merge_stable_1.txt")
|
||||
.arg("merge_stable_2.txt")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("merge_stable.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_reversed() {
|
||||
new_ucmd!()
|
||||
|
@ -575,7 +658,7 @@ fn test_check() {
|
|||
.arg("-c")
|
||||
.arg("check_fail.txt")
|
||||
.fails()
|
||||
.stdout_is("sort: disorder in line 4\n");
|
||||
.stdout_is("sort: check_fail.txt:6: disorder: 5\n");
|
||||
|
||||
new_ucmd!()
|
||||
.arg("-c")
|
||||
|
|
|
@ -4,11 +4,15 @@ extern crate regex;
|
|||
use self::rand::{thread_rng, Rng};
|
||||
use self::regex::Regex;
|
||||
use crate::common::util::*;
|
||||
use rand::SeedableRng;
|
||||
#[cfg(not(windows))]
|
||||
use std::env;
|
||||
use std::fs::{read_dir, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::{
|
||||
fs::{read_dir, File},
|
||||
io::BufWriter,
|
||||
};
|
||||
|
||||
fn random_chars(n: usize) -> String {
|
||||
thread_rng()
|
||||
|
@ -58,7 +62,7 @@ impl Glob {
|
|||
files.sort();
|
||||
let mut data: Vec<u8> = vec![];
|
||||
for name in &files {
|
||||
data.extend(self.directory.read(name).into_bytes());
|
||||
data.extend(self.directory.read_bytes(name));
|
||||
}
|
||||
data
|
||||
}
|
||||
|
@ -81,20 +85,30 @@ impl RandomFile {
|
|||
}
|
||||
|
||||
fn add_bytes(&mut self, bytes: usize) {
|
||||
let chunk_size: usize = if bytes >= 1024 { 1024 } else { bytes };
|
||||
let mut n = bytes;
|
||||
while n > chunk_size {
|
||||
let _ = write!(self.inner, "{}", random_chars(chunk_size));
|
||||
n -= chunk_size;
|
||||
// Note that just writing random characters isn't enough to cover all
|
||||
// cases. We need truly random bytes.
|
||||
let mut writer = BufWriter::new(&self.inner);
|
||||
|
||||
// Seed the rng so as to avoid spurious test failures.
|
||||
let mut rng = rand::rngs::StdRng::seed_from_u64(123);
|
||||
let mut buffer = [0; 1024];
|
||||
let mut remaining_size = bytes;
|
||||
|
||||
while remaining_size > 0 {
|
||||
let to_write = std::cmp::min(remaining_size, buffer.len());
|
||||
let buf = &mut buffer[..to_write];
|
||||
rng.fill(buf);
|
||||
writer.write(buf).unwrap();
|
||||
|
||||
remaining_size -= to_write;
|
||||
}
|
||||
let _ = write!(self.inner, "{}", random_chars(n));
|
||||
}
|
||||
|
||||
/// Add n lines each of size `RandomFile::LINESIZE`
|
||||
fn add_lines(&mut self, lines: usize) {
|
||||
let mut n = lines;
|
||||
while n > 0 {
|
||||
let _ = writeln!(self.inner, "{}", random_chars(RandomFile::LINESIZE));
|
||||
writeln!(self.inner, "{}", random_chars(RandomFile::LINESIZE)).unwrap();
|
||||
n -= 1;
|
||||
}
|
||||
}
|
||||
|
@ -104,18 +118,18 @@ impl RandomFile {
|
|||
fn test_split_default() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "split_default";
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
|
||||
RandomFile::new(&at, name).add_lines(2000);
|
||||
ucmd.args(&[name]).succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
|
||||
assert_eq!(glob.count(), 2);
|
||||
assert_eq!(glob.collate(), at.read(name).into_bytes());
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_numeric_prefixed_chunks_by_bytes() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "split_num_prefixed_chunks_by_bytes";
|
||||
let glob = Glob::new(&at, ".", r"a\d\d$");
|
||||
RandomFile::new(&at, name).add_bytes(10000);
|
||||
ucmd.args(&[
|
||||
"-d", // --numeric-suffixes
|
||||
|
@ -123,52 +137,89 @@ fn test_split_numeric_prefixed_chunks_by_bytes() {
|
|||
"1000", name, "a",
|
||||
])
|
||||
.succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"a\d\d$");
|
||||
assert_eq!(glob.count(), 10);
|
||||
assert_eq!(glob.collate(), at.read(name).into_bytes());
|
||||
for filename in glob.collect() {
|
||||
assert_eq!(glob.directory.metadata(&filename).len(), 1000);
|
||||
}
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_str_prefixed_chunks_by_bytes() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "split_str_prefixed_chunks_by_bytes";
|
||||
let glob = Glob::new(&at, ".", r"b[[:alpha:]][[:alpha:]]$");
|
||||
RandomFile::new(&at, name).add_bytes(10000);
|
||||
// Important that this is less than 1024 since that's our internal buffer
|
||||
// size. Good to test that we don't overshoot.
|
||||
ucmd.args(&["-b", "1000", name, "b"]).succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"b[[:alpha:]][[:alpha:]]$");
|
||||
assert_eq!(glob.count(), 10);
|
||||
assert_eq!(glob.collate(), at.read(name).into_bytes());
|
||||
for filename in glob.collect() {
|
||||
assert_eq!(glob.directory.metadata(&filename).len(), 1000);
|
||||
}
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
// This is designed to test what happens when the desired part size is not a
|
||||
// multiple of the buffer size and we hopefully don't overshoot the desired part
|
||||
// size.
|
||||
#[test]
|
||||
fn test_split_bytes_prime_part_size() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "test_split_bytes_prime_part_size";
|
||||
RandomFile::new(&at, name).add_bytes(10000);
|
||||
// 1753 is prime and greater than the buffer size, 1024.
|
||||
ucmd.args(&["-b", "1753", name, "b"]).succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"b[[:alpha:]][[:alpha:]]$");
|
||||
assert_eq!(glob.count(), 6);
|
||||
let mut fns = glob.collect();
|
||||
// glob.collect() is not guaranteed to return in sorted order, so we sort.
|
||||
fns.sort();
|
||||
for i in 0..5 {
|
||||
assert_eq!(glob.directory.metadata(&fns[i]).len(), 1753);
|
||||
}
|
||||
assert_eq!(glob.directory.metadata(&fns[5]).len(), 1235);
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_num_prefixed_chunks_by_lines() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "split_num_prefixed_chunks_by_lines";
|
||||
let glob = Glob::new(&at, ".", r"c\d\d$");
|
||||
RandomFile::new(&at, name).add_lines(10000);
|
||||
ucmd.args(&["-d", "-l", "1000", name, "c"]).succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"c\d\d$");
|
||||
assert_eq!(glob.count(), 10);
|
||||
assert_eq!(glob.collate(), at.read(name).into_bytes());
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_str_prefixed_chunks_by_lines() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "split_str_prefixed_chunks_by_lines";
|
||||
let glob = Glob::new(&at, ".", r"d[[:alpha:]][[:alpha:]]$");
|
||||
RandomFile::new(&at, name).add_lines(10000);
|
||||
ucmd.args(&["-l", "1000", name, "d"]).succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"d[[:alpha:]][[:alpha:]]$");
|
||||
assert_eq!(glob.count(), 10);
|
||||
assert_eq!(glob.collate(), at.read(name).into_bytes());
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_additional_suffix() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "split_additional_suffix";
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]].txt$");
|
||||
RandomFile::new(&at, name).add_lines(2000);
|
||||
ucmd.args(&["--additional-suffix", ".txt", name]).succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]].txt$");
|
||||
assert_eq!(glob.count(), 2);
|
||||
assert_eq!(glob.collate(), at.read(name).into_bytes());
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
// note: the test_filter* tests below are unix-only
|
||||
|
@ -182,15 +233,16 @@ fn test_filter() {
|
|||
// like `test_split_default()` but run a command before writing
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "filtered";
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
|
||||
let n_lines = 3;
|
||||
RandomFile::new(&at, name).add_lines(n_lines);
|
||||
|
||||
// change all characters to 'i'
|
||||
ucmd.args(&["--filter=sed s/./i/g > $FILE", name])
|
||||
.succeeds();
|
||||
|
||||
// assert all characters are 'i' / no character is not 'i'
|
||||
// (assert that command succeded)
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
|
||||
assert!(
|
||||
glob.collate().iter().find(|&&c| {
|
||||
// is not i
|
||||
|
@ -209,7 +261,6 @@ fn test_filter_with_env_var_set() {
|
|||
// implemented like `test_split_default()` but run a command before writing
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "filtered";
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
|
||||
let n_lines = 3;
|
||||
RandomFile::new(&at, name).add_lines(n_lines);
|
||||
|
||||
|
@ -217,7 +268,9 @@ fn test_filter_with_env_var_set() {
|
|||
env::set_var("FILE", &env_var_value);
|
||||
ucmd.args(&[format!("--filter={}", "cat > $FILE").as_str(), name])
|
||||
.succeeds();
|
||||
assert_eq!(glob.collate(), at.read(name).into_bytes());
|
||||
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
assert!(env::var("FILE").unwrap_or("var was unset".to_owned()) == env_var_value);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,69 +5,6 @@ use crate::common::util::*;
|
|||
extern crate stat;
|
||||
pub use self::stat::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_fsext {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_access() {
|
||||
assert_eq!("drwxr-xr-x", pretty_access(S_IFDIR | 0o755));
|
||||
assert_eq!("-rw-r--r--", pretty_access(S_IFREG | 0o644));
|
||||
assert_eq!("srw-r-----", pretty_access(S_IFSOCK | 0o640));
|
||||
assert_eq!("lrw-r-xr-x", pretty_access(S_IFLNK | 0o655));
|
||||
assert_eq!("?rw-r-xr-x", pretty_access(0o655));
|
||||
|
||||
assert_eq!(
|
||||
"brwSr-xr-x",
|
||||
pretty_access(S_IFBLK | S_ISUID as mode_t | 0o655)
|
||||
);
|
||||
assert_eq!(
|
||||
"brwsr-xr-x",
|
||||
pretty_access(S_IFBLK | S_ISUID as mode_t | 0o755)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"prw---sr--",
|
||||
pretty_access(S_IFIFO | S_ISGID as mode_t | 0o614)
|
||||
);
|
||||
assert_eq!(
|
||||
"prw---Sr--",
|
||||
pretty_access(S_IFIFO | S_ISGID as mode_t | 0o604)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"c---r-xr-t",
|
||||
pretty_access(S_IFCHR | S_ISVTX as mode_t | 0o055)
|
||||
);
|
||||
assert_eq!(
|
||||
"c---r-xr-T",
|
||||
pretty_access(S_IFCHR | S_ISVTX as mode_t | 0o054)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_type() {
|
||||
assert_eq!("block special file", pretty_filetype(S_IFBLK, 0));
|
||||
assert_eq!("character special file", pretty_filetype(S_IFCHR, 0));
|
||||
assert_eq!("regular file", pretty_filetype(S_IFREG, 1));
|
||||
assert_eq!("regular empty file", pretty_filetype(S_IFREG, 0));
|
||||
assert_eq!("weird file", pretty_filetype(0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fs_type() {
|
||||
assert_eq!("ext2/ext3", pretty_fstype(0xEF53));
|
||||
assert_eq!("tmpfs", pretty_fstype(0x01021994));
|
||||
assert_eq!("nfs", pretty_fstype(0x6969));
|
||||
assert_eq!("btrfs", pretty_fstype(0x9123683e));
|
||||
assert_eq!("xfs", pretty_fstype(0x58465342));
|
||||
assert_eq!("zfs", pretty_fstype(0x2FC12FC1));
|
||||
assert_eq!("ntfs", pretty_fstype(0x5346544e));
|
||||
assert_eq!("fat", pretty_fstype(0x4006));
|
||||
assert_eq!("UNKNOWN (0x1234)", pretty_fstype(0x1234));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scanutil() {
|
||||
assert_eq!(Some((-5, 2)), "-5zxc".scan_num::<i32>());
|
||||
|
@ -159,10 +96,10 @@ fn test_invalid_option() {
|
|||
new_ucmd!().arg("-w").arg("-q").arg("/").fails();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
const NORMAL_FMTSTR: &'static str =
|
||||
"%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s %u %U %x %X %y %Y %z %Z"; // avoid "%w %W" (birth/creation) due to `stat` limitations and linux kernel & rust version capability variations
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
const DEV_FMTSTR: &'static str =
|
||||
"%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (%t/%T) %u %U %w %W %x %X %y %Y %z %Z";
|
||||
#[cfg(target_os = "linux")]
|
||||
|
@ -188,8 +125,8 @@ fn test_fs_format() {
|
|||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_terse_normal_format() {
|
||||
// note: contains birth/creation date which increases test fragility
|
||||
// * results may vary due to built-in `stat` limitations as well as linux kernel and rust version capability variations
|
||||
|
@ -198,9 +135,16 @@ fn test_terse_normal_format() {
|
|||
let expect = expected_result(&args);
|
||||
println!("actual: {:?}", actual);
|
||||
println!("expect: {:?}", expect);
|
||||
let v_actual: Vec<&str> = actual.split(' ').collect();
|
||||
let v_expect: Vec<&str> = expect.split(' ').collect();
|
||||
let v_actual: Vec<&str> = actual.trim().split(' ').collect();
|
||||
let mut v_expect: Vec<&str> = expect.trim().split(' ').collect();
|
||||
assert!(!v_expect.is_empty());
|
||||
|
||||
// uu_stat does not support selinux
|
||||
if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(":") {
|
||||
// assume last element contains: `SELinux security context string`
|
||||
v_expect.pop();
|
||||
}
|
||||
|
||||
// * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
|
||||
assert!(
|
||||
expect == "0"
|
||||
|
@ -212,10 +156,10 @@ fn test_terse_normal_format() {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_format_created_time() {
|
||||
let args = ["-c", "%w", "/boot"];
|
||||
let args = ["-c", "%w", "/bin"];
|
||||
let actual = new_ucmd!().args(&args).succeeds().stdout_move_str();
|
||||
let expect = expected_result(&args);
|
||||
println!("actual: {:?}", actual);
|
||||
|
@ -236,10 +180,10 @@ fn test_format_created_time() {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_format_created_seconds() {
|
||||
let args = ["-c", "%W", "/boot"];
|
||||
let args = ["-c", "%W", "/bin"];
|
||||
let actual = new_ucmd!().args(&args).succeeds().stdout_move_str();
|
||||
let expect = expected_result(&args);
|
||||
println!("actual: {:?}", actual);
|
||||
|
@ -260,65 +204,97 @@ fn test_format_created_seconds() {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_normal_format() {
|
||||
let args = ["-c", NORMAL_FMTSTR, "/boot"];
|
||||
let args = ["-c", NORMAL_FMTSTR, "/bin"];
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.run()
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_follow_symlink() {
|
||||
let args = ["-L", "-c", DEV_FMTSTR, "/dev/cdrom"];
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(expected_result(&args));
|
||||
fn test_symlinks() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let mut tested: bool = false;
|
||||
// arbitrarily chosen symlinks with hope that the CI environment provides at least one of them
|
||||
for file in vec![
|
||||
"/bin/sh",
|
||||
"/bin/sudoedit",
|
||||
"/usr/bin/ex",
|
||||
"/etc/localtime",
|
||||
"/etc/aliases",
|
||||
] {
|
||||
if at.file_exists(file) && at.is_symlink(file) {
|
||||
tested = true;
|
||||
let args = ["-c", NORMAL_FMTSTR, file];
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(&args));
|
||||
// -L, --dereference follow links
|
||||
let args = ["-L", "-c", NORMAL_FMTSTR, file];
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
}
|
||||
if !tested {
|
||||
panic!("No symlink found to test in this environment");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_symlink() {
|
||||
let args = ["-c", DEV_FMTSTR, "/dev/cdrom"];
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_char() {
|
||||
let args = ["-c", DEV_FMTSTR, "/dev/pts/ptmx"];
|
||||
// TODO: "(%t) (%x) (%w)" deviate from GNU stat for `character special file` on macOS
|
||||
// Diff < left / right > :
|
||||
// <"(f0000) (2021-05-20 23:08:03.442555000 +0200) (1970-01-01 01:00:00.000000000 +0100)\n"
|
||||
// >"(f) (2021-05-20 23:08:03.455598000 +0200) (-)\n"
|
||||
let args = [
|
||||
"-c",
|
||||
#[cfg(target_os = "linux")]
|
||||
DEV_FMTSTR,
|
||||
#[cfg(target_os = "linux")]
|
||||
"/dev/pts/ptmx",
|
||||
#[cfg(any(target_vendor = "apple"))]
|
||||
"%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (/%T) %u %U %W %X %y %Y %z %Z",
|
||||
#[cfg(any(target_vendor = "apple"))]
|
||||
"/dev/ptmx",
|
||||
];
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.run()
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_multi_files() {
|
||||
let args = [
|
||||
"-c",
|
||||
NORMAL_FMTSTR,
|
||||
"/dev",
|
||||
"/usr/lib",
|
||||
#[cfg(target_os = "linux")]
|
||||
"/etc/fstab",
|
||||
"/var",
|
||||
];
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.run()
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_printf() {
|
||||
let args = [
|
||||
"--printf=123%-# 15q\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.23m\\x12\\167\\132\\112\\n",
|
||||
|
@ -326,16 +302,21 @@ fn test_printf() {
|
|||
];
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.run()
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
fn expected_result(args: &[&str]) -> String {
|
||||
TestScenario::new(util_name!())
|
||||
.cmd_keepenv(util_name!())
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(target_vendor = "apple")]
|
||||
let util_name = format!("g{}", util_name!());
|
||||
|
||||
TestScenario::new(&util_name)
|
||||
.cmd_keepenv(util_name)
|
||||
.env("LANGUAGE", "C")
|
||||
.args(args)
|
||||
.run()
|
||||
.succeeds()
|
||||
.stdout_move_str()
|
||||
}
|
||||
|
|
|
@ -27,12 +27,12 @@ fn test_stdbuf_line_buffered_stdout() {
|
|||
fn test_stdbuf_no_buffer_option_fails() {
|
||||
new_ucmd!().args(&["head"]).fails().stderr_is(
|
||||
"error: The following required arguments were not provided:\n \
|
||||
--error <MODE>\n \
|
||||
--input <MODE>\n \
|
||||
--output <MODE>\n\n\
|
||||
USAGE:\n \
|
||||
stdbuf OPTION... COMMAND\n\n\
|
||||
For more information try --help",
|
||||
--error <MODE>\n \
|
||||
--input <MODE>\n \
|
||||
--output <MODE>\n\n\
|
||||
USAGE:\n \
|
||||
stdbuf OPTION... COMMAND\n\n\
|
||||
For more information try --help",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -49,10 +49,9 @@ fn test_stdbuf_trailing_var_arg() {
|
|||
#[cfg(not(target_os = "windows"))]
|
||||
#[test]
|
||||
fn test_stdbuf_line_buffering_stdin_fails() {
|
||||
new_ucmd!()
|
||||
.args(&["-i", "L", "head"])
|
||||
.fails()
|
||||
.stderr_is("stdbuf: error: line buffering stdin is meaningless\nTry 'stdbuf --help' for more information.");
|
||||
new_ucmd!().args(&["-i", "L", "head"]).fails().stderr_is(
|
||||
"stdbuf: line buffering stdin is meaningless\nTry 'stdbuf --help' for more information.",
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
|
@ -61,5 +60,5 @@ fn test_stdbuf_invalid_mode_fails() {
|
|||
new_ucmd!()
|
||||
.args(&["-i", "1024R", "head"])
|
||||
.fails()
|
||||
.stderr_is("stdbuf: error: invalid mode 1024R\nTry 'stdbuf --help' for more information.");
|
||||
.stderr_is("stdbuf: invalid mode 1024R\nTry 'stdbuf --help' for more information.");
|
||||
}
|
||||
|
|
|
@ -59,9 +59,7 @@ fn test_invalid_file() {
|
|||
|
||||
at.mkdir("a");
|
||||
|
||||
ucmd.arg("a")
|
||||
.fails()
|
||||
.stderr_is("sum: error: 'a' Is a directory");
|
||||
ucmd.arg("a").fails().stderr_is("sum: 'a' Is a directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -70,5 +68,5 @@ fn test_invalid_metadata() {
|
|||
|
||||
ucmd.arg("b")
|
||||
.fails()
|
||||
.stderr_is("sum: error: 'b' No such file or directory");
|
||||
.stderr_is("sum: 'b' No such file or directory");
|
||||
}
|
||||
|
|
|
@ -37,5 +37,5 @@ fn test_sync_no_existing_files() {
|
|||
.arg("--data")
|
||||
.arg("do-no-exist")
|
||||
.fails()
|
||||
.stderr_contains("error: cannot stat");
|
||||
.stderr_contains("cannot stat");
|
||||
}
|
||||
|
|
|
@ -348,3 +348,43 @@ fn test_negative_indexing() {
|
|||
fn test_sleep_interval() {
|
||||
new_ucmd!().arg("-s").arg("10").arg(FOOBAR_TXT).succeeds();
|
||||
}
|
||||
|
||||
/// Test for reading all but the first NUM bytes: `tail -c +3`.
|
||||
#[test]
|
||||
fn test_positive_bytes() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "+3"])
|
||||
.pipe_in("abcde")
|
||||
.succeeds()
|
||||
.stdout_is("cde");
|
||||
}
|
||||
|
||||
/// Test for reading all bytes, specified by `tail -c +0`.
|
||||
#[test]
|
||||
fn test_positive_zero_bytes() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "+0"])
|
||||
.pipe_in("abcde")
|
||||
.succeeds()
|
||||
.stdout_is("abcde");
|
||||
}
|
||||
|
||||
/// Test for reading all but the first NUM lines: `tail -n +3`.
|
||||
#[test]
|
||||
fn test_positive_lines() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "+3"])
|
||||
.pipe_in("a\nb\nc\nd\ne\n")
|
||||
.succeeds()
|
||||
.stdout_is("c\nd\ne\n");
|
||||
}
|
||||
|
||||
/// Test for reading all lines, specified by `tail -n +0`.
|
||||
#[test]
|
||||
fn test_positive_zero_lines() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "+0"])
|
||||
.pipe_in("a\nb\nc\nd\ne\n")
|
||||
.succeeds()
|
||||
.stdout_is("a\nb\nc\nd\ne\n");
|
||||
}
|
||||
|
|
|
@ -122,6 +122,13 @@ fn test_zero_len_not_equals_zero_len_is_false() {
|
|||
new_ucmd!().args(&["", "!=", ""]).run().status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_double_equal_is_string_comparison_op() {
|
||||
// undocumented but part of the GNU test suite
|
||||
new_ucmd!().args(&["t", "==", "t"]).succeeds();
|
||||
new_ucmd!().args(&["t", "==", "f"]).run().status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_comparison() {
|
||||
let scenario = TestScenario::new(util_name!());
|
||||
|
@ -131,11 +138,22 @@ fn test_string_comparison() {
|
|||
["(", "=", "("],
|
||||
["(", "!=", ")"],
|
||||
["!", "=", "!"],
|
||||
["=", "=", "="],
|
||||
];
|
||||
|
||||
for test in &tests {
|
||||
scenario.ucmd().args(&test[..]).succeeds();
|
||||
}
|
||||
|
||||
// run the inverse of all these tests
|
||||
for test in &tests {
|
||||
scenario
|
||||
.ucmd()
|
||||
.arg("!")
|
||||
.args(&test[..])
|
||||
.run()
|
||||
.status_code(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -419,10 +437,9 @@ fn test_not_is_not_empty() {
|
|||
#[cfg(not(windows))]
|
||||
fn test_symlink_is_symlink() {
|
||||
let scenario = TestScenario::new(util_name!());
|
||||
let mut ln = scenario.cmd("ln");
|
||||
let at = &scenario.fixtures;
|
||||
|
||||
// creating symlinks requires admin on Windows
|
||||
ln.args(&["-s", "regular_file", "symlink"]).succeeds();
|
||||
at.symlink_file("regular_file", "symlink");
|
||||
|
||||
// FIXME: implement on Windows
|
||||
scenario.ucmd().args(&["-h", "symlink"]).succeeds();
|
||||
|
@ -485,6 +502,81 @@ fn test_op_prec_and_or_2_overridden_by_parentheses() {
|
|||
.status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negated_boolean_precedence() {
|
||||
let scenario = TestScenario::new(util_name!());
|
||||
|
||||
let tests = [
|
||||
vec!["!", "(", "foo", ")", "-o", "bar"],
|
||||
vec!["!", "", "-o", "", "-a", ""],
|
||||
vec!["!", "(", "", "-a", "", ")", "-o", ""],
|
||||
];
|
||||
|
||||
for test in &tests {
|
||||
scenario.ucmd().args(&test[..]).succeeds();
|
||||
}
|
||||
|
||||
let negative_tests = [
|
||||
vec!["!", "-n", "", "-a", ""],
|
||||
vec!["", "-a", "", "-o", ""],
|
||||
vec!["!", "", "-a", "", "-o", ""],
|
||||
vec!["!", "(", "", "-a", "", ")", "-a", ""],
|
||||
];
|
||||
|
||||
for test in &negative_tests {
|
||||
scenario.ucmd().args(&test[..]).run().status_code(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bang_boolop_precedence() {
|
||||
// For a Boolean combination of two literals, bang inverts the entire expression
|
||||
new_ucmd!().args(&["!", "", "-a", ""]).succeeds();
|
||||
new_ucmd!().args(&["!", "", "-o", ""]).succeeds();
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["!", "a value", "-o", "another value"])
|
||||
.run()
|
||||
.status_code(1);
|
||||
|
||||
// Introducing a UOP — even one that is equivalent to a bare string — causes
|
||||
// bang to invert only the first term
|
||||
new_ucmd!()
|
||||
.args(&["!", "-n", "", "-a", ""])
|
||||
.run()
|
||||
.status_code(1);
|
||||
new_ucmd!()
|
||||
.args(&["!", "", "-a", "-n", ""])
|
||||
.run()
|
||||
.status_code(1);
|
||||
|
||||
// for compound Boolean expressions, bang inverts the _next_ expression
|
||||
// only, not the entire compound expression
|
||||
new_ucmd!()
|
||||
.args(&["!", "", "-a", "", "-a", ""])
|
||||
.run()
|
||||
.status_code(1);
|
||||
|
||||
// parentheses can override this
|
||||
new_ucmd!()
|
||||
.args(&["!", "(", "", "-a", "", "-a", "", ")"])
|
||||
.succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inverted_parenthetical_boolop_precedence() {
|
||||
// For a Boolean combination of two literals, bang inverts the entire expression
|
||||
new_ucmd!()
|
||||
.args(&["!", "a value", "-o", "another value"])
|
||||
.run()
|
||||
.status_code(1);
|
||||
|
||||
// only the parenthetical is inverted, not the entire expression
|
||||
new_ucmd!()
|
||||
.args(&["!", "(", "a value", ")", "-o", "another value"])
|
||||
.succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "fixme: error reporting"]
|
||||
fn test_dangling_parenthesis() {
|
||||
|
|
|
@ -206,7 +206,7 @@ fn test_round_up() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let mut file = at.make_file(TFILE2);
|
||||
file.write_all(b"1234567890").unwrap();
|
||||
ucmd.args(&["--size", "*4", TFILE2]).succeeds();
|
||||
ucmd.args(&["--size", "%4", TFILE2]).succeeds();
|
||||
file.seek(SeekFrom::End(0)).unwrap();
|
||||
let actual = file.seek(SeekFrom::Current(0)).unwrap();
|
||||
assert!(
|
||||
|
@ -235,3 +235,30 @@ fn test_size_and_reference() {
|
|||
actual
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_numbers() {
|
||||
// TODO For compatibility with GNU, `truncate -s 0X` should cause
|
||||
// the same error as `truncate -s 0X file`, but currently it returns
|
||||
// a different error.
|
||||
new_ucmd!()
|
||||
.args(&["-s", "0X", "file"])
|
||||
.fails()
|
||||
.stderr_contains("Invalid number: ‘0X’");
|
||||
new_ucmd!()
|
||||
.args(&["-s", "0XB", "file"])
|
||||
.fails()
|
||||
.stderr_contains("Invalid number: ‘0XB’");
|
||||
new_ucmd!()
|
||||
.args(&["-s", "0B", "file"])
|
||||
.fails()
|
||||
.stderr_contains("Invalid number: ‘0B’");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reference_file_not_found() {
|
||||
new_ucmd!()
|
||||
.args(&["-r", "a", "b"])
|
||||
.fails()
|
||||
.stderr_contains("cannot stat 'a': No such file or directory");
|
||||
}
|
||||
|
|
|
@ -43,5 +43,5 @@ fn test_uname_kernel() {
|
|||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let result = ucmd.arg("-o").succeeds();
|
||||
ucmd.arg("-o").succeeds();
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ fn test_invalid_utf8() {
|
|||
.arg("not-utf8-sequence.txt")
|
||||
.run()
|
||||
.failure()
|
||||
.stderr_only("uniq: error: invalid utf-8 sequence of 1 bytes from index 0");
|
||||
.stderr_only("uniq: invalid utf-8 sequence of 1 bytes from index 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -22,7 +22,7 @@ fn test_unlink_multiple_files() {
|
|||
at.touch(file_b);
|
||||
|
||||
ucmd.arg(file_a).arg(file_b).fails().stderr_is(
|
||||
"unlink: error: extra operand: 'test_unlink_multiple_file_b'\nTry 'unlink --help' \
|
||||
"unlink: extra operand: 'test_unlink_multiple_file_b'\nTry 'unlink --help' \
|
||||
for more information.\n",
|
||||
);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ fn test_unlink_directory() {
|
|||
at.mkdir(dir);
|
||||
|
||||
ucmd.arg(dir).fails().stderr_is(
|
||||
"unlink: error: cannot unlink 'test_unlink_empty_directory': Not a regular file \
|
||||
"unlink: cannot unlink 'test_unlink_empty_directory': Not a regular file \
|
||||
or symlink\n",
|
||||
);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ fn test_unlink_nonexistent() {
|
|||
let file = "test_unlink_nonexistent";
|
||||
|
||||
new_ucmd!().arg(file).fails().stderr_is(
|
||||
"unlink: error: Cannot stat 'test_unlink_nonexistent': No such file or directory \
|
||||
"unlink: Cannot stat 'test_unlink_nonexistent': No such file or directory \
|
||||
(os error 2)\n",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,16 @@ fn test_stdin_default() {
|
|||
new_ucmd!()
|
||||
.pipe_in_fixture("lorem_ipsum.txt")
|
||||
.run()
|
||||
.stdout_is(" 13 109 772\n");
|
||||
.stdout_is(" 13 109 772\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdin_explicit() {
|
||||
new_ucmd!()
|
||||
.pipe_in_fixture("lorem_ipsum.txt")
|
||||
.arg("-")
|
||||
.run()
|
||||
.stdout_is(" 13 109 772 -\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -42,9 +51,11 @@ fn test_utf8() {
|
|||
.args(&["-lwmcL"])
|
||||
.pipe_in_fixture("UTF_8_test.txt")
|
||||
.run()
|
||||
.stdout_is(" 300 4969 22781 22213 79\n");
|
||||
// GNU returns " 300 2086 22219 22781 79"
|
||||
// TODO: we should fix that to match GNU's behavior
|
||||
.stdout_is(" 300 4969 22781 22213 79\n");
|
||||
// GNU returns " 300 2086 22219 22781 79"
|
||||
//
|
||||
// TODO: we should fix the word, character, and byte count to
|
||||
// match the behavior of GNU wc
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -71,7 +82,7 @@ fn test_stdin_all_counts() {
|
|||
.args(&["-c", "-m", "-l", "-L", "-w"])
|
||||
.pipe_in_fixture("alice_in_wonderland.txt")
|
||||
.run()
|
||||
.stdout_is(" 5 57 302 302 66\n");
|
||||
.stdout_is(" 5 57 302 302 66\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -79,7 +90,7 @@ fn test_single_default() {
|
|||
new_ucmd!()
|
||||
.arg("moby_dick.txt")
|
||||
.run()
|
||||
.stdout_is(" 18 204 1115 moby_dick.txt\n");
|
||||
.stdout_is(" 18 204 1115 moby_dick.txt\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -95,7 +106,7 @@ fn test_single_all_counts() {
|
|||
new_ucmd!()
|
||||
.args(&["-c", "-l", "-L", "-m", "-w", "alice_in_wonderland.txt"])
|
||||
.run()
|
||||
.stdout_is(" 5 57 302 302 66 alice_in_wonderland.txt\n");
|
||||
.stdout_is(" 5 57 302 302 66 alice_in_wonderland.txt\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -108,64 +119,101 @@ fn test_multiple_default() {
|
|||
])
|
||||
.run()
|
||||
.stdout_is(
|
||||
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 5 57 302 \
|
||||
alice_in_wonderland.txt\n 36 370 2189 total\n",
|
||||
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 5 57 302 \
|
||||
alice_in_wonderland.txt\n 36 370 2189 total\n",
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for an empty file.
|
||||
#[test]
|
||||
fn test_file_empty() {
|
||||
// TODO There is a leading space in the output that should be
|
||||
// removed; see issue #2173.
|
||||
new_ucmd!()
|
||||
.args(&["-clmwL", "emptyfile.txt"])
|
||||
.run()
|
||||
.stdout_is(" 0 0 0 0 0 emptyfile.txt\n");
|
||||
.stdout_is("0 0 0 0 0 emptyfile.txt\n");
|
||||
}
|
||||
|
||||
/// Test for an file containing a single non-whitespace character
|
||||
/// *without* a trailing newline.
|
||||
#[test]
|
||||
fn test_file_single_line_no_trailing_newline() {
|
||||
// TODO There is a leading space in the output that should be
|
||||
// removed; see issue #2173.
|
||||
new_ucmd!()
|
||||
.args(&["-clmwL", "notrailingnewline.txt"])
|
||||
.run()
|
||||
.stdout_is(" 1 1 2 2 1 notrailingnewline.txt\n");
|
||||
.stdout_is("1 1 2 2 1 notrailingnewline.txt\n");
|
||||
}
|
||||
|
||||
/// Test for a file that has 100 empty lines (that is, the contents of
|
||||
/// the file are the newline character repeated one hundred times).
|
||||
#[test]
|
||||
fn test_file_many_empty_lines() {
|
||||
// TODO There is a leading space in the output that should be
|
||||
// removed; see issue #2173.
|
||||
new_ucmd!()
|
||||
.args(&["-clmwL", "manyemptylines.txt"])
|
||||
.run()
|
||||
.stdout_is(" 100 0 100 100 0 manyemptylines.txt\n");
|
||||
.stdout_is("100 0 100 100 0 manyemptylines.txt\n");
|
||||
}
|
||||
|
||||
/// Test for a file that has one long line comprising only spaces.
|
||||
#[test]
|
||||
fn test_file_one_long_line_only_spaces() {
|
||||
// TODO There is a leading space in the output that should be
|
||||
// removed; see issue #2173.
|
||||
new_ucmd!()
|
||||
.args(&["-clmwL", "onelongemptyline.txt"])
|
||||
.run()
|
||||
.stdout_is(" 1 0 10001 10001 10000 onelongemptyline.txt\n");
|
||||
.stdout_is(" 1 0 10001 10001 10000 onelongemptyline.txt\n");
|
||||
}
|
||||
|
||||
/// Test for a file that has one long line comprising a single "word".
|
||||
#[test]
|
||||
fn test_file_one_long_word() {
|
||||
// TODO There is a leading space in the output that should be
|
||||
// removed; see issue #2173.
|
||||
new_ucmd!()
|
||||
.args(&["-clmwL", "onelongword.txt"])
|
||||
.run()
|
||||
.stdout_is(" 1 1 10001 10001 10000 onelongword.txt\n");
|
||||
.stdout_is(" 1 1 10001 10001 10000 onelongword.txt\n");
|
||||
}
|
||||
|
||||
/// Test that the number of bytes in the file dictate the display width.
|
||||
///
|
||||
/// The width in digits of any count is the width in digits of the
|
||||
/// number of bytes in the file, regardless of whether the number of
|
||||
/// bytes are displayed.
|
||||
#[test]
|
||||
fn test_file_bytes_dictate_width() {
|
||||
// This file has 10,001 bytes. Five digits are required to
|
||||
// represent that. Even though the number of lines is 1 and the
|
||||
// number of words is 0, each of those counts is formatted with
|
||||
// five characters, filled with whitespace.
|
||||
new_ucmd!()
|
||||
.args(&["-lw", "onelongemptyline.txt"])
|
||||
.run()
|
||||
.stdout_is(" 1 0 onelongemptyline.txt\n");
|
||||
|
||||
// This file has zero bytes. Only one digit is required to
|
||||
// represent that.
|
||||
new_ucmd!()
|
||||
.args(&["-lw", "emptyfile.txt"])
|
||||
.run()
|
||||
.stdout_is("0 0 emptyfile.txt\n");
|
||||
}
|
||||
|
||||
/// Test that getting counts from a directory is an error.
|
||||
#[test]
|
||||
fn test_read_from_directory_error() {
|
||||
// TODO To match GNU `wc`, the `stdout` should be:
|
||||
//
|
||||
// " 0 0 0 .\n"
|
||||
//
|
||||
new_ucmd!()
|
||||
.args(&["."])
|
||||
.fails()
|
||||
.stderr_contains(".: Is a directory\n")
|
||||
.stdout_is("0 0 0 .\n");
|
||||
}
|
||||
|
||||
/// Test that getting counts from nonexistent file is an error.
|
||||
#[test]
|
||||
fn test_read_from_nonexistent_file() {
|
||||
new_ucmd!()
|
||||
.args(&["bogusfile"])
|
||||
.fails()
|
||||
.stderr_contains("bogusfile: No such file or directory\n");
|
||||
}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
use crate::common::util::*;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_count() {
|
||||
for opt in vec!["-q", "--count"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_boot() {
|
||||
for opt in vec!["-b", "--boot"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_heading() {
|
||||
for opt in vec!["-H", "--heading"] {
|
||||
|
@ -30,7 +30,7 @@ fn test_heading() {
|
|||
// * minor whitespace differences occur between platform built-in outputs;
|
||||
// specifically number of TABs between "TIME" and "COMMENT" may be variant
|
||||
let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str();
|
||||
let expect = expected_result(opt);
|
||||
let expect = expected_result(&[opt]);
|
||||
println!("actual: {:?}", actual);
|
||||
println!("expect: {:?}", expect);
|
||||
let v_actual: Vec<&str> = actual.split_whitespace().collect();
|
||||
|
@ -39,205 +39,208 @@ fn test_heading() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_short() {
|
||||
for opt in vec!["-s", "--short"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_login() {
|
||||
for opt in vec!["-l", "--login"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_m() {
|
||||
for opt in vec!["-m"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_process() {
|
||||
for opt in vec!["-p", "--process"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_runlevel() {
|
||||
for opt in vec!["-r", "--runlevel"] {
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
new_ucmd!().arg(opt).succeeds().stdout_is("");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_time() {
|
||||
for opt in vec!["-t", "--time"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_mesg() {
|
||||
for opt in vec!["-w", "-T", "--users", "--message", "--writable"] {
|
||||
// -T, -w, --mesg
|
||||
// add user's message status as +, - or ?
|
||||
// --message
|
||||
// same as -T
|
||||
// --writable
|
||||
// same as -T
|
||||
for opt in vec!["-T", "-w", "--mesg", "--message", "--writable"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_arg1_arg2() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let args = ["am", "i"];
|
||||
|
||||
let expected = scene
|
||||
.cmd_keepenv(util_name!())
|
||||
.env("LANGUAGE", "C")
|
||||
.arg("am")
|
||||
.arg("i")
|
||||
.succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("am")
|
||||
.arg("i")
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_is(expected.stdout_str());
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_too_many_args() {
|
||||
let expected =
|
||||
const EXPECTED: &str =
|
||||
"error: The value 'u' was provided to '<FILE>...', but it wasn't expecting any more values";
|
||||
|
||||
new_ucmd!()
|
||||
.arg("am")
|
||||
.arg("i")
|
||||
.arg("u")
|
||||
.fails()
|
||||
.stderr_contains(expected);
|
||||
let args = ["am", "i", "u"];
|
||||
new_ucmd!().args(&args).fails().stderr_contains(EXPECTED);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_users() {
|
||||
for opt in vec!["-u", "--users"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str();
|
||||
let expect = expected_result(&[opt]);
|
||||
println!("actual: {:?}", actual);
|
||||
println!("expect: {:?}", expect);
|
||||
|
||||
let mut v_actual: Vec<&str> = actual.split_whitespace().collect();
|
||||
let mut v_expect: Vec<&str> = expect.split_whitespace().collect();
|
||||
|
||||
// TODO: `--users` differs from GNU's output on macOS
|
||||
// Diff < left / right > :
|
||||
// <"runner console 2021-05-20 22:03 00:08 196\n"
|
||||
// >"runner console 2021-05-20 22:03 old 196\n"
|
||||
if cfg!(target_os = "macos") {
|
||||
v_actual.remove(4);
|
||||
v_expect.remove(4);
|
||||
}
|
||||
|
||||
assert_eq!(v_actual, v_expect);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_lookup() {
|
||||
for opt in vec!["--lookup"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_dead() {
|
||||
for opt in vec!["-d", "--dead"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_all_separately() {
|
||||
if cfg!(target_os = "macos") {
|
||||
// TODO: fix `-u`, see: test_users
|
||||
return;
|
||||
}
|
||||
|
||||
// -a, --all same as -b -d --login -p -r -t -T -u
|
||||
let args = ["-b", "-d", "--login", "-p", "-r", "-t", "-T", "-u"];
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
let expected = scene
|
||||
.cmd_keepenv(util_name!())
|
||||
.env("LANGUAGE", "C")
|
||||
.arg("-b")
|
||||
.arg("-d")
|
||||
.arg("--login")
|
||||
.arg("-p")
|
||||
.arg("-r")
|
||||
.arg("-t")
|
||||
.arg("-T")
|
||||
.arg("-u")
|
||||
.succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-b")
|
||||
.arg("-d")
|
||||
.arg("--login")
|
||||
.arg("-p")
|
||||
.arg("-r")
|
||||
.arg("-t")
|
||||
.arg("-T")
|
||||
.arg("-u")
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_is(expected.stdout_str());
|
||||
|
||||
.stdout_is(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--all")
|
||||
.succeeds()
|
||||
.stdout_is(expected.stdout_str());
|
||||
.stdout_is(expected_result(&args));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_all() {
|
||||
if cfg!(target_os = "macos") {
|
||||
// TODO: fix `-u`, see: test_users
|
||||
return;
|
||||
}
|
||||
|
||||
for opt in vec!["-a", "--all"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.succeeds()
|
||||
.stdout_is(expected_result(opt));
|
||||
.stdout_is(expected_result(&[opt]));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn expected_result(arg: &str) -> String {
|
||||
TestScenario::new(util_name!())
|
||||
.cmd_keepenv(util_name!())
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
fn expected_result(args: &[&str]) -> String {
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(target_vendor = "apple")]
|
||||
let util_name = format!("g{}", util_name!());
|
||||
|
||||
TestScenario::new(&util_name)
|
||||
.cmd_keepenv(util_name)
|
||||
.env("LANGUAGE", "C")
|
||||
.args(&[arg])
|
||||
.args(args)
|
||||
.succeeds()
|
||||
.stdout_move_str()
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::common::util::*;
|
|||
// considered okay. If we are not inside the CI this calls assert!(result.success).
|
||||
//
|
||||
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
|
||||
// stderr: "whoami: error: failed to get username"
|
||||
// stderr: "whoami: failed to get username"
|
||||
// Maybe: "adduser --uid 1001 username" can put things right?
|
||||
fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool {
|
||||
if !result.succeeded() {
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::env;
|
|||
#[cfg(not(windows))]
|
||||
use std::ffi::CString;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::fs::{self, hard_link, File, OpenOptions};
|
||||
use std::io::{Read, Result, Write};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::{symlink as symlink_dir, symlink as symlink_file};
|
||||
|
@ -163,7 +163,7 @@ impl CmdResult {
|
|||
|
||||
/// asserts that the command's exit code is the same as the given one
|
||||
pub fn status_code(&self, code: i32) -> &CmdResult {
|
||||
assert!(self.code == Some(code));
|
||||
assert_eq!(self.code, Some(code));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -295,17 +295,32 @@ impl CmdResult {
|
|||
}
|
||||
|
||||
pub fn stdout_contains<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
|
||||
assert!(self.stdout_str().contains(cmp.as_ref()));
|
||||
assert!(
|
||||
self.stdout_str().contains(cmp.as_ref()),
|
||||
"'{}' does not contain '{}'",
|
||||
self.stdout_str(),
|
||||
cmp.as_ref()
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stderr_contains<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
|
||||
assert!(self.stderr_str().contains(cmp.as_ref()));
|
||||
assert!(
|
||||
self.stderr_str().contains(cmp.as_ref()),
|
||||
"'{}' does not contain '{}'",
|
||||
self.stderr_str(),
|
||||
cmp.as_ref()
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stdout_does_not_contain<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
|
||||
assert!(!self.stdout_str().contains(cmp.as_ref()));
|
||||
assert!(
|
||||
!self.stdout_str().contains(cmp.as_ref()),
|
||||
"'{}' contains '{}' but should not",
|
||||
self.stdout_str(),
|
||||
cmp.as_ref(),
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -509,6 +524,14 @@ impl AtPath {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hard_link(&self, src: &str, dst: &str) {
|
||||
log_info(
|
||||
"hard_link",
|
||||
&format!("{},{}", self.plus_as_string(src), self.plus_as_string(dst)),
|
||||
);
|
||||
hard_link(&self.plus(src), &self.plus(dst)).unwrap();
|
||||
}
|
||||
|
||||
pub fn symlink_file(&self, src: &str, dst: &str) {
|
||||
log_info(
|
||||
"symlink",
|
||||
|
@ -665,6 +688,10 @@ impl TestScenario {
|
|||
cmd
|
||||
}
|
||||
|
||||
/// Returns builder for invoking any system command. Paths given are treated
|
||||
/// relative to the environment's unique temporary test directory.
|
||||
/// Differs from the builder returned by `cmd` in that `cmd_keepenv` does not call
|
||||
/// `Command::env_clear` (Clears the entire environment map for the child process.)
|
||||
pub fn cmd_keepenv<S: AsRef<OsStr>>(&self, bin: S) -> UCommand {
|
||||
UCommand::new_from_tmp(bin, self.tmpd.clone(), false)
|
||||
}
|
||||
|
|
0
tests/fixtures/head/emptyfile.txt
vendored
Normal file
0
tests/fixtures/head/emptyfile.txt
vendored
Normal file
4
tests/fixtures/sort/ext_stable.expected
vendored
Normal file
4
tests/fixtures/sort/ext_stable.expected
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
0a
|
||||
0a
|
||||
0b
|
||||
0b
|
4
tests/fixtures/sort/ext_stable.txt
vendored
Normal file
4
tests/fixtures/sort/ext_stable.txt
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
0a
|
||||
0a
|
||||
0b
|
||||
0b
|
3
tests/fixtures/sort/merge_stable.expected
vendored
Normal file
3
tests/fixtures/sort/merge_stable.expected
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
0a
|
||||
0c
|
||||
0b
|
2
tests/fixtures/sort/merge_stable_1.txt
vendored
Normal file
2
tests/fixtures/sort/merge_stable_1.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
0a
|
||||
0c
|
1
tests/fixtures/sort/merge_stable_2.txt
vendored
Normal file
1
tests/fixtures/sort/merge_stable_2.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
0b
|
Loading…
Add table
Add a link
Reference in a new issue