1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-09-15 11:36:16 +00:00

Merge branch 'master' into issue2167

This commit is contained in:
Sylvestre Ledru 2021-05-08 20:26:21 +02:00 committed by GitHub
commit 01a702c6fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 1948 additions and 1176 deletions

View file

@ -1,6 +1,29 @@
use crate::common::util::*;
use std::ffi::OsStr;
#[test]
fn test_help() {
for help_flg in vec!["-h", "--help"] {
new_ucmd!()
.arg(&help_flg)
.succeeds()
.no_stderr()
.stdout_contains("USAGE:");
}
}
#[test]
fn test_version() {
for version_flg in vec!["-V", "--version"] {
assert!(new_ucmd!()
.arg(&version_flg)
.succeeds()
.no_stderr()
.stdout_str()
.starts_with("basename"));
}
}
#[test]
fn test_directory() {
new_ucmd!()
@ -81,11 +104,25 @@ fn test_no_args() {
expect_error(vec![]);
}
#[test]
fn test_no_args_output() {
new_ucmd!()
.fails()
.stderr_is("basename: error: missing operand\nTry 'basename --help' for more information.");
}
#[test]
fn test_too_many_args() {
expect_error(vec!["a", "b", "c"]);
}
#[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.",
);
}
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");

View file

@ -20,4 +20,16 @@ fn test_df_compatible_si() {
new_ucmd!().arg("-aH").succeeds();
}
#[test]
fn test_df_output() {
if cfg!(target_os = "macos") {
new_ucmd!().arg("-H").arg("-total").succeeds().
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",
);
}
}
// ToDO: more tests...

View file

@ -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() {
@ -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() {
@ -141,7 +157,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 +205,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() {

View file

@ -33,18 +33,16 @@ fn test_fmt_w_too_big() {
"fmt: error: 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
*/

View file

@ -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;
@ -308,6 +309,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!());

View file

@ -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");
}

View file

@ -37,7 +37,29 @@ fn test_larger_than_specified_segment() {
.arg("50K")
.arg("ext_sort.txt")
.succeeds()
.stdout_is_fixture(format!("{}", "ext_sort.expected"));
.stdout_is_fixture("ext_sort.expected");
}
#[test]
fn test_smaller_than_specified_segment() {
new_ucmd!()
.arg("-n")
.arg("-S")
.arg("100M")
.arg("ext_sort.txt")
.succeeds()
.stdout_is_fixture("ext_sort.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]

View file

@ -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);
}

View file

@ -9,42 +9,6 @@ pub use self::stat::*;
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));
@ -198,9 +162,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"

View file

@ -33,7 +33,7 @@ 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]
@ -42,7 +42,7 @@ fn test_utf8() {
.args(&["-lwmcL"])
.pipe_in_fixture("UTF_8_test.txt")
.run()
.stdout_is(" 300 4969 22781 22213 79\n");
.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
}
@ -71,7 +71,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 +79,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 +95,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,7 +108,54 @@ 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() {
new_ucmd!()
.args(&["-clmwL", "emptyfile.txt"])
.run()
.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() {
new_ucmd!()
.args(&["-clmwL", "notrailingnewline.txt"])
.run()
.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() {
new_ucmd!()
.args(&["-clmwL", "manyemptylines.txt"])
.run()
.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() {
new_ucmd!()
.args(&["-clmwL", "onelongemptyline.txt"])
.run()
.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() {
new_ucmd!()
.args(&["-clmwL", "onelongword.txt"])
.run()
.stdout_is(" 1 1 10001 10001 10000 onelongword.txt\n");
}

View file

@ -1,11 +1,13 @@
#[cfg(target_os = "linux")]
use crate::common::util::*;
#[cfg(target_os = "linux")]
#[test]
fn test_count() {
for opt in vec!["-q", "--count"] {
new_ucmd!().arg(opt).run().stdout_is(expected_result(opt));
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
@ -13,17 +15,21 @@ fn test_count() {
#[test]
fn test_boot() {
for opt in vec!["-b", "--boot"] {
new_ucmd!().arg(opt).run().stdout_is(expected_result(opt));
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
fn test_heading() {
for opt in vec!["-H"] {
for opt in vec!["-H", "--heading"] {
// allow whitespace variation
// * minor whitespace differences occur between platform built-in outputs; specifically number of TABs between "TIME" and "COMMENT" may be variant
let actual = new_ucmd!().arg(opt).run().stdout_move_str();
// * 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);
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -37,7 +43,10 @@ fn test_heading() {
#[test]
fn test_short() {
for opt in vec!["-s", "--short"] {
new_ucmd!().arg(opt).run().stdout_is(expected_result(opt));
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
@ -45,7 +54,10 @@ fn test_short() {
#[test]
fn test_login() {
for opt in vec!["-l", "--login"] {
new_ucmd!().arg(opt).run().stdout_is(expected_result(opt));
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
@ -53,7 +65,110 @@ fn test_login() {
#[test]
fn test_m() {
for opt in vec!["-m"] {
new_ucmd!().arg(opt).run().stdout_is(expected_result(opt));
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
fn test_process() {
for opt in vec!["-p", "--process"] {
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
fn test_runlevel() {
for opt in vec!["-r", "--runlevel"] {
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
fn test_time() {
for opt in vec!["-t", "--time"] {
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
fn test_mesg() {
for opt in vec!["-w", "-T", "--users", "--message", "--writable"] {
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
fn test_arg1_arg2() {
let scene = TestScenario::new(util_name!());
let expected = scene
.cmd_keepenv(util_name!())
.env("LANGUAGE", "C")
.arg("am")
.arg("i")
.succeeds();
scene
.ucmd()
.arg("am")
.arg("i")
.succeeds()
.stdout_is(expected.stdout_str());
}
#[test]
fn test_too_many_args() {
let expected =
"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);
}
#[cfg(target_os = "linux")]
#[test]
fn test_users() {
for opt in vec!["-u", "--users"] {
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
#[ignore]
fn test_lookup() {
for opt in vec!["--lookup"] {
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
@ -61,15 +176,60 @@ fn test_m() {
#[test]
fn test_dead() {
for opt in vec!["-d", "--dead"] {
new_ucmd!().arg(opt).run().stdout_is(expected_result(opt));
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
#[cfg(target_os = "linux")]
#[test]
fn test_all_separately() {
// -a, --all same as -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")
.succeeds()
.stdout_is(expected.stdout_str());
scene
.ucmd()
.arg("--all")
.succeeds()
.stdout_is(expected.stdout_str());
}
#[cfg(target_os = "linux")]
#[test]
fn test_all() {
for opt in vec!["-a", "--all"] {
new_ucmd!().arg(opt).run().stdout_is(expected_result(opt));
new_ucmd!()
.arg(opt)
.succeeds()
.stdout_is(expected_result(opt));
}
}
@ -79,6 +239,6 @@ fn expected_result(arg: &str) -> String {
.cmd_keepenv(util_name!())
.env("LANGUAGE", "C")
.args(&[arg])
.run()
.succeeds()
.stdout_move_str()
}

View 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,12 +295,22 @@ 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
}

0
tests/fixtures/wc/emptyfile.txt vendored Normal file
View file

100
tests/fixtures/wc/manyemptylines.txt vendored Normal file
View file

@ -0,0 +1,100 @@

View file

@ -0,0 +1 @@
a

File diff suppressed because one or more lines are too long

1
tests/fixtures/wc/onelongword.txt vendored Normal file

File diff suppressed because one or more lines are too long