Repository: uutils/coreutils (Rust)

Issue:
cksum: show error if a directory is specified
GNU `cksum` shows an error and returns an exit code of `1` if a directory is specified:
```
$ cksum dir file
cksum: dir: Is a directory
4294967295 0 file
$ echo $?
1
```
uutils `cksum`, on the other hand, doesn't show an error and returns an exit code of `0`:
```
$ cargo run cksum dir file
4294967295 0 dir
4294967295 0 file
$ echo $?
0
```
The same applies to `-a`/`--algorithm` with all algorithms.


Discussion:
Is this a generalization of https://github.com/uutils/coreutils/pull/5804? I was just thinking there that blake2b wouldn't be the only case. In https://github.com/uutils/coreutils/pull/5804, the error is generated manually, but "Is a directory" usually comes from an io error. I think it's probably worth investigating what our `cksum` is even doing on directories.
Yes, it is a generalization of it.
I could take on this issue too if it is ok, should be a small modification.
Sure, go ahead :)



Patch:
diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs
index a3e6dfd9e1a..458177e8a7c 100644
--- a/src/uu/cksum/src/cksum.rs
+++ b/src/uu/cksum/src/cksum.rs
@@ -15,8 +15,8 @@ use std::io::{self, stdin, stdout, BufReader, Read, Write};
 use std::iter;
 use std::path::Path;
 use uucore::{
-    error::{FromIo, UError, UResult},
-    format_usage, help_about, help_section, help_usage,
+    error::{FromIo, UError, UResult, USimpleError},
+    format_usage, help_about, help_section, help_usage, show,
     sum::{
         div_ceil, Blake2b, Digest, DigestWriter, Md5, Sha1, Sha224, Sha256, Sha384, Sha512, Sm3,
         BSD, CRC, SYSV,
@@ -174,7 +174,13 @@ where
         });
         let (sum, sz) = digest_read(&mut options.digest, &mut file, options.output_bits)
             .map_err_context(|| "failed to read input".to_string())?;
-
+        if filename.is_dir() {
+            show!(USimpleError::new(
+                1,
+                format!("{}: Is a directory", filename.display())
+            ));
+            continue;
+        }
         if options.raw {
             let bytes = match options.algo_name {
                 ALGORITHM_OPTIONS_CRC => sum.parse::<u32>().unwrap().to_be_bytes().to_vec(),
@@ -214,13 +220,6 @@ where
             (ALGORITHM_OPTIONS_CRC, true) => println!("{sum} {sz}"),
             (ALGORITHM_OPTIONS_CRC, false) => println!("{sum} {sz} {}", filename.display()),
             (ALGORITHM_OPTIONS_BLAKE2B, _) if !options.untagged => {
-                if filename.is_dir() {
-                    return Err(io::Error::new(
-                        io::ErrorKind::InvalidInput,
-                        format!("{}: Is a directory", filename.display()),
-                    )
-                    .into());
-                }
                 if let Some(length) = options.length {
                     // Multiply by 8 here, as we want to print the length in bits.
                     println!("BLAKE2b-{} ({}) = {sum}", length * 8, filename.display());


Test patch:
diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs
index b3db0bf0a02..80cfc749931 100644
--- a/tests/by-util/test_cksum.rs
+++ b/tests/by-util/test_cksum.rs
@@ -80,18 +80,6 @@ fn test_nonexisting_file() {
         .stderr_contains(format!("cksum: {file_name}: No such file or directory"));
 }
 
-#[test]
-fn test_folder() {
-    let (at, mut ucmd) = at_and_ucmd!();
-
-    let folder_name = "a_folder";
-    at.mkdir(folder_name);
-
-    ucmd.arg(folder_name)
-        .succeeds()
-        .stdout_only(format!("4294967295 0 {folder_name}\n"));
-}
-
 // Make sure crc is correct for files larger than 32 bytes
 // but <128 bytes (1 fold pclmul) // spell-checker:disable-line
 #[test]
@@ -312,15 +300,52 @@ fn test_raw_multiple_files() {
 }
 
 #[test]
-fn test_blake2b_fail_on_directory() {
+fn test_fail_on_folder() {
     let (at, mut ucmd) = at_and_ucmd!();
 
     let folder_name = "a_folder";
     at.mkdir(folder_name);
 
-    ucmd.arg("--algorithm=blake2b")
-        .arg(folder_name)
+    ucmd.arg(folder_name)
         .fails()
         .no_stdout()
         .stderr_contains(format!("cksum: {folder_name}: Is a directory"));
 }
+
+#[test]
+fn test_all_algorithms_fail_on_folder() {
+    let scene = TestScenario::new(util_name!());
+
+    let at = &scene.fixtures;
+
+    let folder_name = "a_folder";
+    at.mkdir(folder_name);
+
+    for algo in ALGOS {
+        scene
+            .ucmd()
+            .arg(format!("--algorithm={algo}"))
+            .arg(folder_name)
+            .fails()
+            .no_stdout()
+            .stderr_contains(format!("cksum: {folder_name}: Is a directory"));
+    }
+}
+
+#[test]
+fn test_folder_and_file() {
+    let scene = TestScenario::new(util_name!());
+
+    let at = &scene.fixtures;
+
+    let folder_name = "a_folder";
+    at.mkdir(folder_name);
+
+    scene
+        .ucmd()
+        .arg(folder_name)
+        .arg("lorem_ipsum.txt")
+        .fails()
+        .stderr_contains(format!("cksum: {folder_name}: Is a directory"))
+        .stdout_is_fixture("crc_single_file.expected");
+}