1pub mod temporal;
6pub mod value;
7
8pub use temporal::TemporalValue;
9pub use value::EloValue;
10
11use std::fmt;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct ValidationError {
16 pub path: String,
18 pub message: String,
20 pub rule: String,
22 pub value: Option<String>,
24}
25
26impl ValidationError {
27 pub fn new(
29 path: impl Into<String>,
30 message: impl Into<String>,
31 rule: impl Into<String>,
32 ) -> Self {
33 Self {
34 path: path.into(),
35 message: message.into(),
36 rule: rule.into(),
37 value: None,
38 }
39 }
40
41 pub fn with_value(mut self, value: impl Into<String>) -> Self {
43 self.value = Some(value.into());
44 self
45 }
46}
47
48impl fmt::Display for ValidationError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "{}: {}", self.path, self.message)
51 }
52}
53
54impl std::error::Error for ValidationError {}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct ValidationErrors {
59 pub errors: Vec<ValidationError>,
61}
62
63impl ValidationErrors {
64 pub fn new() -> Self {
66 Self { errors: Vec::new() }
67 }
68
69 pub fn push(&mut self, error: ValidationError) {
71 self.errors.push(error);
72 }
73
74 pub fn is_empty(&self) -> bool {
76 self.errors.is_empty()
77 }
78
79 pub fn len(&self) -> usize {
81 self.errors.len()
82 }
83}
84
85impl Default for ValidationErrors {
86 fn default() -> Self {
87 Self::new()
88 }
89}
90
91impl fmt::Display for ValidationErrors {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 for (i, err) in self.errors.iter().enumerate() {
94 if i > 0 {
95 writeln!(f)?;
96 }
97 write!(f, "{}", err)?;
98 }
99 Ok(())
100 }
101}
102
103impl std::error::Error for ValidationErrors {}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_validation_error_creation() {
111 let err = ValidationError::new("email", "Invalid email", "email_pattern");
112 assert_eq!(err.path, "email");
113 assert_eq!(err.message, "Invalid email");
114 assert_eq!(err.rule, "email_pattern");
115 assert_eq!(err.value, None);
116 }
117
118 #[test]
119 fn test_validation_error_with_value() {
120 let err =
121 ValidationError::new("email", "Invalid email", "email_pattern").with_value("invalid@");
122 assert_eq!(err.value, Some("invalid@".to_string()));
123 }
124
125 #[test]
126 fn test_validation_error_display() {
127 let err = ValidationError::new("email", "Invalid email", "email_pattern");
128 assert_eq!(err.to_string(), "email: Invalid email");
129 }
130
131 #[test]
132 fn test_validation_errors_collection() {
133 let mut errors = ValidationErrors::new();
134 assert!(errors.is_empty());
135 assert_eq!(errors.len(), 0);
136
137 errors.push(ValidationError::new("email", "Invalid", "rule1"));
138 assert!(!errors.is_empty());
139 assert_eq!(errors.len(), 1);
140
141 errors.push(ValidationError::new("age", "Too young", "rule2"));
142 assert_eq!(errors.len(), 2);
143 }
144}