mirror of
https://github.com/uutils/coreutils
synced 2024-12-23 19:43:15 +00:00
ce1323ce1c
Setting the current directory in tests affects other tests, even if the change is reverted after, because tests are run in parallel. This should fix the flaky cp tests.
1304 lines
36 KiB
Rust
1304 lines
36 KiB
Rust
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE
|
|
|
|
use crate::common::util::*;
|
|
#[cfg(not(windows))]
|
|
use std::fs::set_permissions;
|
|
|
|
#[cfg(not(windows))]
|
|
use std::os::unix::fs;
|
|
|
|
#[cfg(target_os = "linux")]
|
|
use std::os::unix::fs::PermissionsExt;
|
|
#[cfg(windows)]
|
|
use std::os::windows::fs::symlink_file;
|
|
|
|
#[cfg(target_os = "linux")]
|
|
use filetime::FileTime;
|
|
#[cfg(target_os = "linux")]
|
|
use rlimit::Resource;
|
|
#[cfg(target_os = "linux")]
|
|
use std::fs as std_fs;
|
|
#[cfg(target_os = "linux")]
|
|
use std::thread::sleep;
|
|
#[cfg(target_os = "linux")]
|
|
use std::time::Duration;
|
|
|
|
static TEST_EXISTING_FILE: &str = "existing_file.txt";
|
|
static TEST_HELLO_WORLD_SOURCE: &str = "hello_world.txt";
|
|
static TEST_HELLO_WORLD_SOURCE_SYMLINK: &str = "hello_world.txt.link";
|
|
static TEST_HELLO_WORLD_DEST: &str = "copy_of_hello_world.txt";
|
|
static TEST_HOW_ARE_YOU_SOURCE: &str = "how_are_you.txt";
|
|
static TEST_HOW_ARE_YOU_DEST: &str = "hello_dir/how_are_you.txt";
|
|
static TEST_COPY_TO_FOLDER: &str = "hello_dir/";
|
|
static TEST_COPY_TO_FOLDER_FILE: &str = "hello_dir/hello_world.txt";
|
|
static TEST_COPY_FROM_FOLDER: &str = "hello_dir_with_file/";
|
|
static TEST_COPY_FROM_FOLDER_FILE: &str = "hello_dir_with_file/hello_world.txt";
|
|
static TEST_COPY_TO_FOLDER_NEW: &str = "hello_dir_new";
|
|
static TEST_COPY_TO_FOLDER_NEW_FILE: &str = "hello_dir_new/hello_world.txt";
|
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
|
static TEST_MOUNT_COPY_FROM_FOLDER: &str = "dir_with_mount";
|
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
|
static TEST_MOUNT_MOUNTPOINT: &str = "mount";
|
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
|
static TEST_MOUNT_OTHER_FILESYSTEM_FILE: &str = "mount/DO_NOT_copy_me.txt";
|
|
|
|
#[test]
|
|
fn test_cp_cp() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
// Invoke our binary to make the copy.
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.succeeds();
|
|
|
|
// Check the content of the destination file that was copied.
|
|
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_existing_target() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.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");
|
|
|
|
// No backup should have been created
|
|
assert!(!at.file_exists(&*format!("{}~", TEST_EXISTING_FILE)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_duplicate_files() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.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() {
|
|
new_ucmd!()
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_EXISTING_FILE)
|
|
.fails()
|
|
.stderr_contains("not a directory");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_directory_not_recursive() {
|
|
new_ucmd!()
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.fails()
|
|
.stderr_contains("omitting directory");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_multiple_files() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.succeeds();
|
|
|
|
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");
|
|
}
|
|
|
|
#[test]
|
|
// FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590
|
|
#[cfg(not(target_os = "macos"))]
|
|
fn test_cp_recurse() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.arg("-r")
|
|
.arg(TEST_COPY_FROM_FOLDER)
|
|
.arg(TEST_COPY_TO_FOLDER_NEW)
|
|
.succeeds();
|
|
|
|
// Check the content of the destination file that was copied.
|
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_NEW_FILE), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_with_dirs_t() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.arg("-t")
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.succeeds();
|
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
// FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590
|
|
#[cfg(not(target_os = "macos"))]
|
|
fn test_cp_with_dirs() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.succeeds();
|
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.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!();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("-t")
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_no_target_directory() {
|
|
new_ucmd!()
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("-v")
|
|
.arg("-T")
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.fails()
|
|
.stderr_contains("cannot overwrite directory");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_interactive() {
|
|
new_ucmd!()
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.arg("-i")
|
|
.pipe_in("N\n")
|
|
.succeeds()
|
|
.stderr_contains("Not overwriting");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_cp_arg_link() {
|
|
use std::os::linux::fs::MetadataExt;
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("--link")
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.succeeds();
|
|
|
|
assert_eq!(at.metadata(TEST_HELLO_WORLD_SOURCE).st_nlink(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_symlink() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("--symbolic-link")
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.succeeds();
|
|
|
|
assert!(at.is_symlink(TEST_HELLO_WORLD_DEST));
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_no_clobber() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.arg("--no-clobber")
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "How are you?\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_no_clobber_twice() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("source.txt");
|
|
scene
|
|
.ucmd()
|
|
.arg("--no-clobber")
|
|
.arg("source.txt")
|
|
.arg("dest.txt")
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read("source.txt"), "");
|
|
|
|
at.append("source.txt", "some-content");
|
|
scene
|
|
.ucmd()
|
|
.arg("--no-clobber")
|
|
.arg("source.txt")
|
|
.arg("dest.txt")
|
|
.succeeds()
|
|
.stdout_does_not_contain("Not overwriting");
|
|
|
|
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"), "");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(not(windows))]
|
|
fn test_cp_arg_force() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
// create dest without write permissions
|
|
let mut permissions = at
|
|
.make_file(TEST_HELLO_WORLD_DEST)
|
|
.metadata()
|
|
.unwrap()
|
|
.permissions();
|
|
permissions.set_readonly(true);
|
|
set_permissions(at.plus(TEST_HELLO_WORLD_DEST), permissions).unwrap();
|
|
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("--force")
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
|
|
}
|
|
|
|
/// TODO: write a better test that differentiates --remove-destination
|
|
/// from --force. Also this test currently doesn't work on
|
|
/// Windows. This test originally checked file timestamps, which
|
|
/// proved to be unreliable per target / CI platform
|
|
#[test]
|
|
#[cfg(not(windows))]
|
|
fn test_cp_arg_remove_destination() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
// create dest without write permissions
|
|
let mut permissions = at
|
|
.make_file(TEST_HELLO_WORLD_DEST)
|
|
.metadata()
|
|
.unwrap()
|
|
.permissions();
|
|
permissions.set_readonly(true);
|
|
set_permissions(at.plus(TEST_HELLO_WORLD_DEST), permissions).unwrap();
|
|
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("--remove-destination")
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_backup() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.arg("-b")
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_backup_with_other_args() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.arg("-vbL")
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_backup_arg_first() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_arg_suffix() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("-b")
|
|
.arg("--suffix")
|
|
.arg(".bak")
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}.bak", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_custom_backup_suffix_via_env() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let suffix = "super-suffix-of-the-century";
|
|
|
|
ucmd.arg("-b")
|
|
.env("SIMPLE_BACKUP_SUFFIX", suffix)
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}{}", TEST_HOW_ARE_YOU_SOURCE, suffix)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_numbered_with_t() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=t")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_numbered() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=numbered")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_existing() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=existing")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_nil() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=nil")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_numbered_if_existing_backup_existing() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let existing_backup = &*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE);
|
|
at.touch(existing_backup);
|
|
|
|
ucmd.arg("--backup=existing")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert!(at.file_exists(TEST_HOW_ARE_YOU_SOURCE));
|
|
assert!(at.file_exists(existing_backup));
|
|
assert_eq!(
|
|
at.read(&*format!("{}.~2~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_numbered_if_existing_backup_nil() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let existing_backup = &*format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE);
|
|
|
|
at.touch(existing_backup);
|
|
ucmd.arg("--backup=nil")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert!(at.file_exists(TEST_HOW_ARE_YOU_SOURCE));
|
|
assert!(at.file_exists(existing_backup));
|
|
assert_eq!(
|
|
at.read(&*format!("{}.~2~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_simple() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=simple")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_never() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=never")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert_eq!(
|
|
at.read(&*format!("{}~", TEST_HOW_ARE_YOU_SOURCE)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_none() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=none")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert!(!at.file_exists(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_off() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup=off")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds()
|
|
.no_stderr();
|
|
|
|
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
|
assert!(!at.file_exists(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_backup_no_clobber_conflicting_options() {
|
|
let (_, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--backup")
|
|
.arg("--no-clobber")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.fails()
|
|
.stderr_is("cp: options --backup and --no-clobber are mutually exclusive\nTry 'cp --help' for more information.");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_deref_conflicting_options() {
|
|
new_ucmd!()
|
|
.arg("-LP")
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.fails();
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_deref() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
#[cfg(not(windows))]
|
|
let _r = fs::symlink(
|
|
TEST_HELLO_WORLD_SOURCE,
|
|
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
|
);
|
|
#[cfg(windows)]
|
|
let _r = symlink_file(
|
|
TEST_HELLO_WORLD_SOURCE,
|
|
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
|
);
|
|
//using -L option
|
|
ucmd.arg("-L")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HELLO_WORLD_SOURCE_SYMLINK)
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.succeeds();
|
|
|
|
let path_to_new_symlink = at
|
|
.subdir
|
|
.join(TEST_COPY_TO_FOLDER)
|
|
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
|
// unlike -P/--no-deref, we expect a file, not a link
|
|
assert!(at.file_exists(
|
|
&path_to_new_symlink
|
|
.clone()
|
|
.into_os_string()
|
|
.into_string()
|
|
.unwrap()
|
|
));
|
|
// Check the content of the destination file that was copied.
|
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
|
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
|
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
|
}
|
|
#[test]
|
|
fn test_cp_no_deref() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
#[cfg(not(windows))]
|
|
let _r = fs::symlink(
|
|
TEST_HELLO_WORLD_SOURCE,
|
|
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
|
);
|
|
#[cfg(windows)]
|
|
let _r = symlink_file(
|
|
TEST_HELLO_WORLD_SOURCE,
|
|
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
|
);
|
|
//using -P option
|
|
ucmd.arg("-P")
|
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg(TEST_HELLO_WORLD_SOURCE_SYMLINK)
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.succeeds();
|
|
|
|
let path_to_new_symlink = at
|
|
.subdir
|
|
.join(TEST_COPY_TO_FOLDER)
|
|
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
|
assert!(at.is_symlink(
|
|
&path_to_new_symlink
|
|
.clone()
|
|
.into_os_string()
|
|
.into_string()
|
|
.unwrap()
|
|
));
|
|
// Check the content of the destination file that was copied.
|
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
|
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
|
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_strip_trailing_slashes() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
//using --strip-trailing-slashes option
|
|
ucmd.arg("--strip-trailing-slashes")
|
|
.arg(format!("{}/", TEST_HELLO_WORLD_SOURCE))
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.succeeds();
|
|
|
|
// Check the content of the destination file that was copied.
|
|
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_parents() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--parents")
|
|
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.succeeds();
|
|
|
|
assert_eq!(
|
|
at.read(&format!(
|
|
"{}/{}",
|
|
TEST_COPY_TO_FOLDER, TEST_COPY_FROM_FOLDER_FILE
|
|
)),
|
|
"Hello, World!\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_parents_multiple_files() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
ucmd.arg("--parents")
|
|
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.succeeds();
|
|
|
|
assert_eq!(
|
|
at.read(&format!(
|
|
"{}/{}",
|
|
TEST_COPY_TO_FOLDER, TEST_COPY_FROM_FOLDER_FILE
|
|
)),
|
|
"Hello, World!\n"
|
|
);
|
|
assert_eq!(
|
|
at.read(&format!(
|
|
"{}/{}",
|
|
TEST_COPY_TO_FOLDER, TEST_HOW_ARE_YOU_SOURCE
|
|
)),
|
|
"How are you?\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_parents_dest_not_directory() {
|
|
new_ucmd!()
|
|
.arg("--parents")
|
|
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.fails()
|
|
.stderr_contains("with --parents, the destination must be a directory");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cp_preserve_no_args() {
|
|
new_ucmd!()
|
|
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
|
.arg(TEST_HELLO_WORLD_DEST)
|
|
.arg("--preserve")
|
|
.succeeds();
|
|
}
|
|
|
|
#[test]
|
|
// For now, disable the test on Windows. Symlinks aren't well support on Windows.
|
|
// It works on Unix for now and it works locally when run from a powershell
|
|
#[cfg(not(windows))]
|
|
fn test_cp_deref_folder_to_folder() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
let path_to_new_symlink = at.plus(TEST_COPY_FROM_FOLDER);
|
|
|
|
at.symlink_file(
|
|
&path_to_new_symlink
|
|
.join(TEST_HELLO_WORLD_SOURCE)
|
|
.to_string_lossy(),
|
|
&path_to_new_symlink
|
|
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK)
|
|
.to_string_lossy(),
|
|
);
|
|
|
|
//using -P -R option
|
|
scene
|
|
.ucmd()
|
|
.arg("-L")
|
|
.arg("-R")
|
|
.arg("-v")
|
|
.arg(TEST_COPY_FROM_FOLDER)
|
|
.arg(TEST_COPY_TO_FOLDER_NEW)
|
|
.succeeds();
|
|
|
|
#[cfg(not(windows))]
|
|
{
|
|
let scene2 = TestScenario::new("ls");
|
|
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
|
|
println!("ls source {}", result.stdout_str());
|
|
|
|
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
|
|
|
|
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
|
|
println!("ls dest {}", result.stdout_str());
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
{
|
|
// No action as this test is disabled but kept in case we want to
|
|
// try to make it work in the future.
|
|
let a = Command::new("cmd").args(&["/C", "dir"]).output();
|
|
println!("output {:#?}", a);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", &at.as_string()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
|
|
let path_to_new_symlink = at.subdir.join(TEST_COPY_FROM_FOLDER);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
|
|
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
}
|
|
|
|
let path_to_new_symlink = at
|
|
.subdir
|
|
.join(TEST_COPY_TO_FOLDER_NEW)
|
|
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
|
assert!(at.file_exists(
|
|
&path_to_new_symlink
|
|
.clone()
|
|
.into_os_string()
|
|
.into_string()
|
|
.unwrap()
|
|
));
|
|
|
|
let path_to_new = at.subdir.join(TEST_COPY_TO_FOLDER_NEW_FILE);
|
|
|
|
// Check the content of the destination file that was copied.
|
|
let path_to_check = path_to_new.to_str().unwrap();
|
|
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
|
|
|
// Check the content of the symlink
|
|
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
|
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
// For now, disable the test on Windows. Symlinks aren't well support on Windows.
|
|
// It works on Unix for now and it works locally when run from a powershell
|
|
#[cfg(not(windows))]
|
|
fn test_cp_no_deref_folder_to_folder() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
let path_to_new_symlink = at.plus(TEST_COPY_FROM_FOLDER);
|
|
|
|
at.symlink_file(
|
|
&path_to_new_symlink
|
|
.join(TEST_HELLO_WORLD_SOURCE)
|
|
.to_string_lossy(),
|
|
&path_to_new_symlink
|
|
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK)
|
|
.to_string_lossy(),
|
|
);
|
|
|
|
//using -P -R option
|
|
scene
|
|
.ucmd()
|
|
.arg("-P")
|
|
.arg("-R")
|
|
.arg("-v")
|
|
.arg(TEST_COPY_FROM_FOLDER)
|
|
.arg(TEST_COPY_TO_FOLDER_NEW)
|
|
.succeeds();
|
|
|
|
#[cfg(not(windows))]
|
|
{
|
|
let scene2 = TestScenario::new("ls");
|
|
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
|
|
println!("ls source {}", result.stdout_str());
|
|
|
|
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
|
|
|
|
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
|
|
println!("ls dest {}", result.stdout_str());
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
{
|
|
// No action as this test is disabled but kept in case we want to
|
|
// try to make it work in the future.
|
|
let a = Command::new("cmd").args(&["/C", "dir"]).output();
|
|
println!("output {:#?}", a);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", &at.as_string()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
|
|
let path_to_new_symlink = at.subdir.join(TEST_COPY_FROM_FOLDER);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
|
|
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
|
|
|
|
let a = Command::new("cmd")
|
|
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
|
.output();
|
|
println!("output {:#?}", a);
|
|
}
|
|
|
|
let path_to_new_symlink = at
|
|
.subdir
|
|
.join(TEST_COPY_TO_FOLDER_NEW)
|
|
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
|
assert!(at.is_symlink(
|
|
&path_to_new_symlink
|
|
.clone()
|
|
.into_os_string()
|
|
.into_string()
|
|
.unwrap()
|
|
));
|
|
|
|
let path_to_new = at.subdir.join(TEST_COPY_TO_FOLDER_NEW_FILE);
|
|
|
|
// Check the content of the destination file that was copied.
|
|
let path_to_check = path_to_new.to_str().unwrap();
|
|
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
|
|
|
// Check the content of the symlink
|
|
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
|
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_cp_archive() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let ts = time::now().to_timespec();
|
|
let previous = FileTime::from_unix_time(ts.sec as i64 - 3600, ts.nsec as u32);
|
|
// set the file creation/modification an hour ago
|
|
filetime::set_file_times(
|
|
at.plus_as_string(TEST_HELLO_WORLD_SOURCE),
|
|
previous,
|
|
previous,
|
|
)
|
|
.unwrap();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("--archive")
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds();
|
|
|
|
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();
|
|
let creation = metadata.modified().unwrap();
|
|
|
|
let metadata2 = std_fs::metadata(at.subdir.join(TEST_HOW_ARE_YOU_SOURCE)).unwrap();
|
|
let creation2 = metadata2.modified().unwrap();
|
|
|
|
let scene2 = TestScenario::new("ls");
|
|
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).succeeds();
|
|
|
|
println!("ls dest {}", result.stdout_str());
|
|
assert_eq!(creation, creation2);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_cp_archive_recursive() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
// creates
|
|
// dir/1
|
|
// dir/1.link => dir/1
|
|
// dir/2
|
|
// dir/2.link => dir/2
|
|
|
|
let file_1 = at.subdir.join(TEST_COPY_TO_FOLDER).join("1");
|
|
let file_1_link = at.subdir.join(TEST_COPY_TO_FOLDER).join("1.link");
|
|
let file_2 = at.subdir.join(TEST_COPY_TO_FOLDER).join("2");
|
|
let file_2_link = at.subdir.join(TEST_COPY_TO_FOLDER).join("2.link");
|
|
|
|
at.touch(&file_1.to_string_lossy());
|
|
at.touch(&file_2.to_string_lossy());
|
|
|
|
at.symlink_file("1", &file_1_link.to_string_lossy());
|
|
at.symlink_file("2", &file_2_link.to_string_lossy());
|
|
|
|
ucmd.arg("--archive")
|
|
.arg(TEST_COPY_TO_FOLDER)
|
|
.arg(TEST_COPY_TO_FOLDER_NEW)
|
|
.succeeds();
|
|
|
|
let scene2 = TestScenario::new("ls");
|
|
let result = scene2
|
|
.cmd("ls")
|
|
.arg("-al")
|
|
.arg(&at.subdir.join(TEST_COPY_TO_FOLDER))
|
|
.run();
|
|
|
|
println!("ls dest {}", result.stdout_str());
|
|
|
|
let result = scene2
|
|
.cmd("ls")
|
|
.arg("-al")
|
|
.arg(&at.subdir.join(TEST_COPY_TO_FOLDER_NEW))
|
|
.run();
|
|
|
|
println!("ls dest {}", result.stdout_str());
|
|
assert!(at.file_exists(
|
|
&at.subdir
|
|
.join(TEST_COPY_TO_FOLDER_NEW)
|
|
.join("1")
|
|
.to_string_lossy()
|
|
));
|
|
assert!(at.file_exists(
|
|
&at.subdir
|
|
.join(TEST_COPY_TO_FOLDER_NEW)
|
|
.join("2")
|
|
.to_string_lossy()
|
|
));
|
|
|
|
assert!(at.is_symlink(
|
|
&at.subdir
|
|
.join(TEST_COPY_TO_FOLDER_NEW)
|
|
.join("1.link")
|
|
.to_string_lossy()
|
|
));
|
|
assert!(at.is_symlink(
|
|
&at.subdir
|
|
.join(TEST_COPY_TO_FOLDER_NEW)
|
|
.join("2.link")
|
|
.to_string_lossy()
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_cp_preserve_timestamps() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let ts = time::now().to_timespec();
|
|
let previous = FileTime::from_unix_time(ts.sec as i64 - 3600, ts.nsec as u32);
|
|
// set the file creation/modification an hour ago
|
|
filetime::set_file_times(
|
|
at.plus_as_string(TEST_HELLO_WORLD_SOURCE),
|
|
previous,
|
|
previous,
|
|
)
|
|
.unwrap();
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("--preserve=timestamps")
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds();
|
|
|
|
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();
|
|
let creation = metadata.modified().unwrap();
|
|
|
|
let metadata2 = std_fs::metadata(at.subdir.join(TEST_HOW_ARE_YOU_SOURCE)).unwrap();
|
|
let creation2 = metadata2.modified().unwrap();
|
|
|
|
let scene2 = TestScenario::new("ls");
|
|
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).run();
|
|
|
|
println!("ls dest {}", result.stdout_str());
|
|
assert_eq!(creation, creation2);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_cp_no_preserve_timestamps() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let ts = time::now().to_timespec();
|
|
let previous = FileTime::from_unix_time(ts.sec as i64 - 3600, ts.nsec as u32);
|
|
// set the file creation/modification an hour ago
|
|
filetime::set_file_times(
|
|
at.plus_as_string(TEST_HELLO_WORLD_SOURCE),
|
|
previous,
|
|
previous,
|
|
)
|
|
.unwrap();
|
|
sleep(Duration::from_secs(3));
|
|
|
|
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
|
.arg("--no-preserve=timestamps")
|
|
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
|
.succeeds();
|
|
|
|
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();
|
|
let creation = metadata.modified().unwrap();
|
|
|
|
let metadata2 = std_fs::metadata(at.subdir.join(TEST_HOW_ARE_YOU_SOURCE)).unwrap();
|
|
let creation2 = metadata2.modified().unwrap();
|
|
|
|
let scene2 = TestScenario::new("ls");
|
|
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).run();
|
|
|
|
println!("ls dest {}", result.stdout_str());
|
|
println!("creation {:?} / {:?}", creation, creation2);
|
|
|
|
assert_ne!(creation, creation2);
|
|
let res = creation.elapsed().unwrap() - creation2.elapsed().unwrap();
|
|
// Some margins with time check
|
|
assert!(res.as_secs() > 3595);
|
|
assert!(res.as_secs() < 3605);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_cp_target_file_dev_null() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let file1 = "/dev/null";
|
|
let file2 = "test_cp_target_file_file_i2";
|
|
|
|
at.touch(file2);
|
|
ucmd.arg(file1).arg(file2).succeeds().no_stderr();
|
|
|
|
assert!(at.file_exists(file2));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
|
fn test_cp_one_file_system() {
|
|
use crate::common::util::AtPath;
|
|
use walkdir::WalkDir;
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
// Test must be run as root (or with `sudo -E`)
|
|
if scene.cmd("whoami").run().stdout_str() != "root\n" {
|
|
return;
|
|
}
|
|
|
|
let at = scene.fixtures.clone();
|
|
let at_src = AtPath::new(&at.plus(TEST_MOUNT_COPY_FROM_FOLDER));
|
|
let at_dst = AtPath::new(&at.plus(TEST_COPY_TO_FOLDER_NEW));
|
|
|
|
// Prepare the mount
|
|
at_src.mkdir(TEST_MOUNT_MOUNTPOINT);
|
|
let mountpoint_path = &at_src.plus_as_string(TEST_MOUNT_MOUNTPOINT);
|
|
|
|
scene
|
|
.cmd("mount")
|
|
.arg("-t")
|
|
.arg("tmpfs")
|
|
.arg("-o")
|
|
.arg("size=640k") // ought to be enough
|
|
.arg("tmpfs")
|
|
.arg(mountpoint_path)
|
|
.succeeds();
|
|
|
|
at_src.touch(TEST_MOUNT_OTHER_FILESYSTEM_FILE);
|
|
|
|
// Begin testing -x flag
|
|
scene
|
|
.ucmd()
|
|
.arg("-rx")
|
|
.arg(TEST_MOUNT_COPY_FROM_FOLDER)
|
|
.arg(TEST_COPY_TO_FOLDER_NEW)
|
|
.succeeds();
|
|
|
|
// Ditch the mount before the asserts
|
|
scene.cmd("umount").arg(mountpoint_path).succeeds();
|
|
|
|
assert!(!at_dst.file_exists(TEST_MOUNT_OTHER_FILESYSTEM_FILE));
|
|
// Check if the other files were copied from the source folder hierarchy
|
|
for entry in WalkDir::new(at_src.as_string()) {
|
|
let entry = entry.unwrap();
|
|
let relative_src = entry
|
|
.path()
|
|
.strip_prefix(at_src.as_string())
|
|
.unwrap()
|
|
.to_str()
|
|
.unwrap();
|
|
|
|
let ft = entry.file_type();
|
|
match (ft.is_dir(), ft.is_file(), ft.is_symlink()) {
|
|
(true, _, _) => assert!(at_dst.dir_exists(relative_src)),
|
|
(_, true, _) => assert!(at_dst.file_exists(relative_src)),
|
|
(_, _, _) => panic!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
|
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.succeeded() {
|
|
// 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(any(target_os = "linux", target_os = "macos"))]
|
|
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(any(target_os = "linux", target_os = "macos"))]
|
|
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(any(target_os = "linux", target_os = "macos"))]
|
|
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");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_cp_reflink_insufficient_permission() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
at.make_file("unreadable")
|
|
.set_permissions(PermissionsExt::from_mode(0o000))
|
|
.unwrap();
|
|
|
|
ucmd.arg("-r")
|
|
.arg("--reflink=auto")
|
|
.arg("unreadable")
|
|
.arg(TEST_EXISTING_FILE)
|
|
.fails()
|
|
.stderr_only("cp: 'unreadable' -> 'existing_file.txt': Permission denied (os error 13)");
|
|
}
|
|
|
|
#[cfg(target_os = "linux")]
|
|
#[test]
|
|
fn test_closes_file_descriptors() {
|
|
new_ucmd!()
|
|
.arg("-r")
|
|
.arg("--reflink=auto")
|
|
.arg("dir_with_10_files/")
|
|
.arg("dir_with_10_files_new/")
|
|
.with_limit(Resource::NOFILE, 9, 9)
|
|
.succeeds();
|
|
}
|
|
|
|
#[test]
|
|
fn test_copy_dir_symlink() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.mkdir("dir");
|
|
at.symlink_dir("dir", "dir-link");
|
|
ucmd.args(&["-r", "dir-link", "copy"]).succeeds();
|
|
assert_eq!(at.resolve_link("copy"), "dir");
|
|
}
|
|
|
|
#[test]
|
|
fn test_copy_dir_with_symlinks() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.mkdir("dir");
|
|
at.make_file("dir/file");
|
|
|
|
TestScenario::new("ln")
|
|
.ucmd()
|
|
.arg("-sr")
|
|
.arg(at.subdir.join("dir/file"))
|
|
.arg(at.subdir.join("dir/file-link"))
|
|
.succeeds();
|
|
|
|
ucmd.args(&["-r", "dir", "copy"]).succeeds();
|
|
assert_eq!(at.resolve_link("copy/file-link"), "file");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(not(windows))]
|
|
fn test_copy_symlink_force() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("file");
|
|
at.symlink_file("file", "file-link");
|
|
at.touch("copy");
|
|
|
|
ucmd.args(&["file-link", "copy", "-f", "--no-dereference"])
|
|
.succeeds();
|
|
assert_eq!(at.resolve_link("copy"), "file");
|
|
}
|