Repository: Stebalien/xattr (language: rust)

Issue:
Cannot use unwrap_err() on xattr::list()
I'm trying to do a test for my filesystem like this:

```rust
#[test]
fn whiteouted_listxattr() {
    let error = xattr::list(session.mountpoint.join("whiteouted_file")).unwrap_err();
    assert_eq!(
        Errno::from_raw(error.raw_os_error().unwrap()),
        Errno::ENOENT
    );
}
```

But it fails to compile with the following error:

```
error[E0277]: `XAttrs` doesn't implement `Debug`
    --> src/main.rs:589:77
     |
589  | ...in("whiteouted_file")).unwrap_err();
     |                           ^^^^^^^^^^ `XAttrs` cannot be formatted using `{:?}` because it doesn't implement `Debug`
     |
     = help: the trait `Debug` is not implemented for `XAttrs`
note: required by a bound in `Result::<T, E>::unwrap_err`
    --> /home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:1195:12
     |
1193 |     pub fn unwrap_err(self) -> E
     |            ---------- required by a bound in this associated function
1194 |     where
1195 |         T: fmt::Debug,
     |            ^^^^^^^^^^ required by this bound in `Result::<T, E>::unwrap_err`
```

It seems that `unwrap_err()` cannot be used on `Result<XAttrs>` because `XAttrs` does not implement `Debug`. Could it be made to implement it?


Discussion / hints:

Fix patch:
diff --git a/src/lib.rs b/src/lib.rs
index d15f1a53..e9aa173c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,9 +32,9 @@ mod util;
 
 use std::ffi::OsStr;
 use std::fs::File;
-use std::io;
 use std::os::unix::io::{AsRawFd, BorrowedFd};
 use std::path::Path;
+use std::{fmt, io};
 
 pub use error::UnsupportedPlatformError;
 pub use sys::{XAttrs, SUPPORTED_PLATFORM};
@@ -153,3 +153,16 @@ pub trait FileExt: AsRawFd {
 }
 
 impl FileExt for File {}
+
+impl fmt::Debug for XAttrs {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Waiting on https://github.com/rust-lang/rust/issues/117729 to stabilize...
+        struct AsList<'a>(&'a XAttrs);
+        impl<'a> fmt::Debug for AsList<'a> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                f.debug_list().entries(self.0.clone()).finish()
+            }
+        }
+        f.debug_tuple("XAttrs").field(&AsList(self)).finish()
+    }
+}
diff --git a/src/sys/unsupported.rs b/src/sys/unsupported.rs
index 1839e300..19a38c84 100644
--- a/src/sys/unsupported.rs
+++ b/src/sys/unsupported.rs
@@ -8,7 +8,7 @@ use crate::UnsupportedPlatformError;
 pub const ENOATTR: i32 = 0;
 
 /// An iterator over a set of extended attributes names.
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Default)]
 pub struct XAttrs;
 
 impl Iterator for XAttrs {


Test patch:
diff --git a/tests/main.rs b/tests/main.rs
index d6650da3..09ade19e 100644
--- a/tests/main.rs
+++ b/tests/main.rs
@@ -85,6 +85,28 @@ fn test_missing() {
     assert!(xattr::get("/var/empty/does-not-exist", "user.test").is_err());
 }
 
+#[test]
+#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
+fn test_debug() {
+    // Only works on "real" filesystems.
+    let tmp = tempfile_in("/var/tmp").unwrap();
+
+    tmp.set_xattr("user.myattr", b"value").unwrap();
+    let mut attrs = tmp.list_xattr().unwrap();
+
+    // Debug is idempotent
+    assert_eq!(format!("{:?}", attrs), format!("{:?}", attrs));
+
+    // It produces the right value.
+    assert_eq!(r#"XAttrs(["user.myattr"])"#, format!("{:?}", attrs));
+
+    // It doesn't affect the underlying iterator.
+    assert_eq!("user.myattr", attrs.next().unwrap());
+
+    // An empty iterator produces the right value.
+    assert_eq!(r#"XAttrs([])"#, format!("{:?}", attrs));
+}
+
 #[test]
 #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
 fn test_multi() {