From 2e3f8e247f88511294275a7cce96e34bddcb962b Mon Sep 17 00:00:00 2001 From: Michael Scofield Date: Thu, 12 Mar 2026 12:21:54 +0100 Subject: [PATCH 1/4] implement the thing --- validator/src/display_impl.rs | 2 +- validator/src/types.rs | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/validator/src/display_impl.rs b/validator/src/display_impl.rs index fc71a178..1d64118e 100644 --- a/validator/src/display_impl.rs +++ b/validator/src/display_impl.rs @@ -7,7 +7,7 @@ impl fmt::Display for ValidationError { if let Some(msg) = self.message.as_ref() { write!(fmt, "{}", msg) } else { - write!(fmt, "Validation error: {} [{:?}]", self.code, self.params) + write!(fmt, "Validation error: {} [{}]", self.code, self.params) } } } diff --git a/validator/src/types.rs b/validator/src/types.rs index 9bf49da6..e1054731 100644 --- a/validator/src/types.rs +++ b/validator/src/types.rs @@ -9,12 +9,12 @@ use serde_json::{to_value, Value}; pub struct ValidationError { pub code: Cow<'static, str>, pub message: Option>, - pub params: HashMap, Value>, + pub params: ValidationErrorParams, } impl ValidationError { pub fn new(code: &'static str) -> ValidationError { - ValidationError { code: Cow::from(code), message: None, params: HashMap::new() } + ValidationError { code: Cow::from(code), message: None, params: Default::default() } } pub fn add_param(&mut self, name: Cow<'static, str>, val: &T) { @@ -206,3 +206,30 @@ impl std::error::Error for ValidationErrors { None } } + +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +pub struct ValidationErrorParams(HashMap, Value>); + +impl std::fmt::Display for ValidationErrorParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + f.write_str(&serde_json::to_string_pretty(&self.0).map_err(|_| std::fmt::Error)?) + } else { + f.write_str(&serde_json::to_string(&self.0).map_err(|_| std::fmt::Error)?) + } + } +} + +impl std::ops::Deref for ValidationErrorParams { + type Target = HashMap, Value>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for ValidationErrorParams { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} From a786b69a634c031d7dd2d5912742cdbc6990a673 Mon Sep 17 00:00:00 2001 From: Michael Scofield Date: Mon, 16 Mar 2026 23:45:48 +0100 Subject: [PATCH 2/4] add tests --- validator/src/types.rs | 42 ++++++++++++++++++++++++++++++++++++++ validator/tests/display.rs | 11 ++++++++++ 2 files changed, 53 insertions(+) diff --git a/validator/src/types.rs b/validator/src/types.rs index e1054731..3e1e3135 100644 --- a/validator/src/types.rs +++ b/validator/src/types.rs @@ -233,3 +233,45 @@ impl std::ops::DerefMut for ValidationErrorParams { &mut self.0 } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_params_display_empty() { + let params = ValidationErrorParams::default(); + assert_eq!(format!("{}", params), "{}"); + } + + #[test] + fn test_params_display_with_values() { + let mut params = ValidationErrorParams::default(); + params.insert(Cow::Borrowed("min"), serde_json::json!(5)); + assert_eq!(format!("{}", params), r#"{"min":5}"#); + } + + #[test] + fn test_params_display_alternate() { + let mut params = ValidationErrorParams::default(); + params.insert(Cow::Borrowed("min"), serde_json::json!(5)); + let pretty = format!("{:#}", params); + assert!(pretty.contains('\n'), "alternate format should be pretty-printed"); + assert!(pretty.contains("\"min\": 5")); + } + + #[test] + fn test_params_deref() { + let mut params = ValidationErrorParams::default(); + params.insert(Cow::Borrowed("key"), serde_json::json!("value")); + assert_eq!(params.len(), 1); + assert!(params.contains_key("key")); + } + + #[test] + fn test_params_deref_mut() { + let mut params = ValidationErrorParams::default(); + params.insert(Cow::Borrowed("key"), serde_json::json!(42)); + assert_eq!(params.get("key"), Some(&serde_json::json!(42))); + } +} diff --git a/validator/tests/display.rs b/validator/tests/display.rs index 1423e602..f3db47ff 100644 --- a/validator/tests/display.rs +++ b/validator/tests/display.rs @@ -1,3 +1,14 @@ +#[test] +fn test_validation_error_display_without_message() { + use std::borrow::Cow; + use validator::ValidationError; + + let mut err = ValidationError::new("length"); + err.add_param(Cow::Borrowed("min"), &1); + let display = format!("{}", err); + assert_eq!(display, r#"Validation error: length [{"min":1}]"#); +} + #[cfg(feature = "derive")] mod tests { use validator::Validate; From 187a873b1257c3d51ae4609864f30fa7b759aaf2 Mon Sep 17 00:00:00 2001 From: Michael Scofield Date: Tue, 14 Apr 2026 10:29:39 +0200 Subject: [PATCH 3/4] fix readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marc-Hendric Lühr --- validator/src/types.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/validator/src/types.rs b/validator/src/types.rs index 3e1e3135..864d0c90 100644 --- a/validator/src/types.rs +++ b/validator/src/types.rs @@ -212,11 +212,12 @@ pub struct ValidationErrorParams(HashMap, Value>); impl std::fmt::Display for ValidationErrorParams { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if f.alternate() { - f.write_str(&serde_json::to_string_pretty(&self.0).map_err(|_| std::fmt::Error)?) + let s = if f.alternate() { + serde_json::to_string_pretty(&self.0) } else { - f.write_str(&serde_json::to_string(&self.0).map_err(|_| std::fmt::Error)?) - } + serde_json::to_string(&self.0) + }.map_err(|_| std::fmt::Error)?; + f.write_str(&s); } } From 78c0cbc1aefabcd3b2a754caa0e26b4c94e22cf7 Mon Sep 17 00:00:00 2001 From: Michael Scofield Date: Tue, 14 Apr 2026 11:56:44 +0200 Subject: [PATCH 4/4] add semicolon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marc-Hendric Lühr --- validator/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/types.rs b/validator/src/types.rs index 864d0c90..cc8d8c24 100644 --- a/validator/src/types.rs +++ b/validator/src/types.rs @@ -217,7 +217,7 @@ impl std::fmt::Display for ValidationErrorParams { } else { serde_json::to_string(&self.0) }.map_err(|_| std::fmt::Error)?; - f.write_str(&s); + f.write_str(&s) } }