mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
cp: add readonly file regression tests (#9045)
* feat: add comprehensive readonly file regression tests for cp - Add 10 new test functions covering readonly destination behavior - Tests cover basic readonly copying, flag combinations, and edge cases - Include macOS-specific clonefile behavior tests - Ensure readonly file protection from PR #5261 cannot regress - Tests provide evidence for closing issue #5349 * perf: optimize readonly regression tests with batched I/O operations - Reduce file I/O overhead by batching file operations - Consolidate setup operations to minimize system calls - Improve test execution time from 0.44s to 0.27s (38% improvement) - Maintain comprehensive test coverage for readonly file behavior * fix: remove duplicate tests and trivial comments per PR feedback - Remove test_cp_readonly_dest_regression (duplicate of test_cp_dest_no_permissions) - Remove test_cp_readonly_dest_with_force (duplicate of test_cp_arg_force) - Remove test_cp_readonly_dest_with_remove_destination (duplicate of test_cp_arg_remove_destination) - Remove test_cp_macos_clonefile_readonly (duplicate of test_cp_existing_target) - Remove test_cp_normal_copy_still_works (duplicate of test_cp_existing_target) - Remove trivial performance comments from readonly tests - Keep existing proven tests per maintainer preferences - Keep unique readonly tests that provide additional coverage
This commit is contained in:
@@ -4101,6 +4101,110 @@ fn test_cp_dest_no_permissions() {
|
||||
.stderr_contains("denied");
|
||||
}
|
||||
|
||||
/// Test readonly destination behavior with reflink options
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_cp_readonly_dest_with_reflink() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("source.txt", "source content");
|
||||
at.write("readonly_dest_auto.txt", "original content");
|
||||
at.write("readonly_dest_always.txt", "original content");
|
||||
at.set_readonly("readonly_dest_auto.txt");
|
||||
at.set_readonly("readonly_dest_always.txt");
|
||||
|
||||
// Test reflink=auto
|
||||
ts.ucmd()
|
||||
.args(&["--reflink=auto", "source.txt", "readonly_dest_auto.txt"])
|
||||
.fails()
|
||||
.stderr_contains("readonly_dest_auto.txt");
|
||||
|
||||
// Test reflink=always
|
||||
ts.ucmd()
|
||||
.args(&["--reflink=always", "source.txt", "readonly_dest_always.txt"])
|
||||
.fails()
|
||||
.stderr_contains("readonly_dest_always.txt");
|
||||
|
||||
assert_eq!(at.read("readonly_dest_auto.txt"), "original content");
|
||||
assert_eq!(at.read("readonly_dest_always.txt"), "original content");
|
||||
}
|
||||
|
||||
/// Test readonly destination behavior in recursive directory copy
|
||||
#[test]
|
||||
fn test_cp_readonly_dest_recursive() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.mkdir("source_dir");
|
||||
at.mkdir("dest_dir");
|
||||
at.write("source_dir/file.txt", "source content");
|
||||
at.write("dest_dir/file.txt", "original content");
|
||||
at.set_readonly("dest_dir/file.txt");
|
||||
|
||||
ts.ucmd().args(&["-r", "source_dir", "dest_dir"]).succeeds();
|
||||
|
||||
assert_eq!(at.read("dest_dir/file.txt"), "original content");
|
||||
}
|
||||
|
||||
/// Test copying to readonly file when another file exists
|
||||
#[test]
|
||||
fn test_cp_readonly_dest_with_existing_file() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("source.txt", "source content");
|
||||
at.write("readonly_dest.txt", "original content");
|
||||
at.write("other_file.txt", "other content");
|
||||
at.set_readonly("readonly_dest.txt");
|
||||
|
||||
ts.ucmd()
|
||||
.args(&["source.txt", "readonly_dest.txt"])
|
||||
.fails()
|
||||
.stderr_contains("readonly_dest.txt")
|
||||
.stderr_contains("denied");
|
||||
|
||||
assert_eq!(at.read("readonly_dest.txt"), "original content");
|
||||
assert_eq!(at.read("other_file.txt"), "other content");
|
||||
}
|
||||
|
||||
/// Test readonly source file (should work fine)
|
||||
#[test]
|
||||
fn test_cp_readonly_source() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("readonly_source.txt", "source content");
|
||||
at.write("dest.txt", "dest content");
|
||||
at.set_readonly("readonly_source.txt");
|
||||
|
||||
ts.ucmd()
|
||||
.args(&["readonly_source.txt", "dest.txt"])
|
||||
.succeeds();
|
||||
|
||||
assert_eq!(at.read("dest.txt"), "source content");
|
||||
}
|
||||
|
||||
/// Test readonly source and destination (should fail)
|
||||
#[test]
|
||||
fn test_cp_readonly_source_and_dest() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
|
||||
at.write("readonly_source.txt", "source content");
|
||||
at.write("readonly_dest.txt", "original content");
|
||||
at.set_readonly("readonly_source.txt");
|
||||
at.set_readonly("readonly_dest.txt");
|
||||
|
||||
ts.ucmd()
|
||||
.args(&["readonly_source.txt", "readonly_dest.txt"])
|
||||
.fails()
|
||||
.stderr_contains("readonly_dest.txt")
|
||||
.stderr_contains("denied");
|
||||
|
||||
assert_eq!(at.read("readonly_dest.txt"), "original content");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "freebsd"), not(target_os = "openbsd")))]
|
||||
fn test_cp_attributes_only() {
|
||||
|
||||
Reference in New Issue
Block a user