scim_server/resource/value_objects/
schema_uri.rs1use crate::error::{ValidationError, ValidationResult};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct SchemaUri(String);
41
42impl SchemaUri {
43 pub fn new(value: String) -> ValidationResult<Self> {
57 Self::validate_format(&value)?;
58 Ok(Self(value))
59 }
60
61 pub fn as_str(&self) -> &str {
63 &self.0
64 }
65
66 pub fn into_string(self) -> String {
68 self.0
69 }
70
71 fn validate_format(value: &str) -> ValidationResult<()> {
75 if value.is_empty() {
76 return Err(ValidationError::InvalidSchemaUri {
77 uri: value.to_string(),
78 });
79 }
80
81 if !value.starts_with("urn:") {
84 return Err(ValidationError::InvalidSchemaUri {
85 uri: value.to_string(),
86 });
87 }
88
89 if !value.contains("scim:schemas") && !value.contains("test:") {
91 return Err(ValidationError::InvalidSchemaUri {
92 uri: value.to_string(),
93 });
94 }
95
96 Ok(())
97 }
98}
99
100impl fmt::Display for SchemaUri {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 write!(f, "{}", self.0)
103 }
104}
105
106impl Serialize for SchemaUri {
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 SchemaUri {
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 SchemaUri {
126 type Error = ValidationError;
127
128 fn try_from(value: String) -> ValidationResult<Self> {
129 Self::new(value)
130 }
131}
132
133impl TryFrom<&str> for SchemaUri {
134 type Error = ValidationError;
135
136 fn try_from(value: &str) -> ValidationResult<Self> {
137 Self::new(value.to_string())
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use serde_json;
145
146 #[test]
147 fn test_valid_schema_uri() {
148 let uri = SchemaUri::new("urn:ietf:params:scim:schemas:core:2.0:User".to_string());
149 assert!(uri.is_ok());
150 assert_eq!(
151 uri.unwrap().as_str(),
152 "urn:ietf:params:scim:schemas:core:2.0:User"
153 );
154 }
155
156 #[test]
157 fn test_invalid_schema_uri_no_urn() {
158 let result = SchemaUri::new("http://example.com/schema".to_string());
159 assert!(result.is_err());
160
161 match result.unwrap_err() {
162 ValidationError::InvalidSchemaUri { uri } => {
163 assert_eq!(uri, "http://example.com/schema");
164 }
165 other => panic!("Expected InvalidSchemaUri error, got: {:?}", other),
166 }
167 }
168
169 #[test]
170 fn test_invalid_schema_uri_no_scim() {
171 let result = SchemaUri::new("urn:example:other:schema".to_string());
172 assert!(result.is_err());
173 }
174
175 #[test]
176 fn test_empty_schema_uri() {
177 let result = SchemaUri::new("".to_string());
178 assert!(result.is_err());
179 }
180
181 #[test]
182 fn test_serialization() {
183 let uri =
184 SchemaUri::new("urn:ietf:params:scim:schemas:core:2.0:Group".to_string()).unwrap();
185 let json = serde_json::to_string(&uri).unwrap();
186 assert_eq!(json, "\"urn:ietf:params:scim:schemas:core:2.0:Group\"");
187 }
188
189 #[test]
190 fn test_deserialization_valid() {
191 let json = "\"urn:ietf:params:scim:schemas:core:2.0:User\"";
192 let uri: SchemaUri = serde_json::from_str(json).unwrap();
193 assert_eq!(uri.as_str(), "urn:ietf:params:scim:schemas:core:2.0:User");
194 }
195
196 #[test]
197 fn test_deserialization_invalid() {
198 let json = "\"invalid-uri\"";
199 let result: Result<SchemaUri, _> = serde_json::from_str(json);
200 assert!(result.is_err());
201 }
202}