From 939ab037a2eb24dc3263f1e9b82c838a30996fb2 Mon Sep 17 00:00:00 2001 From: RustyJack Date: Sun, 21 Dec 2025 10:17:35 +0100 Subject: [PATCH] uucore: use --suffix to enable backup mode (#9741) --- src/uucore/src/lib/features/backup_control.rs | 31 +++++++++++++++++++ tests/by-util/test_cp.rs | 17 ++++++++++ tests/by-util/test_install.rs | 24 ++++++++++++++ tests/by-util/test_ln.rs | 25 +++++++++++++++ tests/by-util/test_mv.rs | 20 ++++++++++++ 5 files changed, 117 insertions(+) diff --git a/src/uucore/src/lib/features/backup_control.rs b/src/uucore/src/lib/features/backup_control.rs index c438a7720..ed6b67034 100644 --- a/src/uucore/src/lib/features/backup_control.rs +++ b/src/uucore/src/lib/features/backup_control.rs @@ -359,6 +359,14 @@ pub fn determine_backup_mode(matches: &ArgMatches) -> UResult { } else { Ok(BackupMode::Existing) } + } else if matches.contains_id(arguments::OPT_SUFFIX) { + // Suffix option is enough to determine mode even if --backup is not set. + // If VERSION_CONTROL is not set, the default backup type is 'existing'. + if let Ok(method) = env::var("VERSION_CONTROL") { + match_method(&method, "$VERSION_CONTROL") + } else { + Ok(BackupMode::Existing) + } } else { // No option was present at all Ok(BackupMode::None) @@ -653,6 +661,29 @@ mod tests { unsafe { env::remove_var(ENV_VERSION_CONTROL) }; } + // Using --suffix without --backup defaults to --backup=existing + #[test] + fn test_backup_mode_suffix_without_backup_option() { + let _dummy = TEST_MUTEX.lock().unwrap(); + let matches = make_app().get_matches_from(vec!["command", "--suffix", ".bak"]); + + let result = determine_backup_mode(&matches).unwrap(); + + assert_eq!(result, BackupMode::Existing); + } + + // Using --suffix without --backup uses env var if existing + #[test] + fn test_backup_mode_suffix_without_backup_option_with_env_var() { + let _dummy = TEST_MUTEX.lock().unwrap(); + unsafe { env::set_var(ENV_VERSION_CONTROL, "numbered") }; + let matches = make_app().get_matches_from(vec!["command", "--suffix", ".bak"]); + + let result = determine_backup_mode(&matches).unwrap(); + + assert_eq!(result, BackupMode::Numbered); + } + #[test] fn test_suffix_takes_hyphen_value() { let _dummy = TEST_MUTEX.lock().unwrap(); diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index c5d1f9390..2563e533a 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1123,6 +1123,23 @@ fn test_cp_arg_suffix() { ); } +#[test] +fn test_cp_arg_suffix_without_backup_option() { + let (at, mut ucmd) = at_and_ucmd!(); + + ucmd.arg(TEST_HELLO_WORLD_SOURCE) + .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!("{TEST_HOW_ARE_YOU_SOURCE}.bak")), + "How are you?\n" + ); +} + #[test] fn test_cp_arg_suffix_hyphen_value() { let (at, mut ucmd) = at_and_ucmd!(); diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index 2a2e7d670..2753a7d3a 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -1231,6 +1231,30 @@ fn test_install_backup_short_custom_suffix() { assert!(at.file_exists(format!("{file_b}{suffix}"))); } +#[test] +fn test_install_suffix_without_backup_option() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let file_a = "test_install_backup_custom_suffix_file_a"; + let file_b = "test_install_backup_custom_suffix_file_b"; + let suffix = "super-suffix-of-the-century"; + + at.touch(file_a); + at.touch(file_b); + scene + .ucmd() + .arg(format!("--suffix={suffix}")) + .arg(file_a) + .arg(file_b) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file_a)); + assert!(at.file_exists(file_b)); + assert!(at.file_exists(format!("{file_b}{suffix}"))); +} + #[test] fn test_install_backup_short_custom_suffix_hyphen_value() { let scene = TestScenario::new(util_name!()); diff --git a/tests/by-util/test_ln.rs b/tests/by-util/test_ln.rs index bc103a629..f2fe23c95 100644 --- a/tests/by-util/test_ln.rs +++ b/tests/by-util/test_ln.rs @@ -194,6 +194,31 @@ fn test_symlink_custom_backup_suffix() { assert_eq!(at.resolve_link(backup), file); } +#[test] +fn test_symlink_suffix_without_backup_option() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.write("a", "a\n"); + at.write("b", "b2\n"); + + assert!(at.file_exists("a")); + assert!(at.file_exists("b")); + let suffix = ".sfx"; + let suffix_arg = &format!("--suffix={suffix}"); + scene + .ucmd() + .args(&["-s", "-f", suffix_arg, "a", "b"]) + .succeeds() + .no_stderr(); + assert!(at.file_exists("a")); + assert!(at.file_exists("b")); + assert_eq!(at.read("a"), "a\n"); + assert_eq!(at.read("b"), "a\n"); + // we should have created backup for b file + assert_eq!(at.read(&format!("b{suffix}")), "b2\n"); +} + #[test] fn test_symlink_custom_backup_suffix_hyphen_value() { let (at, mut ucmd) = at_and_ucmd!(); diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index f28fc8c28..37987e822 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -801,6 +801,26 @@ fn test_mv_custom_backup_suffix() { assert!(at.file_exists(format!("{file_b}{suffix}"))); } +#[test] +fn test_suffix_without_backup_option() { + let (at, mut ucmd) = at_and_ucmd!(); + let file_a = "test_mv_custom_backup_suffix_file_a"; + let file_b = "test_mv_custom_backup_suffix_file_b"; + let suffix = "super-suffix-of-the-century"; + + at.touch(file_a); + at.touch(file_b); + ucmd.arg(format!("--suffix={suffix}")) + .arg(file_a) + .arg(file_b) + .succeeds() + .no_stderr(); + + assert!(!at.file_exists(file_a)); + assert!(at.file_exists(file_b)); + assert!(at.file_exists(format!("{file_b}{suffix}"))); +} + #[test] fn test_mv_custom_backup_suffix_hyphen_value() { let (at, mut ucmd) = at_and_ucmd!();