Repository: jprochazk/garde (Rust)

Issue:
Remove unnecessary colon inside a validation error of a newtype pattern
Could we remove a colon from a tuple struct (newtype pattern) with `#[garde(transperent)`?

For an example:
```rust
use garde::Validate;

#[derive(garde::Validate)]
#[garde(transparent)]
struct Username(
    #[garde(length(max = 50))]
    String,
);

fn main() {
    let a = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    println!("{}", Username(a.into()).validate(&()).unwrap_err().to_string());
}
```

This code will print this:
```
: length is greater than 50
```

I suppose that without a colon, this error message might look better.


Discussion:

Patch:
diff --git a/garde/src/error.rs b/garde/src/error.rs
index e775565..001703d 100644
--- a/garde/src/error.rs
+++ b/garde/src/error.rs
@@ -50,7 +50,11 @@ impl Report {
 impl std::fmt::Display for Report {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         for (path, error) in self.iter() {
-            writeln!(f, "{path}: {error}")?;
+            if path.is_empty() {
+                writeln!(f, "{error}")?;
+            } else {
+                writeln!(f, "{path}: {error}")?;
+            }
         }
         Ok(())
     }


Test patch:
diff --git a/garde/tests/rules/newtype.rs b/garde/tests/rules/newtype.rs
index c2a23a2..5304a91 100644
--- a/garde/tests/rules/newtype.rs
+++ b/garde/tests/rules/newtype.rs
@@ -9,10 +9,30 @@ struct NonEmptyStr_Struct<'a> {
     v: &'a str,
 }
 
+#[test]
+fn newtype_struct_valid() {
+    util::check_ok(&[NonEmptyStr_Struct { v: "test" }], &());
+}
+
+#[test]
+fn newtype_struct_invalid() {
+    util::check_fail!(&[NonEmptyStr_Struct { v: "" }], &());
+}
+
 #[derive(Debug, garde::Validate)]
 #[garde(transparent)]
 struct NonEmptyStr_Tuple<'a>(#[garde(length(min = 1))] &'a str);
 
+#[test]
+fn newtype_tuple_valid() {
+    util::check_ok(&[NonEmptyStr_Tuple("test")], &());
+}
+
+#[test]
+fn newtype_tuple_invalid() {
+    util::check_fail!(&[NonEmptyStr_Tuple("")], &());
+}
+
 #[derive(Debug, garde::Validate)]
 
 struct Test<'a> {
@@ -23,7 +43,7 @@ struct Test<'a> {
 }
 
 #[test]
-fn newtype_valid() {
+fn newtype_fields_valid() {
     util::check_ok(
         &[Test {
             a: NonEmptyStr_Struct { v: "test" },
@@ -34,7 +54,7 @@ fn newtype_valid() {
 }
 
 #[test]
-fn newtype_invalid() {
+fn newtype_fields_invalid() {
     util::check_fail!(
         &[Test {
             a: NonEmptyStr_Struct { v: "" },
diff --git a/garde/tests/rules/snapshots/rules__rules__newtype__newtype_fields_invalid.snap b/garde/tests/rules/snapshots/rules__rules__newtype__newtype_fields_invalid.snap
new file mode 100644
index 0000000..e00267b
--- /dev/null
+++ b/garde/tests/rules/snapshots/rules__rules__newtype__newtype_fields_invalid.snap
@@ -0,0 +1,16 @@
+---
+source: garde/tests/./rules/newtype.rs
+expression: snapshot
+---
+Test {
+    a: NonEmptyStr_Struct {
+        v: "",
+    },
+    b: NonEmptyStr_Tuple(
+        "",
+    ),
+}
+a: length is lower than 1
+b: length is lower than 1
+
+
diff --git a/garde/tests/rules/snapshots/rules__rules__newtype__newtype_struct_invalid.snap b/garde/tests/rules/snapshots/rules__rules__newtype__newtype_struct_invalid.snap
new file mode 100644
index 0000000..58abbec
--- /dev/null
+++ b/garde/tests/rules/snapshots/rules__rules__newtype__newtype_struct_invalid.snap
@@ -0,0 +1,10 @@
+---
+source: garde/tests/./rules/newtype.rs
+expression: snapshot
+---
+NonEmptyStr_Struct {
+    v: "",
+}
+length is lower than 1
+
+
diff --git a/garde/tests/rules/snapshots/rules__rules__newtype__newtype_tuple_invalid.snap b/garde/tests/rules/snapshots/rules__rules__newtype__newtype_tuple_invalid.snap
new file mode 100644
index 0000000..b437d3f
--- /dev/null
+++ b/garde/tests/rules/snapshots/rules__rules__newtype__newtype_tuple_invalid.snap
@@ -0,0 +1,10 @@
+---
+source: garde/tests/./rules/newtype.rs
+expression: snapshot
+---
+NonEmptyStr_Tuple(
+    "",
+)
+length is lower than 1
+
+
diff --git a/garde/tests/rules/util.rs b/garde/tests/rules/util.rs
index 7095d4e..b643b22 100644
--- a/garde/tests/rules/util.rs
+++ b/garde/tests/rules/util.rs
@@ -13,8 +13,8 @@ pub fn check_ok<T: Validate + Debug>(cases: &[T], ctx: &T::Context) {
                 "{} input: {case:?}, errors: [{}]",
                 "FAIL".red(),
                 report
-                    .iter()
-                    .map(|(path, error)| format!("{path}: {error}"))
+                    .to_string()
+                    .split('\n')
                     .collect::<Vec<_>>()
                     .join("; ")
             );
@@ -34,9 +34,7 @@ pub fn __check_fail<T: Validate + Debug>(cases: &[T], ctx: &T::Context) -> Strin
     for case in cases {
         if let Err(report) = case.validate(ctx) {
             writeln!(&mut snapshot, "{case:#?}").unwrap();
-            for (path, error) in report.iter() {
-                writeln!(&mut snapshot, "{path}: {error}").unwrap();
-            }
+            write!(&mut snapshot, "{report}").unwrap();
             writeln!(&mut snapshot).unwrap();
         } else {
             eprintln!("{} input: {case:?}", "SUCCESS".red());