scim_server/resource/value_objects/
user_name.rs1use crate::error::{ValidationError, ValidationResult};
7use crate::resource::value_objects::value_object_trait::{SchemaConstructible, ValueObject};
8use crate::schema::types::{AttributeDefinition, AttributeType};
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use serde_json::Value;
11use std::any::Any;
12use std::fmt;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44pub struct UserName(String);
45
46impl UserName {
47 pub fn new(value: String) -> ValidationResult<Self> {
61 Self::validate_format(&value)?;
62 Ok(Self(value))
63 }
64
65 pub fn as_str(&self) -> &str {
67 &self.0
68 }
69
70 pub fn into_string(self) -> String {
72 self.0
73 }
74
75 fn validate_format(value: &str) -> ValidationResult<()> {
80 if value.is_empty() {
82 return Err(ValidationError::MissingRequiredAttribute {
83 attribute: "userName".to_string(),
84 });
85 }
86
87 Ok(())
97 }
98}
99
100impl fmt::Display for UserName {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 write!(f, "{}", self.0)
103 }
104}
105
106impl Serialize for UserName {
107 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
108 where
109 S: Serializer,
110 {
111 self.0.serialize(serializer)
112 }
113}
114
115impl<'de> Deserialize<'de> for UserName {
116 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
117 where
118 D: Deserializer<'de>,
119 {
120 let value = String::deserialize(deserializer)?;
121 Self::new(value).map_err(serde::de::Error::custom)
122 }
123}
124
125impl TryFrom<String> for UserName {
126 type Error = ValidationError;
127
128 fn try_from(value: String) -> ValidationResult<Self> {
129 Self::new(value)
130 }
131}
132
133impl TryFrom<&str> for UserName {
134 type Error = ValidationError;
135
136 fn try_from(value: &str) -> ValidationResult<Self> {
137 Self::new(value.to_string())
138 }
139}
140
141impl ValueObject for UserName {
142 fn attribute_type(&self) -> AttributeType {
143 AttributeType::String
144 }
145
146 fn attribute_name(&self) -> &str {
147 "userName"
148 }
149
150 fn to_json(&self) -> ValidationResult<Value> {
151 Ok(Value::String(self.0.clone()))
152 }
153
154 fn validate_against_schema(&self, definition: &AttributeDefinition) -> ValidationResult<()> {
155 if definition.data_type != AttributeType::String {
156 return Err(ValidationError::InvalidAttributeType {
157 attribute: definition.name.clone(),
158 expected: "string".to_string(),
159 actual: format!("{:?}", definition.data_type),
160 });
161 }
162
163 if definition.name != "userName" {
164 return Err(ValidationError::InvalidAttributeName {
165 actual: definition.name.clone(),
166 expected: "userName".to_string(),
167 });
168 }
169
170 Ok(())
171 }
172
173 fn as_json_value(&self) -> Value {
174 Value::String(self.0.clone())
175 }
176
177 fn supports_definition(&self, definition: &AttributeDefinition) -> bool {
178 definition.data_type == AttributeType::String && definition.name == "userName"
179 }
180
181 fn clone_boxed(&self) -> Box<dyn ValueObject> {
182 Box::new(self.clone())
183 }
184
185 fn as_any(&self) -> &dyn Any {
186 self
187 }
188}
189
190impl SchemaConstructible for UserName {
191 fn from_schema_and_value(
192 definition: &AttributeDefinition,
193 value: &Value,
194 ) -> ValidationResult<Self> {
195 if definition.name != "userName" || definition.data_type != AttributeType::String {
196 return Err(ValidationError::UnsupportedAttributeType {
197 attribute: definition.name.clone(),
198 type_name: format!("{:?}", definition.data_type),
199 });
200 }
201
202 if let Some(username_str) = value.as_str() {
203 Self::new(username_str.to_string())
204 } else {
205 Err(ValidationError::InvalidAttributeType {
206 attribute: definition.name.clone(),
207 expected: "string".to_string(),
208 actual: "non-string".to_string(),
209 })
210 }
211 }
212
213 fn can_construct_from(definition: &AttributeDefinition) -> bool {
214 definition.name == "userName" && definition.data_type == AttributeType::String
215 }
216
217 fn constructor_priority() -> u8 {
218 100 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use serde_json;
226
227 #[test]
228 fn test_valid_user_name_email() {
229 let username = UserName::new("bjensen@example.com".to_string());
230 assert!(username.is_ok());
231 assert_eq!(username.unwrap().as_str(), "bjensen@example.com");
232 }
233
234 #[test]
235 fn test_valid_user_name_simple() {
236 let username = UserName::new("bjensen".to_string());
237 assert!(username.is_ok());
238 assert_eq!(username.unwrap().as_str(), "bjensen");
239 }
240
241 #[test]
242 fn test_valid_user_name_with_numbers() {
243 let username = UserName::new("user123".to_string());
244 assert!(username.is_ok());
245 assert_eq!(username.unwrap().as_str(), "user123");
246 }
247
248 #[test]
249 fn test_empty_user_name() {
250 let result = UserName::new("".to_string());
251 assert!(result.is_err());
252
253 match result.unwrap_err() {
254 ValidationError::MissingRequiredAttribute { attribute } => {
255 assert_eq!(attribute, "userName");
256 }
257 other => panic!("Expected MissingRequiredAttribute error, got: {:?}", other),
258 }
259 }
260
261 #[test]
262 fn test_into_string() {
263 let username = UserName::new("test-username".to_string()).unwrap();
264 let string_value = username.into_string();
265 assert_eq!(string_value, "test-username");
266 }
267
268 #[test]
269 fn test_display() {
270 let username = UserName::new("display-test".to_string()).unwrap();
271 assert_eq!(format!("{}", username), "display-test");
272 }
273
274 #[test]
275 fn test_serialization() {
276 let username = UserName::new("serialize-test@example.com".to_string()).unwrap();
277 let json = serde_json::to_string(&username).unwrap();
278 assert_eq!(json, "\"serialize-test@example.com\"");
279 }
280
281 #[test]
282 fn test_deserialization_valid() {
283 let json = "\"deserialize-test@example.com\"";
284 let username: UserName = serde_json::from_str(json).unwrap();
285 assert_eq!(username.as_str(), "deserialize-test@example.com");
286 }
287
288 #[test]
289 fn test_deserialization_invalid() {
290 let json = "\"\""; let result: Result<UserName, _> = serde_json::from_str(json);
292 assert!(result.is_err());
293 }
294
295 #[test]
296 fn test_try_from_string() {
297 let result = UserName::try_from("try-from-test".to_string());
298 assert!(result.is_ok());
299 assert_eq!(result.unwrap().as_str(), "try-from-test");
300
301 let empty_result = UserName::try_from("".to_string());
302 assert!(empty_result.is_err());
303 }
304
305 #[test]
306 fn test_try_from_str() {
307 let result = UserName::try_from("try-from-str-test");
308 assert!(result.is_ok());
309 assert_eq!(result.unwrap().as_str(), "try-from-str-test");
310
311 let empty_result = UserName::try_from("");
312 assert!(empty_result.is_err());
313 }
314
315 #[test]
316 fn test_equality() {
317 let username1 = UserName::new("same-username".to_string()).unwrap();
318 let username2 = UserName::new("same-username".to_string()).unwrap();
319 let username3 = UserName::new("different-username".to_string()).unwrap();
320
321 assert_eq!(username1, username2);
322 assert_ne!(username1, username3);
323 }
324
325 #[test]
326 fn test_hash() {
327 use std::collections::HashMap;
328
329 let username1 = UserName::new("hash-test-1".to_string()).unwrap();
330 let username2 = UserName::new("hash-test-2".to_string()).unwrap();
331
332 let mut map = HashMap::new();
333 map.insert(username1.clone(), "value1");
334 map.insert(username2.clone(), "value2");
335
336 assert_eq!(map.get(&username1), Some(&"value1"));
337 assert_eq!(map.get(&username2), Some(&"value2"));
338 }
339
340 #[test]
341 fn test_clone() {
342 let username = UserName::new("clone-test".to_string()).unwrap();
343 let cloned = username.clone();
344
345 assert_eq!(username, cloned);
346 assert_eq!(username.as_str(), cloned.as_str());
347 }
348}