mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
mv: improve move-to-self error handling (#6995)
- improve move-to-self detection, so this errors without data loss: ```diff mkdir mydir mv mydir mydir/subdir -mv: No such file or directory (os error 2) +mv: cannot move 'mydir' to a subdirectory of itself, 'mydir/subdir' ``` - align "cannot move source to a subdirectory of itself" and "same file" errors more closely with coreutils: ```diff mkdir mydir mv mydir/ mydir/.. -mv: cannot move 'mydir/' to a subdirectory of itself, 'mydir/../mydir/' +mv: 'mydir/' and 'mydir/../mydir' are the same file ``` Causing: https://github.com/nushell/nushell/issues/13082
This commit is contained in:
parent
b4cdc36573
commit
98c9be5ec4
3 changed files with 140 additions and 111 deletions
|
@ -6,6 +6,7 @@
|
|||
// spell-checker:ignore mydir
|
||||
use crate::common::util::TestScenario;
|
||||
use filetime::FileTime;
|
||||
use rstest::rstest;
|
||||
use std::io::Write;
|
||||
|
||||
#[test]
|
||||
|
@ -467,7 +468,31 @@ fn test_mv_same_symlink() {
|
|||
.arg(file_c)
|
||||
.arg(file_a)
|
||||
.fails()
|
||||
.stderr_is(format!("mv: '{file_c}' and '{file_a}' are the same file\n",));
|
||||
.stderr_is(format!("mv: '{file_c}' and '{file_a}' are the same file\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
fn test_mv_same_broken_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.symlink_file("missing-target", "broken");
|
||||
|
||||
ucmd.arg("broken")
|
||||
.arg("broken")
|
||||
.fails()
|
||||
.stderr_is("mv: 'broken' and 'broken' are the same file\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
fn test_mv_symlink_into_target() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.mkdir("dir");
|
||||
at.symlink_file("dir", "dir-link");
|
||||
|
||||
ucmd.arg("dir-link").arg("dir").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1389,24 +1414,6 @@ fn test_mv_interactive_error() {
|
|||
.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_into_self() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
let dir1 = "dir1";
|
||||
let dir2 = "dir2";
|
||||
at.mkdir(dir1);
|
||||
at.mkdir(dir2);
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(dir1)
|
||||
.arg(dir2)
|
||||
.arg(dir2)
|
||||
.fails()
|
||||
.stderr_contains("mv: cannot move 'dir2' to a subdirectory of itself, 'dir2/dir2'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_arg_interactive_skipped() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -1456,27 +1463,32 @@ fn test_mv_into_self_data() {
|
|||
assert!(!at.file_exists(file1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_directory_into_subdirectory_of_itself_fails() {
|
||||
#[rstest]
|
||||
#[case(vec!["mydir"], vec!["mydir", "mydir"], "mv: cannot move 'mydir' to a subdirectory of itself, 'mydir/mydir'")]
|
||||
#[case(vec!["mydir"], vec!["mydir/", "mydir/"], "mv: cannot move 'mydir/' to a subdirectory of itself, 'mydir/mydir'")]
|
||||
#[case(vec!["mydir"], vec!["./mydir", "mydir", "mydir/"], "mv: cannot move './mydir' to a subdirectory of itself, 'mydir/mydir'")]
|
||||
#[case(vec!["mydir"], vec!["mydir/", "mydir/mydir_2/"], "mv: cannot move 'mydir/' to a subdirectory of itself, 'mydir/mydir_2/'")]
|
||||
#[case(vec!["mydir/mydir_2"], vec!["mydir", "mydir/mydir_2"], "mv: cannot move 'mydir' to a subdirectory of itself, 'mydir/mydir_2/mydir'\n")]
|
||||
#[case(vec!["mydir/mydir_2"], vec!["mydir/", "mydir/mydir_2/"], "mv: cannot move 'mydir/' to a subdirectory of itself, 'mydir/mydir_2/mydir'\n")]
|
||||
#[case(vec!["mydir", "mydir_2"], vec!["mydir/", "mydir_2/", "mydir_2/"], "mv: cannot move 'mydir_2/' to a subdirectory of itself, 'mydir_2/mydir_2'")]
|
||||
#[case(vec!["mydir"], vec!["mydir/", "mydir"], "mv: cannot move 'mydir/' to a subdirectory of itself, 'mydir/mydir'")]
|
||||
#[case(vec!["mydir"], vec!["-T", "mydir", "mydir"], "mv: 'mydir' and 'mydir' are the same file")]
|
||||
#[case(vec!["mydir"], vec!["mydir/", "mydir/../"], "mv: 'mydir/' and 'mydir/../mydir' are the same file")]
|
||||
fn test_mv_directory_self(
|
||||
#[case] dirs: Vec<&str>,
|
||||
#[case] args: Vec<&str>,
|
||||
#[case] expected_error: &str,
|
||||
) {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
let dir1 = "mydir";
|
||||
let dir2 = "mydir/mydir_2";
|
||||
at.mkdir(dir1);
|
||||
at.mkdir(dir2);
|
||||
scene.ucmd().arg(dir1).arg(dir2).fails().stderr_contains(
|
||||
"mv: cannot move 'mydir' to a subdirectory of itself, 'mydir/mydir_2/mydir'",
|
||||
);
|
||||
|
||||
// check that it also errors out with /
|
||||
for dir in dirs {
|
||||
at.mkdir_all(dir);
|
||||
}
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(format!("{dir1}/"))
|
||||
.arg(dir2)
|
||||
.args(&args)
|
||||
.fails()
|
||||
.stderr_contains(
|
||||
"mv: cannot move 'mydir/' to a subdirectory of itself, 'mydir/mydir_2/mydir/'",
|
||||
);
|
||||
.stderr_contains(expected_error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1755,23 +1767,3 @@ fn test_mv_error_msg_with_multiple_sources_that_does_not_exist() {
|
|||
.stderr_contains("mv: cannot stat 'a': No such file or directory")
|
||||
.stderr_contains("mv: cannot stat 'b/': No such file or directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_error_cant_move_itself() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.mkdir("b");
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("b")
|
||||
.arg("b/")
|
||||
.fails()
|
||||
.stderr_contains("mv: cannot move 'b' to a subdirectory of itself, 'b/b'");
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("./b")
|
||||
.arg("b")
|
||||
.arg("b/")
|
||||
.fails()
|
||||
.stderr_contains("mv: cannot move 'b' to a subdirectory of itself, 'b/b'");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue