From fcfc20cda1220fa0f297e3f2d760bc3740d15a4e Mon Sep 17 00:00:00 2001 From: Nihal Ajayakumar Date: Wed, 25 Feb 2026 16:24:20 -0500 Subject: [PATCH 1/2] test: implement -r/-w/-x on Windows --- src/uu/test/src/test.rs | 10 +++++++--- tests/by-util/test_test.rs | 25 ++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index 58cff2684a5..69cadfb4219 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -341,12 +341,16 @@ fn path(path: &OsStr, condition: &PathCondition) -> bool { PathCondition::Sticky => false, PathCondition::UserOwns => unimplemented!(), PathCondition::Fifo => false, - PathCondition::Readable => false, // TODO + PathCondition::Readable => true, PathCondition::Socket => false, PathCondition::NonEmpty => stat.len() > 0, PathCondition::UserIdFlag => false, - PathCondition::Writable => false, // TODO - PathCondition::Executable => false, // TODO + PathCondition::Writable => !stat.permissions().readonly(), + PathCondition::Executable => std::path::Path::new(path) + .extension() + .and_then(|e| e.to_str()) + .map(|e| matches!(e, "exe" | "bat" | "cmd" | "com")) + .unwrap_or(false), } } diff --git a/tests/by-util/test_test.rs b/tests/by-util/test_test.rs index d7f8215bdb5..c767efa69b6 100644 --- a/tests/by-util/test_test.rs +++ b/tests/by-util/test_test.rs @@ -454,7 +454,6 @@ fn test_file_exists_and_is_regular() { } #[test] -#[cfg(not(windows))] // FIXME: implement on Windows fn test_file_is_readable() { new_ucmd!().args(&["-r", "regular_file"]).succeeds(); } @@ -473,7 +472,6 @@ fn test_file_is_not_readable() { } #[test] -#[cfg(not(windows))] // FIXME: implement on Windows fn test_file_is_writable() { new_ucmd!().args(&["-w", "regular_file"]).succeeds(); } @@ -517,7 +515,7 @@ fn test_file_is_not_executable() { } #[test] -#[cfg(not(windows))] // FIXME: implement on Windows +#[cfg(not(windows))] fn test_file_is_executable() { let scenario = TestScenario::new(util_name!()); let mut chmod = scenario.cmd("chmod"); @@ -527,6 +525,27 @@ fn test_file_is_executable() { scenario.ucmd().args(&["-x", "regular_file"]).succeeds(); } +#[test] +#[cfg(windows)] +fn test_file_is_not_writable_windows() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("readonly_file"); + let mut perms = std::fs::metadata(at.plus("readonly_file")) + .unwrap() + .permissions(); + perms.set_readonly(true); + std::fs::set_permissions(at.plus("readonly_file"), perms).unwrap(); + ucmd.args(&["!", "-w", "readonly_file"]).succeeds(); +} + +#[test] +#[cfg(windows)] +fn test_file_is_executable_windows() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("program.exe"); + ucmd.args(&["-x", "program.exe"]).succeeds(); +} + #[test] fn test_is_not_empty() { new_ucmd!().args(&["-s", "non_empty_file"]).succeeds(); From 3c69a2a0843195c21190e0df897cdd6b11e7ef85 Mon Sep 17 00:00:00 2001 From: Nihal Ajayakumar Date: Wed, 25 Feb 2026 21:50:17 -0500 Subject: [PATCH 2/2] test: fix clippy map-then-unwrap_or lint for Windows executable check Replace `.map(...).unwrap_or(false)` with `.is_some_and(...)` to satisfy the `clippy::option_map_unwrap_or` lint on Windows targets. --- src/uu/test/src/test.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index 69cadfb4219..c1766f5481e 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -349,8 +349,7 @@ fn path(path: &OsStr, condition: &PathCondition) -> bool { PathCondition::Executable => std::path::Path::new(path) .extension() .and_then(|e| e.to_str()) - .map(|e| matches!(e, "exe" | "bat" | "cmd" | "com")) - .unwrap_or(false), + .is_some_and(|e| matches!(e, "exe" | "bat" | "cmd" | "com")), } }