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

Merge branch 'master' into split-wsl-detection

This commit is contained in:
Sylvestre Ledru 2021-04-24 10:24:13 +02:00 committed by GitHub
commit 8ccc6ade61
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
79 changed files with 3127 additions and 1800 deletions

View file

@ -1,4 +1,7 @@
use crate::common::util::*;
#[cfg(unix)]
use std::fs::OpenOptions;
#[cfg(unix)]
use std::io::Read;
#[test]
@ -26,7 +29,7 @@ fn test_no_options() {
}
#[test]
#[cfg(unix)]
#[cfg(any(target_vendor = "apple", target_os = "linux", target_os = "android"))]
fn test_no_options_big_input() {
for &n in &[
0,
@ -54,7 +57,6 @@ fn test_no_options_big_input() {
#[test]
#[cfg(unix)]
fn test_fifo_symlink() {
use std::fs::OpenOptions;
use std::io::Write;
use std::thread;
@ -85,6 +87,74 @@ fn test_fifo_symlink() {
thread.join().unwrap();
}
#[test]
#[cfg(unix)]
fn test_piped_to_regular_file() {
use std::fs::read_to_string;
for &append in &[true, false] {
let s = TestScenario::new(util_name!());
let file_path = s.fixtures.plus("file.txt");
{
let file = OpenOptions::new()
.create_new(true)
.write(true)
.append(append)
.open(&file_path)
.unwrap();
s.ucmd()
.set_stdout(file)
.pipe_in_fixture("alpha.txt")
.succeeds();
}
let contents = read_to_string(&file_path).unwrap();
assert_eq!(contents, "abcde\nfghij\nklmno\npqrst\nuvwxyz\n");
}
}
#[test]
#[cfg(unix)]
fn test_piped_to_dev_null() {
for &append in &[true, false] {
let s = TestScenario::new(util_name!());
{
let dev_null = OpenOptions::new()
.write(true)
.append(append)
.open("/dev/null")
.unwrap();
s.ucmd()
.set_stdout(dev_null)
.pipe_in_fixture("alpha.txt")
.succeeds();
}
}
}
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_piped_to_dev_full() {
for &append in &[true, false] {
let s = TestScenario::new(util_name!());
{
let dev_full = OpenOptions::new()
.write(true)
.append(append)
.open("/dev/full")
.unwrap();
s.ucmd()
.set_stdout(dev_full)
.pipe_in_fixture("alpha.txt")
.fails()
.stderr_contains(&"No space left on device".to_owned());
}
}
}
#[test]
fn test_directory() {
let s = TestScenario::new(util_name!());
@ -330,22 +400,29 @@ fn test_domain_socket() {
use std::thread;
use tempdir::TempDir;
use unix_socket::UnixListener;
use std::sync::{Barrier, Arc};
let dir = TempDir::new("unix_socket").expect("failed to create dir");
let socket_path = dir.path().join("sock");
let listener = UnixListener::bind(&socket_path).expect("failed to create socket");
// use a barrier to ensure we don't run cat before the listener is setup
let barrier = Arc::new(Barrier::new(2));
let barrier2 = Arc::clone(&barrier);
let thread = thread::spawn(move || {
let mut stream = listener.accept().expect("failed to accept connection").0;
barrier2.wait();
stream
.write_all(b"a\tb")
.expect("failed to write test data");
});
new_ucmd!()
.args(&[socket_path])
.succeeds()
.stdout_only("a\tb");
let child = new_ucmd!().args(&[socket_path]).run_no_wait();
barrier.wait();
let stdout = &child.wait_with_output().unwrap().stdout.clone();
let output = String::from_utf8_lossy(&stdout);
assert_eq!("a\tb", output);
thread.join().unwrap();
}

View file

@ -47,7 +47,7 @@ fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
ucmd.arg(arg);
}
let r = ucmd.run();
if !r.success {
if !r.succeeded() {
println!("{}", r.stderr_str());
panic!("{:?}: failed", ucmd.raw);
}
@ -357,7 +357,8 @@ fn test_chmod_symlink_non_existing_file() {
at.symlink_file(non_existing, test_symlink);
// this cannot succeed since the symbolic link dangles
scene.ucmd()
scene
.ucmd()
.arg("755")
.arg("-v")
.arg(test_symlink)
@ -367,7 +368,8 @@ fn test_chmod_symlink_non_existing_file() {
.stderr_contains(expected_stderr);
// this should be the same than with just '-v' but without stderr
scene.ucmd()
scene
.ucmd()
.arg("755")
.arg("-v")
.arg("-f")
@ -394,7 +396,8 @@ fn test_chmod_symlink_non_existing_file_recursive() {
);
// this should succeed
scene.ucmd()
scene
.ucmd()
.arg("-R")
.arg("755")
.arg(test_directory)
@ -408,7 +411,8 @@ fn test_chmod_symlink_non_existing_file_recursive() {
);
// '-v': this should succeed without stderr
scene.ucmd()
scene
.ucmd()
.arg("-R")
.arg("-v")
.arg("755")
@ -418,7 +422,8 @@ fn test_chmod_symlink_non_existing_file_recursive() {
.no_stderr();
// '-vf': this should be the same than with just '-v'
scene.ucmd()
scene
.ucmd()
.arg("-R")
.arg("-v")
.arg("-f")

View file

@ -4,6 +4,34 @@ use rust_users::get_effective_uid;
extern crate chown;
// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
// If we are running inside the CI and "needle" is in "stderr" skipping this test is
// 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: cannot find name for user ID 1001"
// TODO: Maybe `adduser --uid 1001 username` can put things right?
//
// stderr: "id: cannot find name for group ID 116"
// stderr: "thread 'main' panicked at 'called `Result::unwrap()` on an `Err`
// value: Custom { kind: NotFound, error: "No such id: 1001" }',
// /project/src/uucore/src/lib/features/perms.rs:176:44"
//
fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool {
if !result.succeeded() {
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains(needle) {
println!("test skipped:");
return true;
} else {
result.success();
}
}
false
}
#[cfg(test)]
mod test_passgrp {
use super::chown::entries::{gid2grp, grp2gid, uid2usr, usr2uid};
@ -49,116 +77,193 @@ fn test_invalid_option() {
}
#[test]
fn test_chown_myself() {
fn test_chown_only_owner() {
// test chown username file.txt
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
return;
}
println!("results {}", result.stdout_str());
let username = result.stdout_str().trim_end();
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
let user_name = String::from(result.stdout_str().trim());
assert!(!user_name.is_empty());
let file1 = "test_chown_file1";
at.touch(file1);
let result = ucmd.arg(username).arg(file1).run();
println!("results stdout {}", result.stdout_str());
println!("results stderr {}", result.stderr_str());
if is_ci() && result.stderr_str().contains("invalid user") {
// In the CI, some server are failing to return id.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
}
#[test]
fn test_chown_myself_second() {
// test chown username: file.txt
let scene = TestScenario::new(util_name!());
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
return;
}
println!("results {}", result.stdout_str());
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
at.touch(file1);
let result = ucmd
.arg(result.stdout_str().trim_end().to_owned() + ":")
// since only superuser can change owner, we have to change from ourself to ourself
let result = scene
.ucmd()
.arg(user_name)
.arg("--verbose")
.arg(file1)
.run();
result.stderr_contains(&"retained as");
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
assert!(result.success);
// try to change to another existing user, e.g. 'root'
scene
.ucmd()
.arg("root")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
fn test_chown_myself_group() {
// test chown username:group file.txt
fn test_chown_only_owner_colon() {
// test chown username: file.txt
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
return;
}
println!("user name = {}", result.stdout_str());
let username = result.stdout_str().trim_end();
let user_name = String::from(result.stdout_str().trim());
assert!(!user_name.is_empty());
let file1 = "test_chown_file1";
at.touch(file1);
scene
.ucmd()
.arg(format!("{}:", user_name))
.arg("--verbose")
.arg(file1)
.succeeds()
.stderr_contains(&"retained as");
scene
.ucmd()
.arg("root:")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
fn test_chown_only_colon() {
// test chown : file.txt
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let file1 = "test_chown_file1";
at.touch(file1);
// expected:
// $ chown -v : file.txt 2>out_err ; echo $? ; cat out_err
// ownership of 'file.txt' retained
// 0
let result = scene.ucmd().arg(":").arg("--verbose").arg(file1).run();
if skipping_test_is_okay(&result, "No such id") {
return;
}
result.stderr_contains(&"retained as"); // TODO: verbose is not printed to stderr in GNU chown
// test chown : file.txt
// expected:
// $ chown -v :: file.txt 2>out_err ; echo $? ; cat out_err
// 1
// chown: invalid group: ::
scene
.ucmd()
.arg("::")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"invalid group: ::");
}
#[test]
fn test_chown_failed_stdout() {
// test chown root file.txt
// TODO: implement once output "failed to change" to stdout is fixed
// expected:
// $ chown -v root file.txt 2>out_err ; echo $? ; cat out_err
// failed to change ownership of 'file.txt' from jhs to root
// 1
// chown: changing ownership of 'file.txt': Operation not permitted
}
#[test]
fn test_chown_owner_group() {
// test chown username:group file.txt
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd("whoami").run();
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
return;
}
let user_name = String::from(result.stdout_str().trim());
assert!(!user_name.is_empty());
let file1 = "test_chown_file1";
at.touch(file1);
let result = scene.cmd("id").arg("-gn").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
if skipping_test_is_okay(&result, "id: cannot find name for group ID") {
return;
}
println!("group name = {}", result.stdout_str());
let group = result.stdout_str().trim_end();
let group_name = String::from(result.stdout_str().trim());
assert!(!group_name.is_empty());
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
let perm = username.to_owned() + ":" + group;
at.touch(file1);
let result = ucmd.arg(perm).arg(file1).run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains("chown: invalid group:") {
// With some Ubuntu into the CI, we can get this answer
let result = scene
.ucmd()
.arg(format!("{}:{}", user_name, group_name))
.arg("--verbose")
.arg(file1)
.run();
if skipping_test_is_okay(&result, "chown: invalid group:") {
return;
}
assert!(result.success);
result.stderr_contains(&"retained as");
// TODO: on macos group name is not recognized correctly: "chown: invalid group: 'root:root'
#[cfg(any(windows, all(unix, not(target_os = "macos"))))]
scene
.ucmd()
.arg("root:root")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
// TODO: on macos group name is not recognized correctly: "chown: invalid group: ':groupname'
#[cfg(any(windows, all(unix, not(target_os = "macos"))))]
fn test_chown_only_group() {
// test chown :group file.txt
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
return;
}
println!("results {}", result.stdout_str());
let user_name = String::from(result.stdout_str().trim());
assert!(!user_name.is_empty());
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
let perm = ":".to_owned() + result.stdout_str().trim_end();
let file1 = "test_chown_file1";
at.touch(file1);
let result = ucmd.arg(perm).arg(file1).run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let result = scene
.ucmd()
.arg(format!(":{}", user_name))
.arg("--verbose")
.arg(file1)
.run();
if is_ci() && result.stderr_str().contains("Operation not permitted") {
// With ubuntu with old Rust in the CI, we can get an error
return;
@ -167,221 +272,232 @@ fn test_chown_only_group() {
// With mac into the CI, we can get this answer
return;
}
assert!(result.success);
result.stderr_contains(&"retained as");
result.success();
scene
.ucmd()
.arg(":root")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
fn test_chown_only_id() {
fn test_chown_only_user_id() {
// test chown 1111 file.txt
let result = TestScenario::new("id").ucmd_keepenv().arg("-u").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd_keepenv("id").arg("-u").run();
if skipping_test_is_okay(&result, "id: cannot find name for group ID") {
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let id = String::from(result.stdout_str().trim());
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
let user_id = String::from(result.stdout_str().trim());
assert!(!user_id.is_empty());
let file1 = "test_chown_file1";
at.touch(file1);
let result = ucmd.arg(id).arg(file1).run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains("chown: invalid user:") {
// With some Ubuntu into the CI, we can get this answer
let result = scene.ucmd().arg(user_id).arg("--verbose").arg(file1).run();
if skipping_test_is_okay(&result, "invalid user") {
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
// stderr: "chown: invalid user: '1001'
return;
}
assert!(result.success);
result.stderr_contains(&"retained as");
scene
.ucmd()
.arg("0")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
fn test_chown_only_group_id() {
// test chown :1111 file.txt
let result = TestScenario::new("id").ucmd_keepenv().arg("-g").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd_keepenv("id").arg("-g").run();
if skipping_test_is_okay(&result, "id: cannot find name for group ID") {
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let id = String::from(result.stdout_str().trim());
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
let group_id = String::from(result.stdout_str().trim());
assert!(!group_id.is_empty());
let file1 = "test_chown_file1";
at.touch(file1);
let perm = ":".to_owned() + &id;
let result = ucmd.arg(perm).arg(file1).run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains("chown: invalid group:") {
let result = scene
.ucmd()
.arg(format!(":{}", group_id))
.arg("--verbose")
.arg(file1)
.run();
if skipping_test_is_okay(&result, "chown: invalid group:") {
// With mac into the CI, we can get this answer
return;
}
assert!(result.success);
result.stderr_contains(&"retained as");
// Apparently on CI "macos-latest, x86_64-apple-darwin, feat_os_macos"
// the process has the rights to change from runner:staff to runner:wheel
#[cfg(any(windows, all(unix, not(target_os = "macos"))))]
scene
.ucmd()
.arg(":0")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
fn test_chown_both_id() {
fn test_chown_owner_group_id() {
// test chown 1111:1111 file.txt
let result = TestScenario::new("id").ucmd_keepenv().arg("-u").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd_keepenv("id").arg("-u").run();
if skipping_test_is_okay(&result, "id: cannot find name for group ID") {
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let id_user = String::from(result.stdout_str().trim());
let user_id = String::from(result.stdout_str().trim());
assert!(!user_id.is_empty());
let result = TestScenario::new("id").ucmd_keepenv().arg("-g").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let result = scene.cmd_keepenv("id").arg("-g").run();
if skipping_test_is_okay(&result, "id: cannot find name for group ID") {
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let id_group = String::from(result.stdout_str().trim());
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
let group_id = String::from(result.stdout_str().trim());
assert!(!group_id.is_empty());
let file1 = "test_chown_file1";
at.touch(file1);
let perm = id_user + &":".to_owned() + &id_group;
let result = ucmd.arg(perm).arg(file1).run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains("invalid user") {
// In the CI, some server are failing to return id.
// As seems to be a configuration issue, ignoring it
let result = scene
.ucmd()
.arg(format!("{}:{}", user_id, group_id))
.arg("--verbose")
.arg(file1)
.run();
if skipping_test_is_okay(&result, "invalid user") {
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
// stderr: "chown: invalid user: '1001:116'
return;
}
result.stderr_contains(&"retained as");
assert!(result.success);
scene
.ucmd()
.arg("0:0")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
fn test_chown_both_mix() {
// test chown 1111:1111 file.txt
let result = TestScenario::new("id").ucmd_keepenv().arg("-u").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let id_user = String::from(result.stdout_str().trim());
fn test_chown_owner_group_mix() {
// test chown 1111:group file.txt
let result = TestScenario::new("id").ucmd_keepenv().arg("-gn").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd_keepenv("id").arg("-u").run();
if skipping_test_is_okay(&result, "id: cannot find name for group ID") {
return;
}
let user_id = String::from(result.stdout_str().trim());
assert!(!user_id.is_empty());
let result = scene.cmd_keepenv("id").arg("-gn").run();
if skipping_test_is_okay(&result, "id: cannot find name for group ID") {
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let group_name = String::from(result.stdout_str().trim());
assert!(!group_name.is_empty());
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "test_install_target_dir_file_a1";
let file1 = "test_chown_file1";
at.touch(file1);
let perm = id_user + &":".to_owned() + &group_name;
let result = ucmd.arg(perm).arg(file1).run();
let result = scene
.ucmd()
.arg(format!("{}:{}", user_id, group_name))
.arg("--verbose")
.arg(file1)
.run();
result.stderr_contains(&"retained as");
if is_ci() && result.stderr_str().contains("invalid user") {
// In the CI, some server are failing to return id.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
// TODO: on macos group name is not recognized correctly: "chown: invalid group: '0:root'
#[cfg(any(windows, all(unix, not(target_os = "macos"))))]
scene
.ucmd()
.arg("0:root")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"failed to change");
}
#[test]
fn test_chown_recursive() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let username = result.stdout_str().trim_end();
let user_name = String::from(result.stdout_str().trim());
assert!(!user_name.is_empty());
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("a");
at.mkdir("a/b");
at.mkdir("a/b/c");
at.mkdir_all("a/b/c");
at.mkdir("z");
at.touch(&at.plus_as_string("a/a"));
at.touch(&at.plus_as_string("a/b/b"));
at.touch(&at.plus_as_string("a/b/c/c"));
at.touch(&at.plus_as_string("z/y"));
let result = ucmd
let result = scene
.ucmd()
.arg("-R")
.arg("--verbose")
.arg(username)
.arg(user_name)
.arg("a")
.arg("z")
.run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains("invalid user") {
// In the CI, some server are failing to return id.
// As seems to be a configuration issue, ignoring it
return;
}
result
.stderr_contains(&"ownership of 'a/a' retained as")
.stderr_contains(&"ownership of 'z/y' retained as")
.success();
result.stderr_contains(&"ownership of 'a/a' retained as");
result.stderr_contains(&"ownership of 'z/y' retained as");
}
#[test]
fn test_root_preserve() {
let scene = TestScenario::new(util_name!());
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
return;
}
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let username = result.stdout_str().trim_end();
let user_name = String::from(result.stdout_str().trim());
assert!(!user_name.is_empty());
let result = new_ucmd!()
let result = scene
.ucmd()
.arg("--preserve-root")
.arg("-R")
.arg(username)
.arg(user_name)
.arg("/")
.fails();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains("invalid user") {
// In the CI, some server are failing to return id.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result
.stderr
.contains("chown: it is dangerous to operate recursively"));
result.stderr_contains(&"chown: it is dangerous to operate recursively");
}
#[cfg(target_os = "linux")]
@ -393,8 +509,34 @@ fn test_big_p() {
.arg("bin")
.arg("/proc/self/cwd")
.fails()
.stderr_is(
"chown: changing ownership of '/proc/self/cwd': Operation not permitted (os error 1)\n",
.stderr_contains(
"chown: changing ownership of '/proc/self/cwd': Operation not permitted (os error 1)",
);
}
}
#[test]
fn test_chown_file_notexisting() {
// test chown username not_existing
let scene = TestScenario::new(util_name!());
let result = scene.cmd("whoami").run();
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
return;
}
let user_name = String::from(result.stdout_str().trim());
assert!(!user_name.is_empty());
let _result = scene
.ucmd()
.arg(user_name)
.arg("--verbose")
.arg("not_existing")
.fails();
// TODO: uncomment once "failed to change ownership of '{}' to {}" added to stdout
// result.stderr_contains(&"retained as");
// TODO: uncomment once message changed from "cannot dereference" to "cannot access"
// result.stderr_contains(&"cannot access 'not_existing': No such file or directory");
}

View file

@ -4,14 +4,11 @@ use crate::common::util::*;
fn test_missing_operand() {
let result = new_ucmd!().run();
assert_eq!(
true,
result
.stderr
.starts_with("error: The following required arguments were not provided")
);
assert!(result
.stderr_str()
.starts_with("error: The following required arguments were not provided"));
assert_eq!(true, result.stderr.contains("<newroot>"));
assert!(result.stderr_str().contains("<newroot>"));
}
#[test]
@ -20,14 +17,11 @@ fn test_enter_chroot_fails() {
at.mkdir("jail");
let result = ucmd.arg("jail").run();
let result = ucmd.arg("jail").fails();
assert_eq!(
true,
result.stderr.starts_with(
"chroot: error: cannot chroot to jail: Operation not permitted (os error 1)"
)
)
assert!(result
.stderr_str()
.starts_with("chroot: error: cannot chroot to jail: Operation not permitted (os error 1)"));
}
#[test]
@ -47,19 +41,18 @@ fn test_invalid_user_spec() {
at.mkdir("a");
let result = ucmd.arg("a").arg("--userspec=ARABA:").run();
let result = ucmd.arg("a").arg("--userspec=ARABA:").fails();
assert_eq!(
true,
result.stderr.starts_with("chroot: error: invalid userspec")
);
assert!(result
.stderr_str()
.starts_with("chroot: error: invalid userspec"));
}
#[test]
fn test_preference_of_userspec() {
let scene = TestScenario::new(util_name!());
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr.contains("No such user/group") {
if is_ci() && result.stderr_str().contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
return;
@ -73,7 +66,7 @@ fn test_preference_of_userspec() {
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr.contains("cannot find name for user ID") {
if is_ci() && result.stderr_str().contains("cannot find name for user ID") {
// In the CI, some server are failing to return id.
// As seems to be a configuration issue, ignoring it
return;

View file

@ -31,7 +31,10 @@ fn test_empty() {
at.touch("a");
ucmd.arg("a").succeeds().stdout.ends_with("0 a");
ucmd.arg("a")
.succeeds()
.no_stderr()
.normalized_newlines_stdout_is("4294967295 0 a\n");
}
#[test]
@ -41,36 +44,37 @@ fn test_arg_overrides_stdin() {
at.touch("a");
let result = ucmd
.arg("a")
ucmd.arg("a")
.pipe_in(input.as_bytes())
// the command might have exited before all bytes have been pipe in.
// in that case, we don't care about the error (broken pipe)
.ignore_stdin_write_error()
.run();
println!("{}, {}", result.stdout, result.stderr);
assert!(result.stdout.ends_with("0 a\n"))
.succeeds()
.no_stderr()
.normalized_newlines_stdout_is("4294967295 0 a\n");
}
#[test]
fn test_invalid_file() {
let (_, mut ucmd) = at_and_ucmd!();
let ts = TestScenario::new(util_name!());
let at = ts.fixtures.clone();
let ls = TestScenario::new("ls");
let files = ls.cmd("ls").arg("-l").run();
println!("{:?}", files.stdout);
println!("{:?}", files.stderr);
let folder_name = "asdf";
let folder_name = "asdf".to_string();
// First check when file doesn't exist
ts.ucmd()
.arg(folder_name)
.fails()
.no_stdout()
.stderr_contains("cksum: error: 'asdf' No such file or directory");
let result = ucmd.arg(&folder_name).run();
println!("stdout: {:?}", result.stdout);
println!("stderr: {:?}", result.stderr);
assert!(result.stderr.contains("cksum: error: 'asdf'"));
assert!(!result.success);
// Then check when the file is of an invalid type
at.mkdir(folder_name);
ts.ucmd()
.arg(folder_name)
.fails()
.no_stdout()
.stderr_contains("cksum: error: 'asdf' Is a directory");
}
// Make sure crc is correct for files larger than 32 bytes
@ -79,14 +83,13 @@ fn test_invalid_file() {
fn test_crc_for_bigger_than_32_bytes() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("chars.txt").run();
let result = ucmd.arg("chars.txt").succeeds();
let mut stdout_splitted = result.stdout.split(" ");
let mut stdout_splitted = result.stdout_str().split(" ");
let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap();
assert!(result.success);
assert_eq!(cksum, 586047089);
assert_eq!(bytes_cnt, 16);
}
@ -95,14 +98,13 @@ fn test_crc_for_bigger_than_32_bytes() {
fn test_stdin_larger_than_128_bytes() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("larger_than_2056_bytes.txt").run();
let result = ucmd.arg("larger_than_2056_bytes.txt").succeeds();
let mut stdout_splitted = result.stdout.split(" ");
let mut stdout_splitted = result.stdout_str().split(" ");
let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap();
assert!(result.success);
assert_eq!(cksum, 945881979);
assert_eq!(bytes_cnt, 2058);
}

View file

@ -42,13 +42,9 @@ static TEST_MOUNT_OTHER_FILESYSTEM_FILE: &str = "mount/DO_NOT_copy_me.txt";
fn test_cp_cp() {
let (at, mut ucmd) = at_and_ucmd!();
// Invoke our binary to make the copy.
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HELLO_WORLD_DEST)
.run();
// Check that the exit code represents a successful copy.
assert!(result.success);
.succeeds();
// Check the content of the destination file that was copied.
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
@ -57,12 +53,9 @@ fn test_cp_cp() {
#[test]
fn test_cp_existing_target() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_EXISTING_FILE)
.run();
assert!(result.success);
.succeeds();
// Check the content of the destination file
assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n");
@ -74,52 +67,41 @@ fn test_cp_existing_target() {
#[test]
fn test_cp_duplicate_files() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_COPY_TO_FOLDER)
.run();
assert!(result.success);
assert!(result.stderr.contains("specified more than once"));
.succeeds()
.stderr_contains("specified more than once");
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
}
#[test]
fn test_cp_multiple_files_target_is_file() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_EXISTING_FILE)
.run();
assert!(!result.success);
assert!(result.stderr.contains("not a directory"));
.fails()
.stderr_contains("not a directory");
}
#[test]
fn test_cp_directory_not_recursive() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg(TEST_COPY_TO_FOLDER)
.arg(TEST_HELLO_WORLD_DEST)
.run();
assert!(!result.success);
assert!(result.stderr.contains("omitting directory"));
.fails()
.stderr_contains("omitting directory");
}
#[test]
fn test_cp_multiple_files() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HOW_ARE_YOU_SOURCE)
.arg(TEST_COPY_TO_FOLDER)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
assert_eq!(at.read(TEST_HOW_ARE_YOU_DEST), "How are you?\n");
}
@ -129,14 +111,11 @@ fn test_cp_multiple_files() {
#[cfg(not(macos))]
fn test_cp_recurse() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg("-r")
ucmd.arg("-r")
.arg(TEST_COPY_FROM_FOLDER)
.arg(TEST_COPY_TO_FOLDER_NEW)
.run();
.succeeds();
assert!(result.success);
// Check the content of the destination file that was copied.
assert_eq!(at.read(TEST_COPY_TO_FOLDER_NEW_FILE), "Hello, World!\n");
}
@ -144,14 +123,10 @@ fn test_cp_recurse() {
#[test]
fn test_cp_with_dirs_t() {
let (at, mut ucmd) = at_and_ucmd!();
//using -t option
let result_to_dir_t = ucmd
.arg("-t")
ucmd.arg("-t")
.arg(TEST_COPY_TO_FOLDER)
.arg(TEST_HELLO_WORLD_SOURCE)
.run();
assert!(result_to_dir_t.success);
.succeeds();
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
}
@ -162,63 +137,52 @@ fn test_cp_with_dirs() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
//using -t option
let result_to_dir = scene
scene
.ucmd()
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_COPY_TO_FOLDER)
.run();
assert!(result_to_dir.success);
.succeeds();
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
let result_from_dir = scene
scene
.ucmd()
.arg(TEST_COPY_FROM_FOLDER_FILE)
.arg(TEST_HELLO_WORLD_DEST)
.run();
assert!(result_from_dir.success);
.succeeds();
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
}
#[test]
fn test_cp_arg_target_directory() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("-t")
.arg(TEST_COPY_TO_FOLDER)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
}
#[test]
fn test_cp_arg_no_target_directory() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg(TEST_HELLO_WORLD_SOURCE)
.arg("-v")
.arg("-T")
.arg(TEST_COPY_TO_FOLDER)
.run();
assert!(!result.success);
assert!(result.stderr.contains("cannot overwrite directory"));
.fails()
.stderr_contains("cannot overwrite directory");
}
#[test]
fn test_cp_arg_interactive() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HOW_ARE_YOU_SOURCE)
.arg("-i")
.pipe_in("N\n")
.run();
assert!(result.success);
assert!(result.stderr.contains("Not overwriting"));
.succeeds()
.stderr_contains("Not overwriting");
}
#[test]
@ -227,39 +191,33 @@ fn test_cp_arg_link() {
use std::os::linux::fs::MetadataExt;
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--link")
.arg(TEST_HELLO_WORLD_DEST)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.metadata(TEST_HELLO_WORLD_SOURCE).st_nlink(), 2);
}
#[test]
fn test_cp_arg_symlink() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--symbolic-link")
.arg(TEST_HELLO_WORLD_DEST)
.run();
.succeeds();
assert!(result.success);
assert!(at.is_symlink(TEST_HELLO_WORLD_DEST));
}
#[test]
fn test_cp_arg_no_clobber() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--no-clobber")
.arg(TEST_HOW_ARE_YOU_SOURCE)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "How are you?\n");
}
@ -267,34 +225,31 @@ fn test_cp_arg_no_clobber() {
fn test_cp_arg_no_clobber_twice() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("source.txt");
let result = scene
scene
.ucmd()
.arg("--no-clobber")
.arg("source.txt")
.arg("dest.txt")
.run();
.succeeds()
.no_stderr();
println!("stderr = {:?}", result.stderr_str());
println!("stdout = {:?}", result.stdout_str());
assert!(result.success);
assert!(result.stderr.is_empty());
assert_eq!(at.read("source.txt"), "");
at.append("source.txt", "some-content");
let result = scene
scene
.ucmd()
.arg("--no-clobber")
.arg("source.txt")
.arg("dest.txt")
.run();
.succeeds()
.stdout_does_not_contain("Not overwriting");
assert!(result.success);
assert_eq!(at.read("source.txt"), "some-content");
// Should be empty as the "no-clobber" should keep
// the previous version
assert_eq!(at.read("dest.txt"), "");
assert!(!result.stderr.contains("Not overwriting"));
}
#[test]
@ -311,16 +266,11 @@ fn test_cp_arg_force() {
permissions.set_readonly(true);
set_permissions(at.plus(TEST_HELLO_WORLD_DEST), permissions).unwrap();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--force")
.arg(TEST_HELLO_WORLD_DEST)
.run();
.succeeds();
println!("{:?}", result.stderr_str());
println!("{:?}", result.stdout_str());
assert!(result.success);
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
}
@ -342,13 +292,11 @@ fn test_cp_arg_remove_destination() {
permissions.set_readonly(true);
set_permissions(at.plus(TEST_HELLO_WORLD_DEST), permissions).unwrap();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--remove-destination")
.arg(TEST_HELLO_WORLD_DEST)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
}
@ -356,13 +304,11 @@ fn test_cp_arg_remove_destination() {
fn test_cp_arg_backup() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--backup")
.arg(TEST_HOW_ARE_YOU_SOURCE)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
assert_eq!(
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
@ -374,14 +320,12 @@ fn test_cp_arg_backup() {
fn test_cp_arg_suffix() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--suffix")
.arg(".bak")
.arg(TEST_HOW_ARE_YOU_SOURCE)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
assert_eq!(
at.read(&*format!("{}.bak", TEST_HOW_ARE_YOU_SOURCE)),
@ -391,9 +335,8 @@ fn test_cp_arg_suffix() {
#[test]
fn test_cp_deref_conflicting_options() {
let (_at, mut ucmd) = at_and_ucmd!();
ucmd.arg("-LP")
new_ucmd!()
.arg("-LP")
.arg(TEST_COPY_TO_FOLDER)
.arg(TEST_HELLO_WORLD_SOURCE)
.fails();
@ -401,8 +344,7 @@ fn test_cp_deref_conflicting_options() {
#[test]
fn test_cp_deref() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let (at, mut ucmd) = at_and_ucmd!();
#[cfg(not(windows))]
let _r = fs::symlink(
@ -415,16 +357,12 @@ fn test_cp_deref() {
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
);
//using -L option
let result = scene
.ucmd()
.arg("-L")
ucmd.arg("-L")
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HELLO_WORLD_SOURCE_SYMLINK)
.arg(TEST_COPY_TO_FOLDER)
.run();
.succeeds();
// Check that the exit code represents a successful copy.
assert!(result.success);
let path_to_new_symlink = at
.subdir
.join(TEST_COPY_TO_FOLDER)
@ -444,8 +382,7 @@ fn test_cp_deref() {
}
#[test]
fn test_cp_no_deref() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let (at, mut ucmd) = at_and_ucmd!();
#[cfg(not(windows))]
let _r = fs::symlink(
@ -458,16 +395,12 @@ fn test_cp_no_deref() {
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
);
//using -P option
let result = scene
.ucmd()
.arg("-P")
ucmd.arg("-P")
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_HELLO_WORLD_SOURCE_SYMLINK)
.arg(TEST_COPY_TO_FOLDER)
.run();
.succeeds();
// Check that the exit code represents a successful copy.
assert!(result.success);
let path_to_new_symlink = at
.subdir
.join(TEST_COPY_TO_FOLDER)
@ -490,14 +423,10 @@ fn test_cp_strip_trailing_slashes() {
let (at, mut ucmd) = at_and_ucmd!();
//using --strip-trailing-slashes option
let result = ucmd
.arg("--strip-trailing-slashes")
ucmd.arg("--strip-trailing-slashes")
.arg(format!("{}/", TEST_HELLO_WORLD_SOURCE))
.arg(TEST_HELLO_WORLD_DEST)
.run();
// Check that the exit code represents a successful copy.
assert!(result.success);
.succeeds();
// Check the content of the destination file that was copied.
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
@ -507,14 +436,11 @@ fn test_cp_strip_trailing_slashes() {
fn test_cp_parents() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg("--parents")
ucmd.arg("--parents")
.arg(TEST_COPY_FROM_FOLDER_FILE)
.arg(TEST_COPY_TO_FOLDER)
.run();
.succeeds();
assert!(result.success);
// Check the content of the destination file that was copied.
assert_eq!(
at.read(&format!(
"{}/{}",
@ -528,14 +454,12 @@ fn test_cp_parents() {
fn test_cp_parents_multiple_files() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg("--parents")
ucmd.arg("--parents")
.arg(TEST_COPY_FROM_FOLDER_FILE)
.arg(TEST_HOW_ARE_YOU_SOURCE)
.arg(TEST_COPY_TO_FOLDER)
.run();
.succeeds();
assert!(result.success);
assert_eq!(
at.read(&format!(
"{}/{}",
@ -554,20 +478,12 @@ fn test_cp_parents_multiple_files() {
#[test]
fn test_cp_parents_dest_not_directory() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg("--parents")
.arg(TEST_COPY_FROM_FOLDER_FILE)
.arg(TEST_HELLO_WORLD_DEST)
.run();
println!("{:?}", result);
// Check that we did not succeed in copying.
assert!(!result.success);
assert!(result
.stderr
.contains("with --parents, the destination must be a directory"));
.fails()
.stderr_contains("with --parents, the destination must be a directory");
}
#[test]
@ -594,18 +510,14 @@ fn test_cp_deref_folder_to_folder() {
assert!(env::set_current_dir(&cwd).is_ok());
//using -P -R option
let result = scene
scene
.ucmd()
.arg("-L")
.arg("-R")
.arg("-v")
.arg(TEST_COPY_FROM_FOLDER)
.arg(TEST_COPY_TO_FOLDER_NEW)
.run();
println!("cp output {}", result.stdout_str());
// Check that the exit code represents a successful copy.
assert!(result.success);
.succeeds();
#[cfg(not(windows))]
{
@ -698,18 +610,14 @@ fn test_cp_no_deref_folder_to_folder() {
assert!(env::set_current_dir(&cwd).is_ok());
//using -P -R option
let result = scene
scene
.ucmd()
.arg("-P")
.arg("-R")
.arg("-v")
.arg(TEST_COPY_FROM_FOLDER)
.arg(TEST_COPY_TO_FOLDER_NEW)
.run();
println!("cp output {}", result.stdout_str());
// Check that the exit code represents a successful copy.
assert!(result.success);
.succeeds();
#[cfg(not(windows))]
{
@ -791,13 +699,11 @@ fn test_cp_archive() {
previous,
)
.unwrap();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--archive")
.arg(TEST_HOW_ARE_YOU_SOURCE)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
let metadata = std_fs::metadata(at.subdir.join(TEST_HELLO_WORLD_SOURCE)).unwrap();
@ -807,11 +713,10 @@ fn test_cp_archive() {
let creation2 = metadata2.modified().unwrap();
let scene2 = TestScenario::new("ls");
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).run();
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).succeeds();
println!("ls dest {}", result.stdout_str());
assert_eq!(creation, creation2);
assert!(result.success);
}
#[test]
@ -850,11 +755,10 @@ fn test_cp_archive_recursive() {
// Back to the initial cwd (breaks the other tests)
assert!(env::set_current_dir(&cwd).is_ok());
let resultg = ucmd
.arg("--archive")
ucmd.arg("--archive")
.arg(TEST_COPY_TO_FOLDER)
.arg(TEST_COPY_TO_FOLDER_NEW)
.run();
.fails(); // fails for now
let scene2 = TestScenario::new("ls");
let result = scene2
@ -865,7 +769,6 @@ fn test_cp_archive_recursive() {
println!("ls dest {}", result.stdout_str());
let scene2 = TestScenario::new("ls");
let result = scene2
.cmd("ls")
.arg("-al")
@ -910,9 +813,6 @@ fn test_cp_archive_recursive() {
.join("2.link")
.to_string_lossy()
));
// fails for now
assert!(resultg.success);
}
#[test]
@ -928,13 +828,11 @@ fn test_cp_preserve_timestamps() {
previous,
)
.unwrap();
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--preserve=timestamps")
.arg(TEST_HOW_ARE_YOU_SOURCE)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
let metadata = std_fs::metadata(at.subdir.join(TEST_HELLO_WORLD_SOURCE)).unwrap();
@ -948,7 +846,6 @@ fn test_cp_preserve_timestamps() {
println!("ls dest {}", result.stdout_str());
assert_eq!(creation, creation2);
assert!(result.success);
}
#[test]
@ -966,13 +863,11 @@ fn test_cp_dont_preserve_timestamps() {
.unwrap();
sleep(Duration::from_secs(3));
let result = ucmd
.arg(TEST_HELLO_WORLD_SOURCE)
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
.arg("--no-preserve=timestamps")
.arg(TEST_HOW_ARE_YOU_SOURCE)
.run();
.succeeds();
assert!(result.success);
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
let metadata = std_fs::metadata(at.subdir.join(TEST_HELLO_WORLD_SOURCE)).unwrap();
@ -992,7 +887,6 @@ fn test_cp_dont_preserve_timestamps() {
// Some margins with time check
assert!(res.as_secs() > 3595);
assert!(res.as_secs() < 3605);
assert!(result.success);
}
#[test]
@ -1017,7 +911,7 @@ fn test_cp_one_file_system() {
let scene = TestScenario::new(util_name!());
// Test must be run as root (or with `sudo -E`)
if scene.cmd("whoami").run().stdout != "root\n" {
if scene.cmd("whoami").run().stdout_str() != "root\n" {
return;
}
@ -1029,7 +923,7 @@ fn test_cp_one_file_system() {
at_src.mkdir(TEST_MOUNT_MOUNTPOINT);
let mountpoint_path = &at_src.plus_as_string(TEST_MOUNT_MOUNTPOINT);
let _r = scene
scene
.cmd("mount")
.arg("-t")
.arg("tmpfs")
@ -1037,24 +931,21 @@ fn test_cp_one_file_system() {
.arg("size=640k") // ought to be enough
.arg("tmpfs")
.arg(mountpoint_path)
.run();
assert!(_r.code == Some(0), "{}", _r.stderr);
.succeeds();
at_src.touch(TEST_MOUNT_OTHER_FILESYSTEM_FILE);
// Begin testing -x flag
let result = scene
scene
.ucmd()
.arg("-rx")
.arg(TEST_MOUNT_COPY_FROM_FOLDER)
.arg(TEST_COPY_TO_FOLDER_NEW)
.run();
.succeeds();
// Ditch the mount before the asserts
let _r = scene.cmd("umount").arg(mountpoint_path).run();
assert!(_r.code == Some(0), "{}", _r.stderr);
scene.cmd("umount").arg(mountpoint_path).succeeds();
assert!(result.success);
assert!(!at_dst.file_exists(TEST_MOUNT_OTHER_FILESYSTEM_FILE));
// Check if the other files were copied from the source folder hirerarchy
for entry in WalkDir::new(at_src.as_string()) {
@ -1074,3 +965,59 @@ fn test_cp_one_file_system() {
}
}
}
#[test]
#[cfg(target_os = "linux")]
fn test_cp_reflink_always() {
let (at, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg("--reflink=always")
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_EXISTING_FILE)
.run();
if result.success {
// Check the content of the destination file
assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n");
} else {
// Older Linux versions do not support cloning.
}
}
#[test]
#[cfg(target_os = "linux")]
fn test_cp_reflink_auto() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("--reflink=auto")
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_EXISTING_FILE)
.succeeds();
// Check the content of the destination file
assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n");
}
#[test]
#[cfg(target_os = "linux")]
fn test_cp_reflink_never() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("--reflink=never")
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_EXISTING_FILE)
.succeeds();
// Check the content of the destination file
assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n");
}
#[test]
#[cfg(target_os = "linux")]
fn test_cp_reflink_bad() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
.arg("--reflink=bad")
.arg(TEST_HELLO_WORLD_SOURCE)
.arg(TEST_EXISTING_FILE)
.fails()
.stderr_contains("invalid argument");
}

View file

@ -7,174 +7,147 @@ use rust_users::*;
#[test]
fn test_date_email() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--rfc-email").run();
assert!(result.success);
new_ucmd!().arg("--rfc-email").succeeds();
}
#[test]
fn test_date_email2() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-R").run();
assert!(result.success);
new_ucmd!().arg("-R").succeeds();
}
#[test]
fn test_date_rfc_3339() {
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("--rfc-3339=ns").succeeds();
let rfc_regexp = concat!(
r#"(\d+)-(0[1-9]|1[012])-(0[1-9]|[12]\d|3[01])\s([01]\d|2[0-3]):"#,
r#"([0-5]\d):([0-5]\d|60)(\.\d+)?(([Zz])|([\+|\-]([01]\d|2[0-3])))"#
);
let re = Regex::new(rfc_regexp).unwrap();
// Check that the output matches the regexp
let rfc_regexp = r"(\d+)-(0[1-9]|1[012])-(0[1-9]|[12]\d|3[01])\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d|60)(\.\d+)?(([Zz])|([\+|\-]([01]\d|2[0-3])))";
let re = Regex::new(rfc_regexp).unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene
.ucmd()
.arg("--rfc-3339=ns")
.succeeds()
.stdout_matches(&re);
result = scene.ucmd().arg("--rfc-3339=seconds").succeeds();
// Check that the output matches the regexp
let re = Regex::new(rfc_regexp).unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene
.ucmd()
.arg("--rfc-3339=seconds")
.succeeds()
.stdout_matches(&re);
}
#[test]
fn test_date_rfc_8601() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--iso-8601=ns").run();
assert!(result.success);
new_ucmd!().arg("--iso-8601=ns").succeeds();
}
#[test]
fn test_date_rfc_8601_second() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--iso-8601=second").run();
assert!(result.success);
new_ucmd!().arg("--iso-8601=second").succeeds();
}
#[test]
fn test_date_utc() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--utc").run();
assert!(result.success);
new_ucmd!().arg("--utc").succeeds();
}
#[test]
fn test_date_universal() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--universal").run();
assert!(result.success);
new_ucmd!().arg("--universal").succeeds();
}
#[test]
fn test_date_format_y() {
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("+%Y").succeeds();
assert!(result.success);
let mut re = Regex::new(r"^\d{4}$").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene.ucmd().arg("+%Y").succeeds().stdout_matches(&re);
result = scene.ucmd().arg("+%y").succeeds();
assert!(result.success);
re = Regex::new(r"^\d{2}$").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene.ucmd().arg("+%y").succeeds().stdout_matches(&re);
}
#[test]
fn test_date_format_m() {
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("+%b").succeeds();
assert!(result.success);
let mut re = Regex::new(r"\S+").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene.ucmd().arg("+%b").succeeds().stdout_matches(&re);
result = scene.ucmd().arg("+%m").succeeds();
assert!(result.success);
re = Regex::new(r"^\d{2}$").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene.ucmd().arg("+%m").succeeds().stdout_matches(&re);
}
#[test]
fn test_date_format_day() {
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("+%a").succeeds();
assert!(result.success);
let mut re = Regex::new(r"\S+").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
result = scene.ucmd().arg("+%A").succeeds();
assert!(result.success);
scene.ucmd().arg("+%a").succeeds().stdout_matches(&re);
re = Regex::new(r"\S+").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene.ucmd().arg("+%A").succeeds().stdout_matches(&re);
result = scene.ucmd().arg("+%u").succeeds();
assert!(result.success);
re = Regex::new(r"^\d{1}$").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
scene.ucmd().arg("+%u").succeeds().stdout_matches(&re);
}
#[test]
fn test_date_format_full_day() {
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("+'%a %Y-%m-%d'").succeeds();
assert!(result.success);
let re = Regex::new(r"\S+ \d{4}-\d{2}-\d{2}").unwrap();
assert!(re.is_match(&result.stdout_str().trim()));
new_ucmd!()
.arg("+'%a %Y-%m-%d'")
.succeeds()
.stdout_matches(&re);
}
#[test]
#[cfg(all(unix, not(target_os = "macos")))]
fn test_date_set_valid() {
if get_effective_uid() == 0 {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg("--set")
.arg("2020-03-12 13:30:00+08:00")
.succeeds();
result.no_stdout().no_stderr();
.succeeds()
.no_stdout()
.no_stderr();
}
}
#[test]
#[cfg(any(windows, all(unix, not(target_os = "macos"))))]
fn test_date_set_invalid() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--set").arg("123abcd").fails();
let result = result.no_stdout();
assert!(result.stderr.starts_with("date: invalid date "));
let result = new_ucmd!().arg("--set").arg("123abcd").fails();
result.no_stdout();
assert!(result.stderr_str().starts_with("date: invalid date "));
}
#[test]
#[cfg(all(unix, not(target_os = "macos")))]
fn test_date_set_permissions_error() {
if !(get_effective_uid() == 0 || uucore::os::is_wsl_1()) {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--set").arg("2020-03-11 21:45:00+08:00").fails();
let result = result.no_stdout();
assert!(result.stderr.starts_with("date: cannot set date: "));
let result = new_ucmd!()
.arg("--set")
.arg("2020-03-11 21:45:00+08:00")
.fails();
result.no_stdout();
assert!(result.stderr_str().starts_with("date: cannot set date: "));
}
}
#[test]
#[cfg(target_os = "macos")]
fn test_date_set_mac_unavailable() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--set").arg("2020-03-11 21:45:00+08:00").fails();
let result = result.no_stdout();
let result = new_ucmd!()
.arg("--set")
.arg("2020-03-11 21:45:00+08:00")
.fails();
result.no_stdout();
assert!(result
.stderr
.stderr_str()
.starts_with("date: setting the date is not supported by macOS"));
}
@ -183,13 +156,12 @@ fn test_date_set_mac_unavailable() {
/// TODO: expected to fail currently; change to succeeds() when required.
fn test_date_set_valid_2() {
if get_effective_uid() == 0 {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
let result = new_ucmd!()
.arg("--set")
.arg("Sat 20 Mar 2021 14:53:01 AWST")
.fails();
let result = result.no_stdout();
assert!(result.stderr.starts_with("date: invalid date "));
result.no_stdout();
assert!(result.stderr_str().starts_with("date: invalid date "));
}
}
@ -198,13 +170,12 @@ fn test_date_set_valid_2() {
/// TODO: expected to fail currently; change to succeeds() when required.
fn test_date_set_valid_3() {
if get_effective_uid() == 0 {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
let result = new_ucmd!()
.arg("--set")
.arg("Sat 20 Mar 2021 14:53:01") // Local timezone
.fails();
let result = result.no_stdout();
assert!(result.stderr.starts_with("date: invalid date "));
result.no_stdout();
assert!(result.stderr_str().starts_with("date: invalid date "));
}
}
@ -213,12 +184,11 @@ fn test_date_set_valid_3() {
/// TODO: expected to fail currently; change to succeeds() when required.
fn test_date_set_valid_4() {
if get_effective_uid() == 0 {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd
let result = new_ucmd!()
.arg("--set")
.arg("2020-03-11 21:45:00") // Local timezone
.fails();
let result = result.no_stdout();
assert!(result.stderr.starts_with("date: invalid date "));
result.no_stdout();
assert!(result.stderr_str().starts_with("date: invalid date "));
}
}

View file

@ -2,30 +2,22 @@ use crate::common::util::*;
#[test]
fn test_df_compatible_no_size_arg() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-a").run();
assert!(result.success);
new_ucmd!().arg("-a").succeeds();
}
#[test]
fn test_df_compatible() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-ah").run();
assert!(result.success);
new_ucmd!().arg("-ah").succeeds();
}
#[test]
fn test_df_compatible_type() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-aT").run();
assert!(result.success);
new_ucmd!().arg("-aT").succeeds();
}
#[test]
fn test_df_compatible_si() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-aH").run();
assert!(result.success);
new_ucmd!().arg("-aH").succeeds();
}
// ToDO: more tests...

View file

@ -7,12 +7,10 @@ const SUB_LINK: &str = "subdir/links/sublink.txt";
#[test]
fn test_du_basics() {
new_ucmd!()
.succeeds()
.no_stderr();
new_ucmd!().succeeds().no_stderr();
}
#[cfg(target_vendor = "apple")]
fn _du_basics(s: String) {
fn _du_basics(s: &str) {
let answer = "32\t./subdir
8\t./subdir/deeper
24\t./subdir/links
@ -32,11 +30,18 @@ fn _du_basics(s: &str) {
#[test]
fn test_du_basics_subdir() {
let (_at, mut ucmd) = at_and_ucmd!();
let scene = TestScenario::new(util_name!());
let result = ucmd.arg(SUB_DIR).run();
assert!(result.success);
assert_eq!(result.stderr, "");
let result = scene.ucmd().arg(SUB_DIR).succeeds();
#[cfg(target_os = "linux")]
{
let result_reference = scene.cmd("du").arg(SUB_DIR).run();
if result_reference.succeeded() {
assert_eq!(result.stdout_str(), result_reference.stdout_str());
return;
}
}
_du_basics_subdir(result.stdout_str());
}
@ -60,26 +65,29 @@ fn _du_basics_subdir(s: &str) {
#[test]
fn test_du_basics_bad_name() {
let (_at, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("bad_name").run();
assert_eq!(result.stdout_str(), "");
assert_eq!(
result.stderr,
"du: error: bad_name: No such file or directory\n"
);
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");
}
#[test]
fn test_du_soft_link() {
let ts = TestScenario::new("du");
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let link = ts.ccmd("ln").arg("-s").arg(SUB_FILE).arg(SUB_LINK).run();
assert!(link.success);
at.symlink_file(SUB_FILE, SUB_LINK);
let result = ts.ucmd().arg(SUB_DIR_LINKS).run();
assert!(result.success);
assert_eq!(result.stderr, "");
let result = scene.ucmd().arg(SUB_DIR_LINKS).succeeds();
#[cfg(target_os = "linux")]
{
let result_reference = scene.cmd("du").arg(SUB_DIR_LINKS).run();
if result_reference.succeeded() {
assert_eq!(result.stdout_str(), result_reference.stdout_str());
return;
}
}
_du_soft_link(result.stdout_str());
}
@ -104,14 +112,23 @@ fn _du_soft_link(s: &str) {
#[test]
fn test_du_hard_link() {
let ts = TestScenario::new("du");
let scene = TestScenario::new(util_name!());
let link = ts.ccmd("ln").arg(SUB_FILE).arg(SUB_LINK).run();
assert!(link.success);
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();
}
let result = ts.ucmd().arg(SUB_DIR_LINKS).run();
assert!(result.success);
assert_eq!(result.stderr, "");
let result = scene.ucmd().arg(SUB_DIR_LINKS).succeeds();
#[cfg(target_os = "linux")]
{
let result_reference = scene.cmd("du").arg(SUB_DIR_LINKS).run();
if result_reference.succeeded() {
assert_eq!(result.stdout_str(), result_reference.stdout_str());
return;
}
}
// We do not double count hard links as the inodes are identical
_du_hard_link(result.stdout_str());
}
@ -136,11 +153,23 @@ fn _du_hard_link(s: &str) {
#[test]
fn test_du_d_flag() {
let ts = TestScenario::new("du");
let scene = TestScenario::new(util_name!());
let result = ts.ucmd().arg("-d").arg("1").run();
assert!(result.success);
assert_eq!(result.stderr, "");
let result = scene.ucmd().arg("-d1").succeeds();
#[cfg(target_os = "linux")]
{
let result_reference = scene.cmd("du").arg("-d1").run();
if result_reference.succeeded() {
assert_eq!(
// TODO: gnu `du` doesn't use trailing "/" here
// result.stdout_str(), result_reference.stdout_str()
result.stdout_str().trim_end_matches("/\n"),
result_reference.stdout_str().trim_end_matches("\n")
);
return;
}
}
_du_d_flag(result.stdout_str());
}
@ -164,9 +193,7 @@ fn _du_d_flag(s: &str) {
#[test]
fn test_du_h_flag_empty_file() {
let ts = TestScenario::new("du");
ts.ucmd()
new_ucmd!()
.arg("-h")
.arg("empty.txt")
.succeeds()
@ -176,17 +203,61 @@ fn test_du_h_flag_empty_file() {
#[cfg(feature = "touch")]
#[test]
fn test_du_time() {
let ts = TestScenario::new("du");
let scene = TestScenario::new(util_name!());
let touch = ts.ccmd("touch").arg("-a").arg("-m").arg("-t").arg("201505150000").arg("date_test").run();
assert!(touch.success);
scene
.ccmd("touch")
.arg("-a")
.arg("-m")
.arg("-t")
.arg("201505150000")
.arg("date_test")
.succeeds();
let result = ts.ucmd().arg("--time").arg("date_test").run();
// cleanup by removing test file
ts.cmd("rm").arg("date_test").run();
assert!(result.success);
assert_eq!(result.stderr, "");
assert_eq!(result.stdout, "0\t2015-05-15 00:00\tdate_test\n");
scene
.ucmd()
.arg("--time")
.arg("date_test")
.succeeds()
.stdout_only("0\t2015-05-15 00:00\tdate_test\n");
}
#[cfg(not(target_os = "windows"))]
#[cfg(feature = "chmod")]
#[test]
fn test_du_no_permission() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.mkdir_all(SUB_DIR_LINKS);
scene.ccmd("chmod").arg("-r").arg(SUB_DIR_LINKS).succeeds();
let result = scene.ucmd().arg(SUB_DIR_LINKS).run(); // TODO: replace with ".fails()" once `du` is fixed
result.stderr_contains(
"du: cannot read directory subdir/links: Permission denied (os error 13)",
);
#[cfg(target_os = "linux")]
{
let result_reference = scene.cmd("du").arg(SUB_DIR_LINKS).fails();
if result_reference
.stderr_str()
.contains("du: cannot read directory 'subdir/links': Permission denied")
{
assert_eq!(result.stdout_str(), result_reference.stdout_str());
return;
}
}
_du_no_permission(result.stdout_str());
}
#[cfg(target_vendor = "apple")]
fn _du_no_permission(s: &str) {
assert_eq!(s, "0\tsubdir/links\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_no_permission(s: &str) {
assert_eq!(s, "4\tsubdir/links\n");
}

View file

@ -2,10 +2,7 @@ use crate::common::util::*;
#[test]
fn test_default() {
new_ucmd!()
.arg("hi")
.succeeds()
.stdout_only("hi\n");
new_ucmd!().arg("hi").succeeds().stdout_only("hi\n");
}
#[test]

View file

@ -26,17 +26,18 @@ fn test_env_version() {
#[test]
fn test_echo() {
let result = new_ucmd!()
.arg("echo")
.arg("FOO-bar")
.succeeds();
let result = new_ucmd!().arg("echo").arg("FOO-bar").succeeds();
assert_eq!(result.stdout_str().trim(), "FOO-bar");
}
#[test]
fn test_file_option() {
let out = new_ucmd!().arg("-f").arg("vars.conf.txt").run().stdout_move_str();
let out = new_ucmd!()
.arg("-f")
.arg("vars.conf.txt")
.run()
.stdout_move_str();
assert_eq!(
out.lines()
@ -89,7 +90,8 @@ fn test_multiple_name_value_pairs() {
let out = new_ucmd!().arg("FOO=bar").arg("ABC=xyz").run();
assert_eq!(
out.stdout_str().lines()
out.stdout_str()
.lines()
.filter(|&line| line == "FOO=bar" || line == "ABC=xyz")
.count(),
2
@ -138,8 +140,11 @@ fn test_unset_variable() {
#[test]
fn test_fail_null_with_program() {
let out = new_ucmd!().arg("--null").arg("cd").fails().stderr;
assert!(out.contains("cannot specify --null (-0) with command"));
new_ucmd!()
.arg("--null")
.arg("cd")
.fails()
.stderr_contains("cannot specify --null (-0) with command");
}
#[cfg(not(windows))]

View file

@ -29,7 +29,7 @@ fn test_fmt_w_too_big() {
.run();
//.stdout_is_fixture("call_graph.expected");
assert_eq!(
result.stderr.trim(),
result.stderr_str().trim(),
"fmt: error: invalid width: '2501': Numerical result out of range"
);
}

View file

@ -542,4 +542,4 @@ fn test_obsolete_syntax() {
.arg("space_separated_words.txt")
.succeeds()
.stdout_is("test1\n \ntest2\n \ntest3\n \ntest4\n \ntest5\n \ntest6\n ");
}
}

View file

@ -10,7 +10,7 @@ fn test_groups() {
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
result.success();
assert!(!result.stdout_str().trim().is_empty());
}
@ -30,16 +30,12 @@ fn test_groups_arg() {
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
assert!(result.success);
result.success();
assert!(!result.stdout_str().is_empty());
let username = result.stdout_str().trim();
// call groups with the user name to check that we
// are getting something
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg(username).run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
assert!(result.success);
new_ucmd!().arg(username).succeeds();
assert!(!result.stdout_str().is_empty());
}

View file

@ -156,14 +156,10 @@ fn test_negative_zero_bytes() {
}
#[test]
fn test_no_such_file_or_directory() {
let result = new_ucmd!().arg("no_such_file.toml").run();
assert_eq!(
true,
result
.stderr
.contains("cannot open 'no_such_file.toml' for reading: No such file or directory")
)
new_ucmd!()
.arg("no_such_file.toml")
.fails()
.stderr_contains("cannot open 'no_such_file.toml' for reading: No such file or directory");
}
// there was a bug not caught by previous tests

View file

@ -4,10 +4,6 @@ use self::regex::Regex;
#[test]
fn test_normal() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(result.success);
let re = Regex::new(r"^[0-9a-f]{8}").unwrap();
assert!(re.is_match(&result.stdout_str()));
new_ucmd!().succeeds().stdout_matches(&re);
}

View file

@ -14,9 +14,7 @@ fn test_hostname() {
#[cfg(not(target_vendor = "apple"))]
#[test]
fn test_hostname_ip() {
let result = new_ucmd!().arg("-i").run();
println!("{:#?}", result);
assert!(result.success);
let result = new_ucmd!().arg("-i").succeeds();
assert!(!result.stdout_str().trim().is_empty());
}
@ -25,6 +23,8 @@ fn test_hostname_full() {
let ls_short_res = new_ucmd!().arg("-s").succeeds();
assert!(!ls_short_res.stdout_str().trim().is_empty());
new_ucmd!().arg("-f").succeeds()
new_ucmd!()
.arg("-f")
.succeeds()
.stdout_contains(ls_short_res.stdout_str().trim());
}

View file

@ -1,11 +1,32 @@
use crate::common::util::*;
// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
// If we are running inside the CI and "needle" is in "stderr" skipping this test is
// 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: 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
fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool {
if !result.succeeded() {
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains(needle) {
println!("test skipped:");
return true;
} else {
result.success();
}
}
false
}
fn return_whoami_username() -> String {
let scene = TestScenario::new("whoami");
let result = scene.cmd("whoami").run();
if is_ci() && result.stderr.contains("cannot find name for user ID") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
println!("test skipped:");
return String::from("");
}
@ -14,39 +35,41 @@ fn return_whoami_username() -> String {
#[test]
fn test_id() {
let result = new_ucmd!().arg("-u").run();
if result.stderr.contains("cannot find name for user ID") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-u").succeeds();
let uid = result.stdout_str().trim();
let result = scene.ucmd().run();
if skipping_test_is_okay(&result, "Could not find uid") {
return;
}
let uid = result.success().stdout_str().trim();
let result = new_ucmd!().run();
if is_ci() && result.stderr.contains("cannot find name for user ID") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
return;
}
if !result.stderr_str().contains("Could not find uid") {
// Verify that the id found by --user/-u exists in the list
result.success().stdout_contains(&uid);
}
// Verify that the id found by --user/-u exists in the list
result.stdout_contains(uid);
}
#[test]
fn test_id_from_name() {
let username = return_whoami_username();
if username == "" {
// Sometimes, the CI is failing here
if username.is_empty() {
return;
}
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg(&username).run();
if skipping_test_is_okay(&result, "Could not find uid") {
return;
}
let result = new_ucmd!().arg(&username).succeeds();
let uid = result.stdout_str().trim();
new_ucmd!().succeeds()
let result = scene.ucmd().run();
if skipping_test_is_okay(&result, "Could not find uid") {
return;
}
result
// Verify that the id found by --user/-u exists in the list
.stdout_contains(uid)
// Verify that the username found by whoami exists in the list
@ -55,51 +78,42 @@ fn test_id_from_name() {
#[test]
fn test_id_name_from_id() {
let result = new_ucmd!().arg("-u").succeeds();
let uid = result.stdout_str().trim();
let result = new_ucmd!().arg("-nu").run();
let result = new_ucmd!().arg("-nu").arg(uid).run();
if is_ci() && result.stderr.contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let username_id = result.stdout_str().trim();
let username_whoami = return_whoami_username();
if username_whoami.is_empty() {
return;
}
let username_id = result
.success()
.stdout_str()
.trim();
let scene = TestScenario::new("whoami");
let result = scene.cmd("whoami").succeeds();
let username_whoami = result.stdout_str().trim();
assert_eq!(username_id, username_whoami);
}
#[test]
fn test_id_group() {
let mut result = new_ucmd!().arg("-g").succeeds();
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("-g").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
result = new_ucmd!().arg("--group").succeeds();
result = scene.ucmd().arg("--group").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
}
#[test]
fn test_id_groups() {
let result = new_ucmd!().arg("-G").succeeds();
assert!(result.success);
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-G").succeeds();
let groups = result.stdout_str().trim().split_whitespace();
for s in groups {
assert!(s.parse::<f64>().is_ok());
}
let result = new_ucmd!().arg("--groups").succeeds();
assert!(result.success);
let result = scene.ucmd().arg("--groups").succeeds();
let groups = result.stdout_str().trim().split_whitespace();
for s in groups {
assert!(s.parse::<f64>().is_ok());
@ -108,11 +122,13 @@ fn test_id_groups() {
#[test]
fn test_id_user() {
let mut result = new_ucmd!().arg("-u").succeeds();
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-u").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
result = new_ucmd!().arg("--user").succeeds();
let result = scene.ucmd().arg("--user").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
}
@ -120,28 +136,34 @@ fn test_id_user() {
#[test]
fn test_id_pretty_print() {
let username = return_whoami_username();
if username == "" {
// Sometimes, the CI is failing here
if username.is_empty() {
return;
}
let result = new_ucmd!().arg("-p").run();
if result.stdout_str().trim() == "" {
// Sometimes, the CI is failing here with
// old rust versions on Linux
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-p").run();
if result.stdout_str().trim().is_empty() {
// this fails only on: "MinRustV (ubuntu-latest, feat_os_unix)"
// `rustc 1.40.0 (73528e339 2019-12-16)`
// run: /home/runner/work/coreutils/coreutils/target/debug/coreutils id -p
// thread 'test_id::test_id_pretty_print' panicked at 'Command was expected to succeed.
// stdout =
// stderr = ', tests/common/util.rs:157:13
println!("test skipped:");
return;
}
result.success().stdout_contains(username);
}
#[test]
fn test_id_password_style() {
let username = return_whoami_username();
if username == "" {
// Sometimes, the CI is failing here
if username.is_empty() {
return;
}
let result = new_ucmd!().arg("-P").succeeds();
assert!(result.stdout_str().starts_with(&username));
}

View file

@ -11,12 +11,10 @@ use std::thread::sleep;
fn test_install_help() {
let (_, mut ucmd) = at_and_ucmd!();
assert!(ucmd
.arg("--help")
ucmd.arg("--help")
.succeeds()
.no_stderr()
.stdout
.contains("FLAGS:"));
.stdout_contains("FLAGS:");
}
#[test]
@ -59,13 +57,11 @@ fn test_install_failing_not_dir() {
at.touch(file1);
at.touch(file2);
at.touch(file3);
assert!(ucmd
.arg(file1)
ucmd.arg(file1)
.arg(file2)
.arg(file3)
.fails()
.stderr
.contains("not a directory"));
.stderr_contains("not a directory");
}
#[test]
@ -77,13 +73,11 @@ fn test_install_unimplemented_arg() {
at.touch(file);
at.mkdir(dir);
assert!(ucmd
.arg(context_arg)
ucmd.arg(context_arg)
.arg(file)
.arg(dir)
.fails()
.stderr
.contains("Unimplemented"));
.stderr_contains("Unimplemented");
assert!(!at.file_exists(&format!("{}/{}", dir, file)));
}
@ -231,13 +225,11 @@ fn test_install_mode_failing() {
at.touch(file);
at.mkdir(dir);
assert!(ucmd
.arg(file)
ucmd.arg(file)
.arg(dir)
.arg(mode_arg)
.fails()
.stderr
.contains("Invalid mode string: invalid digit found in string"));
.stderr_contains("Invalid mode string: invalid digit found in string");
let dest_file = &format!("{}/{}", dir, file);
assert!(at.file_exists(file));
@ -336,7 +328,7 @@ fn test_install_target_new_file_with_owner() {
.arg(format!("{}/{}", dir, file))
.run();
if is_ci() && result.stderr.contains("error: no such user:") {
if is_ci() && result.stderr_str().contains("error: 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;
@ -359,7 +351,7 @@ fn test_install_target_new_file_failing_nonexistent_parent() {
ucmd.arg(file1)
.arg(format!("{}/{}", dir, file2))
.fails()
.stderr_contains(&"not a directory");
.stderr_contains(&"No such file or directory");
}
#[test]
@ -443,9 +435,12 @@ fn test_install_failing_omitting_directory() {
at.mkdir(dir2);
at.touch(file1);
let r = ucmd.arg(dir1).arg(file1).arg(dir2).run();
assert!(r.code == Some(1));
assert!(r.stderr.contains("omitting directory"));
ucmd.arg(dir1)
.arg(file1)
.arg(dir2)
.fails()
.code_is(1)
.stderr_contains("omitting directory");
}
#[test]
@ -458,9 +453,12 @@ fn test_install_failing_no_such_file() {
at.mkdir(dir1);
at.touch(file1);
let r = ucmd.arg(file1).arg(file2).arg(dir1).run();
assert!(r.code == Some(1));
assert!(r.stderr.contains("No such file or directory"));
ucmd.arg(file1)
.arg(file2)
.arg(dir1)
.fails()
.code_is(1)
.stderr_contains("No such file or directory");
}
#[test]
@ -613,33 +611,64 @@ fn test_install_and_strip_with_program() {
#[test]
#[cfg(not(windows))]
fn test_install_and_strip_with_invalid_program() {
let scene = TestScenario::new(util_name!());
let stderr = scene
.ucmd()
new_ucmd!()
.arg("-s")
.arg("--strip-program")
.arg("/bin/date")
.arg(strip_source_file())
.arg(STRIP_TARGET_FILE)
.fails()
.stderr;
assert!(stderr.contains("strip program failed"));
.stderr_contains("strip program failed");
}
#[test]
#[cfg(not(windows))]
fn test_install_and_strip_with_non_existent_program() {
let scene = TestScenario::new(util_name!());
let stderr = scene
.ucmd()
new_ucmd!()
.arg("-s")
.arg("--strip-program")
.arg("/usr/bin/non_existent_program")
.arg(strip_source_file())
.arg(STRIP_TARGET_FILE)
.fails()
.stderr;
assert!(stderr.contains("No such file or directory"));
.stderr_contains("No such file or directory");
}
#[test]
fn test_install_creating_leading_dirs() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let source = "create_leading_test_file";
let target = "dir1/dir2/dir3/test_file";
at.touch(source);
scene
.ucmd()
.arg("-D")
.arg(source)
.arg(at.plus(target))
.succeeds()
.no_stderr();
}
#[test]
#[cfg(not(windows))]
fn test_install_creating_leading_dir_fails_on_long_name() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let source = "create_leading_test_file";
let target = format!("{}/test_file", "d".repeat(libc::PATH_MAX as usize + 1));
at.touch(source);
scene
.ucmd()
.arg("-D")
.arg(source)
.arg(at.plus(target.as_str()))
.fails()
.stderr_contains("failed to create");
}

View file

@ -299,13 +299,11 @@ fn test_symlink_overwrite_dir_fail() {
at.touch(path_a);
at.mkdir(path_b);
assert!(
ucmd.args(&["-s", "-T", path_a, path_b])
.fails()
.stderr
.len()
> 0
);
assert!(!ucmd
.args(&["-s", "-T", path_a, path_b])
.fails()
.stderr_str()
.is_empty());
}
#[test]
@ -358,7 +356,11 @@ fn test_symlink_target_only() {
at.mkdir(dir);
assert!(ucmd.args(&["-s", "-t", dir]).fails().stderr.len() > 0);
assert!(!ucmd
.args(&["-s", "-t", dir])
.fails()
.stderr_str()
.is_empty());
}
#[test]

View file

@ -5,6 +5,7 @@ use crate::common::util::*;
extern crate regex;
use self::regex::Regex;
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;
@ -102,6 +103,20 @@ fn test_ls_width() {
.succeeds()
.stdout_only("test-width-1\ntest-width-2\ntest-width-3\ntest-width-4\n");
}
scene
.ucmd()
.arg("-w=bad")
.fails()
.stderr_contains("invalid line width");
for option in &["-w 1a", "-w=1a", "--width=1a", "--width 1a"] {
scene
.ucmd()
.args(&option.split(" ").collect::<Vec<_>>())
.fails()
.stderr_only("ls: error: invalid line width: 1a");
}
}
#[test]
@ -435,6 +450,39 @@ fn test_ls_deref() {
assert!(!re.is_match(result.stdout_str().trim()));
}
#[test]
fn test_ls_sort_none() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("test-3");
at.touch("test-1");
at.touch("test-2");
// Order is not specified so we just check that it doesn't
// give any errors.
scene.ucmd().arg("--sort=none").succeeds();
scene.ucmd().arg("-U").succeeds();
}
#[test]
fn test_ls_sort_name() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("test-3");
at.touch("test-1");
at.touch("test-2");
let sep = if cfg!(unix) { "\n" } else { " " };
scene
.ucmd()
.arg("--sort=name")
.succeeds()
.stdout_is(["test-1", "test-2", "test-3\n"].join(sep));
}
#[test]
fn test_ls_order_size() {
let scene = TestScenario::new(util_name!());
@ -463,6 +511,18 @@ fn test_ls_order_size() {
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
#[cfg(windows)]
result.stdout_only("test-1 test-2 test-3 test-4\n");
let result = scene.ucmd().arg("--sort=size").succeeds();
#[cfg(not(windows))]
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
#[cfg(windows)]
result.stdout_only("test-4 test-3 test-2 test-1\n");
let result = scene.ucmd().arg("--sort=size").arg("-r").succeeds();
#[cfg(not(windows))]
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
#[cfg(windows)]
result.stdout_only("test-1 test-2 test-3 test-4\n");
}
#[test]
@ -471,13 +531,16 @@ fn test_ls_long_ctime() {
let at = &scene.fixtures;
at.touch("test-long-ctime-1");
let result = scene.ucmd().arg("-lc").succeeds();
// Should show the time on Unix, but question marks on windows.
#[cfg(unix)]
result.stdout_contains(":");
#[cfg(not(unix))]
result.stdout_contains("???");
for arg in &["-c", "--time=ctime", "--time=status"] {
let result = scene.ucmd().arg("-l").arg(arg).succeeds();
// Should show the time on Unix, but question marks on windows.
#[cfg(unix)]
result.stdout_contains(":");
#[cfg(not(unix))]
result.stdout_contains("???");
}
}
#[test]
@ -518,32 +581,46 @@ fn test_ls_order_time() {
#[cfg(windows)]
result.stdout_only("test-4 test-3 test-2 test-1\n");
let result = scene.ucmd().arg("--sort=time").succeeds();
#[cfg(not(windows))]
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
#[cfg(windows)]
result.stdout_only("test-4 test-3 test-2 test-1\n");
let result = scene.ucmd().arg("-tr").succeeds();
#[cfg(not(windows))]
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
#[cfg(windows)]
result.stdout_only("test-1 test-2 test-3 test-4\n");
let result = scene.ucmd().arg("--sort=time").arg("-r").succeeds();
#[cfg(not(windows))]
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
#[cfg(windows)]
result.stdout_only("test-1 test-2 test-3 test-4\n");
// 3 was accessed last in the read
// So the order should be 2 3 4 1
let result = scene.ucmd().arg("-tu").succeeds();
let file3_access = at.open("test-3").metadata().unwrap().accessed().unwrap();
let file4_access = at.open("test-4").metadata().unwrap().accessed().unwrap();
for arg in &["-u", "--time=atime", "--time=access", "--time=use"] {
let result = scene.ucmd().arg("-t").arg(arg).succeeds();
let file3_access = at.open("test-3").metadata().unwrap().accessed().unwrap();
let file4_access = at.open("test-4").metadata().unwrap().accessed().unwrap();
// It seems to be dependent on the platform whether the access time is actually set
if file3_access > file4_access {
if cfg!(not(windows)) {
result.stdout_only("test-3\ntest-4\ntest-2\ntest-1\n");
// It seems to be dependent on the platform whether the access time is actually set
if file3_access > file4_access {
if cfg!(not(windows)) {
result.stdout_only("test-3\ntest-4\ntest-2\ntest-1\n");
} else {
result.stdout_only("test-3 test-4 test-2 test-1\n");
}
} else {
result.stdout_only("test-3 test-4 test-2 test-1\n");
}
} else {
// Access time does not seem to be set on Windows and some other
// systems so the order is 4 3 2 1
if cfg!(not(windows)) {
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
} else {
result.stdout_only("test-4 test-3 test-2 test-1\n");
// Access time does not seem to be set on Windows and some other
// systems so the order is 4 3 2 1
if cfg!(not(windows)) {
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
} else {
result.stdout_only("test-4 test-3 test-2 test-1\n");
}
}
}
@ -620,20 +697,27 @@ fn test_ls_recursive() {
result.stdout_contains(&"a\\b:\nb");
}
#[cfg(unix)]
#[test]
fn test_ls_ls_color() {
fn test_ls_color() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.mkdir("a");
at.mkdir("a/nested_dir");
let nested_dir = Path::new("a")
.join("nested_dir")
.to_string_lossy()
.to_string();
at.mkdir(&nested_dir);
at.mkdir("z");
at.touch(&at.plus_as_string("a/nested_file"));
let nested_file = Path::new("a")
.join("nested_file")
.to_string_lossy()
.to_string();
at.touch(&nested_file);
at.touch("test-color");
let a_with_colors = "\x1b[01;34ma\x1b[0m";
let z_with_colors = "\x1b[01;34mz\x1b[0m";
let nested_dir_with_colors = "\x1b[01;34mnested_dir\x1b[0m";
let a_with_colors = "\x1b[1;34ma\x1b[0m";
let z_with_colors = "\x1b[1;34mz\x1b[0m";
let nested_dir_with_colors = "\x1b[1;34mnested_dir\x1b[0m";
// Color is disabled by default
let result = scene.ucmd().succeeds();
@ -669,14 +753,6 @@ fn test_ls_ls_color() {
.succeeds()
.stdout_contains(nested_dir_with_colors);
// Color has no effect
scene
.ucmd()
.arg("--color=always")
.arg("a/nested_file")
.succeeds()
.stdout_contains("a/nested_file\n");
// No output
scene
.ucmd()
@ -816,7 +892,7 @@ fn test_ls_indicator_style() {
let options = vec!["classify", "file-type", "slash"];
for opt in options {
// Verify that classify and file-type both contain indicators for symlinks.
let result = scene
scene
.ucmd()
.arg(format!("--indicator-style={}", opt))
.succeeds()
@ -826,7 +902,7 @@ fn test_ls_indicator_style() {
// Same test as above, but with the alternate flags.
let options = vec!["--classify", "--file-type", "-p"];
for opt in options {
let result = scene
scene
.ucmd()
.arg(format!("{}", opt))
.succeeds()
@ -837,7 +913,7 @@ fn test_ls_indicator_style() {
let options = vec!["classify", "file-type"];
for opt in options {
// Verify that classify and file-type both contain indicators for symlinks.
let result = scene
scene
.ucmd()
.arg(format!("--indicator-style={}", opt))
.succeeds()
@ -961,7 +1037,7 @@ fn test_ls_hidden_windows() {
let result = scene.ucmd().succeeds();
assert!(!result.stdout_str().contains(file));
let result = scene.ucmd().arg("-a").succeeds().stdout_contains(file);
scene.ucmd().arg("-a").succeeds().stdout_contains(file);
}
#[test]
@ -1051,9 +1127,11 @@ fn test_ls_quoting_style() {
at.touch("one");
// It seems that windows doesn't allow \n in filenames.
// And it also doesn't like \, of course.
#[cfg(unix)]
{
at.touch("one\ntwo");
at.touch("one\\two");
// Default is shell-escape
scene
.ucmd()
@ -1115,6 +1193,42 @@ fn test_ls_quoting_style() {
.succeeds()
.stdout_only(format!("{}\n", correct));
}
for (arg, correct) in &[
("--quoting-style=literal", "one\\two"),
("-N", "one\\two"),
("--quoting-style=c", "\"one\\\\two\""),
("-Q", "\"one\\\\two\""),
("--quote-name", "\"one\\\\two\""),
("--quoting-style=escape", "one\\\\two"),
("-b", "one\\\\two"),
("--quoting-style=shell-escape", "'one\\two'"),
("--quoting-style=shell-escape-always", "'one\\two'"),
("--quoting-style=shell", "'one\\two'"),
("--quoting-style=shell-always", "'one\\two'"),
] {
scene
.ucmd()
.arg(arg)
.arg("one\\two")
.succeeds()
.stdout_only(format!("{}\n", correct));
}
// Tests for a character that forces quotation in shell-style escaping
// after a character in a dollar expression
at.touch("one\n&two");
for (arg, correct) in &[
("--quoting-style=shell-escape", "'one'$'\\n''&two'"),
("--quoting-style=shell-escape-always", "'one'$'\\n''&two'"),
] {
scene
.ucmd()
.arg(arg)
.arg("one\n&two")
.succeeds()
.stdout_only(format!("{}\n", correct));
}
}
scene
@ -1314,3 +1428,256 @@ fn test_ls_ignore_hide() {
.stderr_contains(&"Invalid pattern")
.stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n");
}
#[test]
fn test_ls_ignore_backups() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("somefile");
at.touch("somebackup~");
at.touch(".somehiddenfile");
at.touch(".somehiddenbackup~");
scene.ucmd().arg("-B").succeeds().stdout_is("somefile\n");
scene
.ucmd()
.arg("--ignore-backups")
.succeeds()
.stdout_is("somefile\n");
scene
.ucmd()
.arg("-aB")
.succeeds()
.stdout_contains(".somehiddenfile")
.stdout_contains("somefile")
.stdout_does_not_contain("somebackup")
.stdout_does_not_contain(".somehiddenbackup~");
scene
.ucmd()
.arg("-a")
.arg("--ignore-backups")
.succeeds()
.stdout_contains(".somehiddenfile")
.stdout_contains("somefile")
.stdout_does_not_contain("somebackup")
.stdout_does_not_contain(".somehiddenbackup~");
}
#[test]
fn test_ls_directory() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.mkdir("some_dir");
at.symlink_dir("some_dir", "sym_dir");
at.touch(Path::new("some_dir").join("nested_file").to_str().unwrap());
scene
.ucmd()
.arg("some_dir")
.succeeds()
.stdout_is("nested_file\n");
scene
.ucmd()
.arg("--directory")
.arg("some_dir")
.succeeds()
.stdout_is("some_dir\n");
scene
.ucmd()
.arg("sym_dir")
.succeeds()
.stdout_is("nested_file\n");
}
#[test]
fn test_ls_deref_command_line() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("some_file");
at.symlink_file("some_file", "sym_file");
scene
.ucmd()
.arg("sym_file")
.succeeds()
.stdout_is("sym_file\n");
// -l changes the default to no dereferencing
scene
.ucmd()
.arg("-l")
.arg("sym_file")
.succeeds()
.stdout_contains("sym_file ->");
scene
.ucmd()
.arg("--dereference-command-line-symlink-to-dir")
.arg("sym_file")
.succeeds()
.stdout_is("sym_file\n");
scene
.ucmd()
.arg("-l")
.arg("--dereference-command-line-symlink-to-dir")
.arg("sym_file")
.succeeds()
.stdout_contains("sym_file ->");
scene
.ucmd()
.arg("--dereference-command-line")
.arg("sym_file")
.succeeds()
.stdout_is("sym_file\n");
let result = scene
.ucmd()
.arg("-l")
.arg("--dereference-command-line")
.arg("sym_file")
.succeeds();
assert!(!result.stdout_str().contains("->"));
let result = scene.ucmd().arg("-lH").arg("sym_file").succeeds();
assert!(!result.stdout_str().contains("sym_file ->"));
// If the symlink is not a command line argument, it must be shown normally
scene
.ucmd()
.arg("-l")
.arg("--dereference-command-line")
.succeeds()
.stdout_contains("sym_file ->");
}
#[test]
fn test_ls_deref_command_line_dir() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.mkdir("some_dir");
at.symlink_dir("some_dir", "sym_dir");
at.touch(Path::new("some_dir").join("nested_file").to_str().unwrap());
scene
.ucmd()
.arg("sym_dir")
.succeeds()
.stdout_contains("nested_file");
scene
.ucmd()
.arg("-l")
.arg("sym_dir")
.succeeds()
.stdout_contains("sym_dir ->");
scene
.ucmd()
.arg("--dereference-command-line-symlink-to-dir")
.arg("sym_dir")
.succeeds()
.stdout_contains("nested_file");
scene
.ucmd()
.arg("-l")
.arg("--dereference-command-line-symlink-to-dir")
.arg("sym_dir")
.succeeds()
.stdout_contains("nested_file");
scene
.ucmd()
.arg("--dereference-command-line")
.arg("sym_dir")
.succeeds()
.stdout_contains("nested_file");
scene
.ucmd()
.arg("-l")
.arg("--dereference-command-line")
.arg("sym_dir")
.succeeds()
.stdout_contains("nested_file");
scene
.ucmd()
.arg("-lH")
.arg("sym_dir")
.succeeds()
.stdout_contains("nested_file");
// If the symlink is not a command line argument, it must be shown normally
scene
.ucmd()
.arg("-l")
.arg("--dereference-command-line")
.succeeds()
.stdout_contains("sym_dir ->");
scene
.ucmd()
.arg("-lH")
.succeeds()
.stdout_contains("sym_dir ->");
scene
.ucmd()
.arg("-l")
.arg("--dereference-command-line-symlink-to-dir")
.succeeds()
.stdout_contains("sym_dir ->");
// --directory does not dereference anything by default
scene
.ucmd()
.arg("-l")
.arg("--directory")
.arg("sym_dir")
.succeeds()
.stdout_contains("sym_dir ->");
let result = scene
.ucmd()
.arg("-l")
.arg("--directory")
.arg("--dereference-command-line-symlink-to-dir")
.arg("sym_dir")
.succeeds();
assert!(!result.stdout_str().ends_with("sym_dir"));
// --classify does not dereference anything by default
scene
.ucmd()
.arg("-l")
.arg("--directory")
.arg("sym_dir")
.succeeds()
.stdout_contains("sym_dir ->");
let result = scene
.ucmd()
.arg("-l")
.arg("--directory")
.arg("--dereference-command-line-symlink-to-dir")
.arg("sym_dir")
.succeeds();
assert!(!result.stdout_str().ends_with("sym_dir"));
}

View file

@ -19,8 +19,7 @@ fn test_create_one_fifo_with_invalid_mode() {
.arg("-m")
.arg("invalid")
.fails()
.stderr
.contains("invalid mode");
.stderr_contains("invalid mode");
}
#[test]

View file

@ -113,17 +113,14 @@ fn test_mktemp_mktemp_t() {
.arg("-t")
.arg(TEST_TEMPLATE7)
.succeeds();
let result = scene
scene
.ucmd()
.env(TMPDIR, &pathname)
.arg("-t")
.arg(TEST_TEMPLATE8)
.fails();
println!("stdout {}", result.stdout);
println!("stderr {}", result.stderr);
assert!(result
.stderr
.contains("error: suffix cannot contain any path separators"));
.fails()
.no_stdout()
.stderr_contains("error: suffix cannot contain any path separators");
}
#[test]
@ -391,10 +388,8 @@ fn test_mktemp_tmpdir_one_arg() {
.arg("--tmpdir")
.arg("apt-key-gpghome.XXXXXXXXXX")
.succeeds();
println!("stdout {}", result.stdout);
println!("stderr {}", result.stderr);
assert!(result.stdout.contains("apt-key-gpghome."));
assert!(PathBuf::from(result.stdout.trim()).is_file());
result.no_stderr().stdout_contains("apt-key-gpghome.");
assert!(PathBuf::from(result.stdout_str().trim()).is_file());
}
#[test]
@ -407,8 +402,6 @@ fn test_mktemp_directory_tmpdir() {
.arg("--tmpdir")
.arg("apt-key-gpghome.XXXXXXXXXX")
.succeeds();
println!("stdout {}", result.stdout);
println!("stderr {}", result.stderr);
assert!(result.stdout.contains("apt-key-gpghome."));
assert!(PathBuf::from(result.stdout.trim()).is_dir());
result.no_stderr().stdout_contains("apt-key-gpghome.");
assert!(PathBuf::from(result.stdout_str().trim()).is_dir());
}

View file

@ -2,18 +2,15 @@ use crate::common::util::*;
#[test]
fn test_more_no_arg() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(!result.success);
// stderr = more: Reading from stdin isn't supported yet.
new_ucmd!().fails();
}
#[test]
fn test_more_dir_arg() {
let (_, mut ucmd) = at_and_ucmd!();
ucmd.arg(".");
let result = ucmd.run();
assert!(!result.success);
let result = new_ucmd!().arg(".").run();
result.failure();
const EXPECTED_ERROR_MESSAGE: &str =
"more: '.' is a directory.\nTry 'more --help' for more information.";
assert_eq!(result.stderr.trim(), EXPECTED_ERROR_MESSAGE);
assert_eq!(result.stderr_str().trim(), EXPECTED_ERROR_MESSAGE);
}

View file

@ -476,16 +476,9 @@ fn test_mv_overwrite_nonempty_dir() {
// GNU: "mv: cannot move a to b: Directory not empty"
// Verbose output for the move should not be shown on failure
assert!(
ucmd.arg("-vT")
.arg(dir_a)
.arg(dir_b)
.fails()
.no_stdout()
.stderr
.len()
> 0
);
let result = ucmd.arg("-vT").arg(dir_a).arg(dir_b).fails();
result.no_stdout();
assert!(!result.stderr_str().is_empty());
assert!(at.dir_exists(dir_a));
assert!(at.dir_exists(dir_b));
@ -526,15 +519,15 @@ fn test_mv_errors() {
// $ mv -T -t a b
// mv: cannot combine --target-directory (-t) and --no-target-directory (-T)
let result = scene
scene
.ucmd()
.arg("-T")
.arg("-t")
.arg(dir)
.arg(file_a)
.arg(file_b)
.fails();
assert!(result.stderr.contains("cannot be used with"));
.fails()
.stderr_contains("cannot be used with");
// $ at.touch file && at.mkdir dir
// $ mv -T file dir
@ -553,7 +546,13 @@ fn test_mv_errors() {
// $ at.mkdir dir && at.touch file
// $ mv dir file
// err == mv: cannot overwrite non-directory file with directory dir
assert!(scene.ucmd().arg(dir).arg(file_a).fails().stderr.len() > 0);
assert!(!scene
.ucmd()
.arg(dir)
.arg(file_a)
.fails()
.stderr_str()
.is_empty());
}
#[test]

View file

@ -16,7 +16,7 @@ fn test_negative_adjustment() {
let res = new_ucmd!().args(&["-n", "-1", "true"]).run();
assert!(res
.stderr
.stderr_str()
.starts_with("nice: warning: setpriority: Permission denied"));
}

View file

@ -2,54 +2,46 @@ use crate::common::util::*;
#[test]
fn test_nproc() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(result.success);
let nproc: u8 = result.stdout.trim().parse().unwrap();
let nproc: u8 = new_ucmd!().succeeds().stdout_str().trim().parse().unwrap();
assert!(nproc > 0);
}
#[test]
fn test_nproc_all_omp() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--all").run();
assert!(result.success);
let nproc: u8 = result.stdout.trim().parse().unwrap();
let result = new_ucmd!().arg("--all").succeeds();
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
assert!(nproc > 0);
let result = TestScenario::new(util_name!())
.ucmd_keepenv()
.env("OMP_NUM_THREADS", "1")
.run();
assert!(result.success);
let nproc_omp: u8 = result.stdout.trim().parse().unwrap();
.succeeds();
let nproc_omp: u8 = result.stdout_str().trim().parse().unwrap();
assert!(nproc - 1 == nproc_omp);
let result = TestScenario::new(util_name!())
.ucmd_keepenv()
.env("OMP_NUM_THREADS", "1") // Has no effect
.arg("--all")
.run();
assert!(result.success);
let nproc_omp: u8 = result.stdout.trim().parse().unwrap();
.succeeds();
let nproc_omp: u8 = result.stdout_str().trim().parse().unwrap();
assert!(nproc == nproc_omp);
}
#[test]
fn test_nproc_ignore() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(result.success);
let nproc: u8 = result.stdout.trim().parse().unwrap();
let result = new_ucmd!().succeeds();
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
if nproc > 1 {
// Ignore all CPU but one
let result = TestScenario::new(util_name!())
.ucmd_keepenv()
.arg("--ignore")
.arg((nproc - 1).to_string())
.run();
assert!(result.success);
let nproc: u8 = result.stdout.trim().parse().unwrap();
.succeeds();
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
assert!(nproc == 1);
}
}

View file

@ -43,11 +43,9 @@ fn test_short_format_i() {
let actual = TestScenario::new(util_name!())
.ucmd()
.args(&args)
.run()
.stdout;
.succeeds()
.stdout_move_str();
let expect = expected_result(&args);
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
let v_actual: Vec<&str> = actual.split_whitespace().collect();
let v_expect: Vec<&str> = expect.split_whitespace().collect();
assert_eq!(v_actual, v_expect);
@ -62,11 +60,9 @@ fn test_short_format_q() {
let actual = TestScenario::new(util_name!())
.ucmd()
.args(&args)
.run()
.stdout;
.succeeds()
.stdout_move_str();
let expect = expected_result(&args);
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
let v_actual: Vec<&str> = actual.split_whitespace().collect();
let v_expect: Vec<&str> = expect.split_whitespace().collect();
assert_eq!(v_actual, v_expect);
@ -79,5 +75,5 @@ fn expected_result(args: &[&str]) -> String {
.env("LANGUAGE", "C")
.args(args)
.run()
.stdout
.stdout_move_str()
}

View file

@ -7,10 +7,11 @@ fn test_get_all() {
env::set_var(key, "VALUE");
assert_eq!(env::var(key), Ok("VALUE".to_string()));
let result = TestScenario::new(util_name!()).ucmd_keepenv().run();
assert!(result.success);
assert!(result.stdout.contains("HOME="));
assert!(result.stdout.contains("KEY=VALUE"));
TestScenario::new(util_name!())
.ucmd_keepenv()
.succeeds()
.stdout_contains("HOME=")
.stdout_contains("KEY=VALUE");
}
#[test]
@ -22,9 +23,8 @@ fn test_get_var() {
let result = TestScenario::new(util_name!())
.ucmd_keepenv()
.arg("KEY")
.run();
.succeeds();
assert!(result.success);
assert!(!result.stdout.is_empty());
assert!(result.stdout.trim() == "VALUE");
assert!(!result.stdout_str().is_empty());
assert!(result.stdout_str().trim() == "VALUE");
}

View file

@ -5,7 +5,7 @@ static GIBBERISH: &'static str = "supercalifragilisticexpialidocious";
#[test]
fn test_canonicalize() {
let (at, mut ucmd) = at_and_ucmd!();
let actual = ucmd.arg("-f").arg(".").run().stdout;
let actual = ucmd.arg("-f").arg(".").run().stdout_move_str();
let expect = at.root_dir_resolved() + "\n";
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -15,7 +15,7 @@ fn test_canonicalize() {
#[test]
fn test_canonicalize_existing() {
let (at, mut ucmd) = at_and_ucmd!();
let actual = ucmd.arg("-e").arg(".").run().stdout;
let actual = ucmd.arg("-e").arg(".").run().stdout_move_str();
let expect = at.root_dir_resolved() + "\n";
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -25,7 +25,7 @@ fn test_canonicalize_existing() {
#[test]
fn test_canonicalize_missing() {
let (at, mut ucmd) = at_and_ucmd!();
let actual = ucmd.arg("-m").arg(GIBBERISH).run().stdout;
let actual = ucmd.arg("-m").arg(GIBBERISH).run().stdout_move_str();
let expect = path_concat!(at.root_dir_resolved(), GIBBERISH) + "\n";
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -37,7 +37,7 @@ fn test_long_redirection_to_current_dir() {
let (at, mut ucmd) = at_and_ucmd!();
// Create a 256-character path to current directory
let dir = path_concat!(".", ..128);
let actual = ucmd.arg("-n").arg("-m").arg(dir).run().stdout;
let actual = ucmd.arg("-n").arg("-m").arg(dir).run().stdout_move_str();
let expect = at.root_dir_resolved();
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -48,7 +48,12 @@ fn test_long_redirection_to_current_dir() {
fn test_long_redirection_to_root() {
// Create a 255-character path to root
let dir = path_concat!("..", ..85);
let actual = new_ucmd!().arg("-n").arg("-m").arg(dir).run().stdout;
let actual = new_ucmd!()
.arg("-n")
.arg("-m")
.arg(dir)
.run()
.stdout_move_str();
let expect = get_root_path();
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);

View file

@ -36,9 +36,7 @@ fn test_shred_force() {
at.set_readonly(file);
// Try shred -u.
let result = scene.ucmd().arg("-u").arg(file).run();
println!("stderr = {:?}", result.stderr);
println!("stdout = {:?}", result.stdout);
scene.ucmd().arg("-u").arg(file).run();
// file_a was not deleted because it is readonly.
assert!(at.file_exists(file));

View file

@ -9,35 +9,28 @@ fn test_output_is_random_permutation() {
.collect::<Vec<String>>()
.join("\n");
let result = new_ucmd!()
.pipe_in(input.as_bytes())
.succeeds()
.no_stderr()
.stdout
.clone();
let result = new_ucmd!().pipe_in(input.as_bytes()).succeeds();
result.no_stderr();
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
assert_ne!(result, input, "Output is not randomised");
assert_ne!(result.stdout_str(), input, "Output is not randomised");
assert_eq!(result_seq, input_seq, "Output is not a permutation");
}
#[test]
fn test_zero_termination() {
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result = new_ucmd!()
.arg("-z")
.arg("-i1-10")
.succeeds()
.no_stderr()
.stdout
.clone();
let result = new_ucmd!().arg("-z").arg("-i1-10").succeeds();
result.no_stderr();
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\0")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
@ -57,12 +50,11 @@ fn test_echo() {
.map(|x| x.to_string())
.collect::<Vec<String>>(),
)
.succeeds()
.no_stderr()
.stdout
.clone();
.succeeds();
result.no_stderr();
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
@ -84,12 +76,11 @@ fn test_head_count() {
let result = new_ucmd!()
.args(&["-n", &repeat_limit.to_string()])
.pipe_in(input.as_bytes())
.succeeds()
.no_stderr()
.stdout
.clone();
.succeeds();
result.no_stderr();
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
@ -99,7 +90,7 @@ fn test_head_count() {
assert!(
result_seq.iter().all(|x| input_seq.contains(x)),
"Output includes element not from input: {}",
result
result.stdout_str()
)
}
@ -117,12 +108,11 @@ fn test_repeat() {
.arg("-r")
.args(&["-n", &repeat_limit.to_string()])
.pipe_in(input.as_bytes())
.succeeds()
.no_stderr()
.stdout
.clone();
.succeeds();
result.no_stderr();
let result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
@ -146,14 +136,11 @@ fn test_repeat() {
fn test_file_input() {
let expected_seq = vec![11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
let result = new_ucmd!()
.arg("file_input.txt")
.succeeds()
.no_stderr()
.stdout
.clone();
let result = new_ucmd!().arg("file_input.txt").succeeds();
result.no_stderr();
let mut result_seq: Vec<i32> = result
.stdout_str()
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
@ -164,52 +151,50 @@ fn test_file_input() {
#[test]
fn test_shuf_echo_and_input_range_not_allowed() {
let result = new_ucmd!().args(&["-e", "0", "-i", "0-2"]).run();
assert!(!result.success);
assert!(result
.stderr
.contains("The argument '--input-range <LO-HI>' cannot be used with '--echo <ARG>...'"));
new_ucmd!()
.args(&["-e", "0", "-i", "0-2"])
.fails()
.stderr_contains(
"The argument '--input-range <LO-HI>' cannot be used with '--echo <ARG>...'",
);
}
#[test]
fn test_shuf_input_range_and_file_not_allowed() {
let result = new_ucmd!().args(&["-i", "0-9", "file"]).run();
assert!(!result.success);
assert!(result
.stderr
.contains("The argument '<file>' cannot be used with '--input-range <LO-HI>'"));
new_ucmd!()
.args(&["-i", "0-9", "file"])
.fails()
.stderr_contains("The argument '<file>' cannot be used with '--input-range <LO-HI>'");
}
#[test]
fn test_shuf_invalid_input_range_one() {
let result = new_ucmd!().args(&["-i", "0"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid input range"));
new_ucmd!()
.args(&["-i", "0"])
.fails()
.stderr_contains("invalid input range");
}
#[test]
fn test_shuf_invalid_input_range_two() {
let result = new_ucmd!().args(&["-i", "a-9"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid input range: 'a'"));
new_ucmd!()
.args(&["-i", "a-9"])
.fails()
.stderr_contains("invalid input range: 'a'");
}
#[test]
fn test_shuf_invalid_input_range_three() {
let result = new_ucmd!().args(&["-i", "0-b"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid input range: 'b'"));
new_ucmd!()
.args(&["-i", "0-b"])
.fails()
.stderr_contains("invalid input range: 'b'");
}
#[test]
fn test_shuf_invalid_input_line_count() {
let result = new_ucmd!().args(&["-n", "a"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid line count: 'a'"));
new_ucmd!()
.args(&["-n", "a"])
.fails()
.stderr_contains("invalid line count: 'a'");
}

View file

@ -16,10 +16,10 @@ fn test_months_whitespace() {
#[test]
fn test_version_empty_lines() {
new_ucmd!()
.arg("-V")
.arg("version-empty-lines.txt")
.succeeds()
.stdout_is("\n\n\n\n\n\n\n1.2.3-alpha\n1.2.3-alpha2\n\t\t\t1.12.4\n11.2.3\n");
.arg("-V")
.arg("version-empty-lines.txt")
.succeeds()
.stdout_is("\n\n\n\n\n\n\n1.2.3-alpha\n1.2.3-alpha2\n\t\t\t1.12.4\n11.2.3\n");
}
#[test]
@ -38,11 +38,7 @@ fn test_multiple_decimals_general() {
#[test]
fn test_multiple_decimals_numeric() {
new_ucmd!()
.arg("-n")
.arg("multiple_decimals_numeric.txt")
.succeeds()
.stdout_is("-2028789030\n-896689\n-8.90880\n-1\n-.05\n\n\n\n\n\n\n\n\n000\nCARAvan\n00000001\n1\n1.040000000\n1.444\n1.58590\n8.013\n45\n46.89\n 4567.\n4567.1\n4567.34\n\t\t\t\t\t\t\t\t\t\t4567..457\n\t\t\t\t37800\n\t\t\t\t\t\t45670.89079.098\n\t\t\t\t\t\t45670.89079.1\n576,446.88800000\n576,446.890\n4798908.340000000000\n4798908.45\n4798908.8909800\n");
test_helper("multiple_decimals_numeric", "-n")
}
#[test]
@ -69,7 +65,7 @@ fn test_random_shuffle_len() {
// check whether output is the same length as the input
const FILE: &'static str = "default_unsorted_ints.expected";
let (at, _ucmd) = at_and_ucmd!();
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout_move_str();
let expected = at.read(FILE);
assert_ne!(result, expected);
@ -81,9 +77,9 @@ fn test_random_shuffle_contains_all_lines() {
// check whether lines of input are all in output
const FILE: &'static str = "default_unsorted_ints.expected";
let (at, _ucmd) = at_and_ucmd!();
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout_move_str();
let expected = at.read(FILE);
let result_sorted = new_ucmd!().pipe_in(result.clone()).run().stdout;
let result_sorted = new_ucmd!().pipe_in(result.clone()).run().stdout_move_str();
assert_ne!(result, expected);
assert_eq!(result_sorted, expected);
@ -96,9 +92,9 @@ fn test_random_shuffle_two_runs_not_the_same() {
// as the starting order, or if both random sorts end up having the same order.
const FILE: &'static str = "default_unsorted_ints.expected";
let (at, _ucmd) = at_and_ucmd!();
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout_move_str();
let expected = at.read(FILE);
let unexpected = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let unexpected = new_ucmd!().arg("-R").arg(FILE).run().stdout_move_str();
assert_ne!(result, expected);
assert_ne!(result, unexpected);
@ -111,9 +107,9 @@ fn test_random_shuffle_contains_two_runs_not_the_same() {
// as the starting order, or if both random sorts end up having the same order.
const FILE: &'static str = "default_unsorted_ints.expected";
let (at, _ucmd) = at_and_ucmd!();
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout_move_str();
let expected = at.read(FILE);
let unexpected = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let unexpected = new_ucmd!().arg("-R").arg(FILE).run().stdout_move_str();
assert_ne!(result, expected);
assert_ne!(result, unexpected);
@ -585,3 +581,12 @@ fn test_check_silent() {
.fails()
.stdout_is("");
}
#[test]
fn test_trailing_separator() {
new_ucmd!()
.args(&["-t", "x", "-k", "1,1"])
.pipe_in("aax\naaa\n")
.succeeds()
.stdout_is("aax\naaa\n");
}

View file

@ -194,7 +194,7 @@ 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
let args = ["-t", "/"];
let actual = new_ucmd!().args(&args).run().stdout;
let actual = new_ucmd!().args(&args).succeeds().stdout_move_str();
let expect = expected_result(&args);
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -216,7 +216,7 @@ fn test_terse_normal_format() {
#[cfg(target_os = "linux")]
fn test_format_created_time() {
let args = ["-c", "%w", "/boot"];
let actual = new_ucmd!().args(&args).run().stdout;
let actual = new_ucmd!().args(&args).succeeds().stdout_move_str();
let expect = expected_result(&args);
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -240,7 +240,7 @@ fn test_format_created_time() {
#[cfg(target_os = "linux")]
fn test_format_created_seconds() {
let args = ["-c", "%W", "/boot"];
let actual = new_ucmd!().args(&args).run().stdout;
let actual = new_ucmd!().args(&args).succeeds().stdout_move_str();
let expect = expected_result(&args);
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -337,5 +337,5 @@ fn expected_result(args: &[&str]) -> String {
.env("LANGUAGE", "C")
.args(args)
.run()
.stdout
.stdout_move_str()
}

View file

@ -5,8 +5,7 @@ use tempfile::tempdir;
#[test]
fn test_sync_default() {
let result = new_ucmd!().run();
assert!(result.success);
new_ucmd!().succeeds();
}
#[test]
@ -18,8 +17,10 @@ fn test_sync_incorrect_arg() {
fn test_sync_fs() {
let temporary_directory = tempdir().unwrap();
let temporary_path = fs::canonicalize(temporary_directory.path()).unwrap();
let result = new_ucmd!().arg("--file-system").arg(&temporary_path).run();
assert!(result.success);
new_ucmd!()
.arg("--file-system")
.arg(&temporary_path)
.succeeds();
}
#[test]
@ -27,12 +28,14 @@ fn test_sync_data() {
// Todo add a second arg
let temporary_directory = tempdir().unwrap();
let temporary_path = fs::canonicalize(temporary_directory.path()).unwrap();
let result = new_ucmd!().arg("--data").arg(&temporary_path).run();
assert!(result.success);
new_ucmd!().arg("--data").arg(&temporary_path).succeeds();
}
#[test]
fn test_sync_no_existing_files() {
let result = new_ucmd!().arg("--data").arg("do-no-exist").fails();
assert!(result.stderr.contains("error: cannot stat"));
new_ucmd!()
.arg("--data")
.arg("do-no-exist")
.fails()
.stderr_contains("error: cannot stat");
}

View file

@ -52,18 +52,19 @@ fn test_single_non_newline_separator_before() {
#[test]
fn test_invalid_input() {
let (_, mut ucmd) = at_and_ucmd!();
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
ucmd.arg("b")
.run()
.stderr
.contains("tac: error: failed to open 'b' for reading");
let (at, mut ucmd) = at_and_ucmd!();
scene
.ucmd()
.arg("b")
.fails()
.stderr_contains("failed to open 'b' for reading: No such file or directory");
at.mkdir("a");
ucmd.arg("a")
.run()
.stderr
.contains("tac: error: failed to read 'a'");
scene
.ucmd()
.arg("a")
.fails()
.stderr_contains("dir: read error: Invalid argument");
}

View file

@ -226,8 +226,8 @@ fn test_bytes_big() {
.arg(FILE)
.arg("-c")
.arg(format!("{}", N_ARG))
.run()
.stdout;
.succeeds()
.stdout_move_str();
let expected = at.read(EXPECTED_FILE);
assert_eq!(result.len(), expected.len());
@ -340,6 +340,15 @@ fn test_negative_indexing() {
let negative_bytes_index = new_ucmd!().arg("-c").arg("-20").arg(FOOBAR_TXT).run();
assert_eq!(positive_lines_index.stdout, negative_lines_index.stdout);
assert_eq!(positive_bytes_index.stdout, negative_bytes_index.stdout);
assert_eq!(positive_lines_index.stdout(), negative_lines_index.stdout());
assert_eq!(positive_bytes_index.stdout(), negative_bytes_index.stdout());
}
#[test]
fn test_sleep_interval() {
new_ucmd!()
.arg("-s")
.arg("10")
.arg(FOOBAR_TXT)
.succeeds();
}

View file

@ -367,7 +367,58 @@ fn test_touch_mtime_dst_succeeds() {
let target_time = str_to_filetime("%Y%m%d%H%M", "202103140300");
let (_, mtime) = get_file_times(&at, file);
eprintln!("target_time: {:?}", target_time);
eprintln!("mtime: {:?}", mtime);
assert!(target_time == mtime);
}
// is_dst_switch_hour returns true if timespec ts is just before the switch
// to Daylight Saving Time.
// For example, in EST (UTC-5), Timespec { sec: 1583647200, nsec: 0 }
// for March 8 2020 01:00:00 AM
// is just before the switch because on that day clock jumps by 1 hour,
// so 1 minute after 01:59:00 is 03:00:00.
fn is_dst_switch_hour(ts: time::Timespec) -> bool {
let ts_after = ts + time::Duration::hours(1);
let tm = time::at(ts);
let tm_after = time::at(ts_after);
tm_after.tm_hour == tm.tm_hour + 2
}
// get_dstswitch_hour returns date string for which touch -m -t fails.
// For example, in EST (UTC-5), that will be "202003080200" so
// touch -m -t 202003080200 somefile
// fails (that date/time does not exist).
// In other locales it will be a different date/time, and in some locales
// it doesn't exist at all, in which case this function will return None.
fn get_dstswitch_hour() -> Option<String> {
let now = time::now();
// Start from January 1, 2020, 00:00.
let mut tm = time::strptime("20200101-0000", "%Y%m%d-%H%M").unwrap();
tm.tm_isdst = -1;
tm.tm_utcoff = now.tm_utcoff;
let mut ts = tm.to_timespec();
// Loop through all hours in year 2020 until we find the hour just
// before the switch to DST.
for _i in 0..(366 * 24) {
if is_dst_switch_hour(ts) {
let mut tm = time::at(ts);
tm.tm_hour = tm.tm_hour + 1;
let s = time::strftime("%Y%m%d%H%M", &tm).unwrap().to_string();
return Some(s);
}
ts = ts + time::Duration::hours(1);
}
None
}
#[test]
fn test_touch_mtime_dst_fails() {
let (_at, mut ucmd) = at_and_ucmd!();
let file = "test_touch_set_mtime_dst_fails";
match get_dstswitch_hour() {
Some(s) => {
ucmd.args(&["-m", "-t", &s, file]).fails();
}
None => (),
}
}

View file

@ -120,19 +120,15 @@ fn test_truncate_with_set1_shorter_than_set2() {
#[test]
fn missing_args_fails() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(!result.success);
assert!(result.stderr.contains("missing operand"));
ucmd.fails().stderr_contains("missing operand");
}
#[test]
fn missing_required_second_arg_fails() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.args(&["foo"]).run();
assert!(!result.success);
assert!(result.stderr.contains("missing operand after"));
ucmd.args(&["foo"])
.fails()
.stderr_contains("missing operand after");
}
#[test]

View file

@ -53,6 +53,16 @@ fn test_decrease_file_size() {
assert!(file.seek(SeekFrom::Current(0)).unwrap() == 6);
}
#[test]
fn test_space_in_size() {
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();
file.seek(SeekFrom::End(0)).unwrap();
assert!(file.seek(SeekFrom::Current(0)).unwrap() == 4);
}
#[test]
fn test_failed() {
new_ucmd!().fails();
@ -69,3 +79,4 @@ fn test_failed_incorrect_arg() {
let (_at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["-s", "+5A", TFILE1]).fails();
}

View file

@ -18,33 +18,35 @@ fn test_sort_self_loop() {
#[test]
fn test_no_such_file() {
let result = new_ucmd!().arg("invalid_file_txt").run();
assert_eq!(true, result.stderr.contains("No such file or directory"));
new_ucmd!()
.arg("invalid_file_txt")
.fails()
.stderr_contains("No such file or directory");
}
#[test]
fn test_version_flag() {
let version_short = new_ucmd!().arg("-V").run();
let version_long = new_ucmd!().arg("--version").run();
let version_short = new_ucmd!().arg("-V").succeeds();
let version_long = new_ucmd!().arg("--version").succeeds();
assert_eq!(version_short.stdout, version_long.stdout);
assert_eq!(version_short.stdout_str(), version_long.stdout_str());
}
#[test]
fn test_help_flag() {
let help_short = new_ucmd!().arg("-h").run();
let help_long = new_ucmd!().arg("--help").run();
let help_short = new_ucmd!().arg("-h").succeeds();
let help_long = new_ucmd!().arg("--help").succeeds();
assert_eq!(help_short.stdout, help_long.stdout);
assert_eq!(help_short.stdout_str(), help_long.stdout_str());
}
#[test]
fn test_multiple_arguments() {
let result = new_ucmd!()
new_ucmd!()
.arg("call_graph.txt")
.arg("invalid_file.txt")
.run();
assert_eq!(true, result.stderr.contains("error: Found argument 'invalid_file.txt' which wasn't expected, or isn't valid in this context"))
.arg("invalid_file")
.fails()
.stderr_contains(
"Found argument 'invalid_file' which wasn't expected, or isn't valid in this context",
);
}

View file

@ -2,60 +2,41 @@ use crate::common::util::*;
#[test]
fn test_uname_compatible() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-a").run();
assert!(result.success);
new_ucmd!().arg("-a").succeeds();
}
#[test]
fn test_uname_name() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-n").run();
assert!(result.success);
new_ucmd!().arg("-n").succeeds();
}
#[test]
fn test_uname_processor() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-p").run();
assert!(result.success);
assert_eq!(result.stdout.trim_end(), "unknown");
let result = new_ucmd!().arg("-p").succeeds();
assert_eq!(result.stdout_str().trim_end(), "unknown");
}
#[test]
fn test_uname_hwplatform() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-i").run();
assert!(result.success);
assert_eq!(result.stdout.trim_end(), "unknown");
let result = new_ucmd!().arg("-i").succeeds();
assert_eq!(result.stdout_str().trim_end(), "unknown");
}
#[test]
fn test_uname_machine() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-m").run();
assert!(result.success);
new_ucmd!().arg("-m").succeeds();
}
#[test]
fn test_uname_kernel_version() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-v").run();
assert!(result.success);
new_ucmd!().arg("-v").succeeds();
}
#[test]
fn test_uname_kernel() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("-o").run();
assert!(result.success);
let result = ucmd.arg("-o").succeeds();
#[cfg(target_os = "linux")]
assert!(result.stdout.to_lowercase().contains("linux"));
assert!(result.stdout_str().to_lowercase().contains("linux"));
}

View file

@ -4,33 +4,23 @@ use crate::common::util::*;
#[test]
fn test_uptime() {
let result = TestScenario::new(util_name!()).ucmd_keepenv().run();
TestScenario::new(util_name!())
.ucmd_keepenv()
.succeeds()
.stdout_contains("load average:")
.stdout_contains(" up ");
println!("stdout = {}", result.stdout);
println!("stderr = {}", result.stderr);
assert!(result.success);
assert!(result.stdout.contains("load average:"));
assert!(result.stdout.contains(" up "));
// Don't check for users as it doesn't show in some CI
}
#[test]
fn test_uptime_since() {
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("--since").succeeds();
println!("stdout = {}", result.stdout);
println!("stderr = {}", result.stderr);
assert!(result.success);
let re = Regex::new(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}").unwrap();
assert!(re.is_match(&result.stdout.trim()));
new_ucmd!().arg("--since").succeeds().stdout_matches(&re);
}
#[test]
fn test_failed() {
let (_at, mut ucmd) = at_and_ucmd!();
ucmd.arg("willfail").fails();
new_ucmd!().arg("willfail").fails();
}

View file

@ -3,14 +3,11 @@ use std::env;
#[test]
fn test_users_noarg() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(result.success);
new_ucmd!().succeeds();
}
#[test]
fn test_users_check_name() {
let result = TestScenario::new(util_name!()).ucmd_keepenv().run();
assert!(result.success);
let result = TestScenario::new(util_name!()).ucmd_keepenv().succeeds();
// Expectation: USER is often set
let key = "USER";
@ -21,9 +18,9 @@ fn test_users_check_name() {
// Check if "users" contains the name of the user
{
println!("username found {}", &username);
println!("result.stdout {}", &result.stdout);
if !&result.stdout.is_empty() {
assert!(result.stdout.contains(&username))
// println!("result.stdout {}", &result.stdout);
if !result.stdout_str().is_empty() {
result.stdout_contains(&username);
}
}
}

View file

@ -23,7 +23,7 @@ fn test_heading() {
for opt in vec!["-H"] {
// 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;
let actual = new_ucmd!().arg(opt).run().stdout_move_str();
let expect = expected_result(opt);
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
@ -80,5 +80,5 @@ fn expected_result(arg: &str) -> String {
.env("LANGUAGE", "C")
.args(&[arg])
.run()
.stdout
.stdout_move_str()
}

View file

@ -1,50 +1,63 @@
use crate::common::util::*;
use std::env;
// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
// If we are running inside the CI and "needle" is in "stderr" skipping this test is
// 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"
// Maybe: "adduser --uid 1001 username" can put things right?
fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool {
if !result.succeeded() {
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr_str().contains(needle) {
println!("test skipped:");
return true;
} else {
result.success();
}
}
false
}
#[test]
fn test_normal() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
println!("env::var(CI).is_ok() = {}", env::var("CI").is_ok());
for (key, value) in env::vars() {
println!("{}: {}", key, value);
}
if is_ci() && result.stderr.contains("failed to get username") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
// use std::env;
// println!("env::var(CI).is_ok() = {}", env::var("CI").is_ok());
// for (key, value) in env::vars() {
// println!("{}: {}", key, value);
// }
if skipping_test_is_okay(&result, "failed to get username") {
return;
}
assert!(result.success);
assert!(!result.stdout.trim().is_empty());
result.no_stderr();
assert!(!result.stdout_str().trim().is_empty());
}
#[test]
#[cfg(not(windows))]
fn test_normal_compare_id() {
let (_, mut ucmd) = at_and_ucmd!();
let scene = TestScenario::new(util_name!());
let result = ucmd.run();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
if is_ci() && result.stderr.contains("failed to get username") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let result_ucmd = scene.ucmd().run();
if skipping_test_is_okay(&result_ucmd, "failed to get username") {
return;
}
assert!(result.success);
let ts = TestScenario::new("id");
let id = ts.cmd("id").arg("-un").run();
if is_ci() && id.stderr.contains("cannot find name for user ID") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
let result_cmd = scene.cmd("id").arg("-un").run();
if skipping_test_is_okay(&result_cmd, "cannot find name for user ID") {
return;
}
assert_eq!(result.stdout.trim(), id.stdout.trim());
assert_eq!(
result_ucmd.stdout_str().trim(),
result_cmd.stdout_str().trim()
);
}