ic_dbms_api/validate/
web.rs1use ic_dbms_api::prelude::{IcDbmsError, Value};
2
3use crate::prelude::Validate;
4
5pub struct MimeTypeValidator;
19
20impl Validate for MimeTypeValidator {
21 fn validate(&self, value: &crate::prelude::Value) -> ic_dbms_api::prelude::IcDbmsResult<()> {
22 let Value::Text(text) = value else {
23 return Err(IcDbmsError::Validation("Value is not a Text".to_string()));
24 };
25
26 let s = &text.0;
27
28 let parts: Vec<&str> = s.split('/').collect();
30 if parts.len() != 2 {
31 return Err(IcDbmsError::Validation(format!(
32 "MIME type '{s}' must contain exactly one '/'"
33 )));
34 }
35
36 let is_valid_part = |part: &str| {
37 !part.is_empty()
38 && part
39 .chars()
40 .all(|c| c.is_ascii_alphanumeric() || "+.-".contains(c))
41 };
42
43 if !is_valid_part(parts[0]) {
44 return Err(IcDbmsError::Validation(format!(
45 "MIME type '{s}' has invalid type part"
46 )));
47 }
48 if !is_valid_part(parts[1]) {
49 return Err(IcDbmsError::Validation(format!(
50 "MIME type '{s}' has invalid subtype part"
51 )));
52 }
53
54 Ok(())
55 }
56}
57
58pub struct UrlValidator;
69
70impl Validate for UrlValidator {
71 fn validate(&self, value: &crate::prelude::Value) -> ic_dbms_api::prelude::IcDbmsResult<()> {
72 let Value::Text(text) = value else {
73 return Err(IcDbmsError::Validation("Value is not a Text".to_string()));
74 };
75
76 let s = &text.0;
77
78 if url::Url::parse(s).is_err() {
79 return Err(IcDbmsError::Validation(format!(
80 "Value '{s}' is not a valid URL"
81 )));
82 }
83
84 Ok(())
85 }
86}
87
88#[cfg(test)]
89mod tests {
90
91 use super::*;
92
93 #[test]
94 fn test_should_not_validate_mime_if_not_text() {
95 let value = Value::Uint32(crate::prelude::Uint32(42));
96 let result = MimeTypeValidator.validate(&value);
97 assert!(result.is_err());
98 }
99
100 #[test]
101 fn test_mime_type_validator() {
102 let valid_mime_types = vec![
103 "text/plain",
104 "image/jpeg",
105 "application/json",
106 "application/vnd.api+json",
107 "audio/mpeg",
108 ];
109 for mime in valid_mime_types {
110 let value = Value::Text(crate::prelude::Text(mime.to_string()));
111 assert!(
112 MimeTypeValidator.validate(&value).is_ok(),
113 "MIME type '{mime}' should be valid"
114 );
115 }
116 }
117
118 #[test]
119 fn test_invalid_mime_type_validator() {
120 let invalid_mime_types = vec![
121 "textplain",
122 "image//jpeg",
123 "/json",
124 "application/vnd.api+json/extra",
125 "audio/mpeg/",
126 "audio/mpe g",
127 ];
128 for mime in invalid_mime_types {
129 let value = Value::Text(crate::prelude::Text(mime.to_string()));
130 assert!(
131 MimeTypeValidator.validate(&value).is_err(),
132 "MIME type '{mime}' should be invalid"
133 );
134 }
135 }
136
137 #[test]
138 fn test_url_validator() {
139 let valid_urls = vec![
140 "http://example.com",
141 "https://example.com/path?query=param#fragment",
142 "ftp://ftp.example.com/resource",
143 "mailto:christian@example.com",
144 ];
145 for url in valid_urls {
146 let value = Value::Text(crate::prelude::Text(url.to_string()));
147 assert!(
148 UrlValidator.validate(&value).is_ok(),
149 "URL '{url}' should be valid"
150 );
151 }
152 }
153
154 #[test]
155 fn test_invalid_url_validator() {
156 let invalid_urls = vec![
157 "://missing.scheme.com",
159 "http//missing.colon.com",
160 "justastring",
161 "http://in valid.com",
162 ];
163 for url in invalid_urls {
164 let value = Value::Text(crate::prelude::Text(url.to_string()));
165 assert!(
166 UrlValidator.validate(&value).is_err(),
167 "URL '{url}' should be invalid"
168 );
169 }
170 }
171
172 #[test]
173 fn test_should_not_validate_url_if_not_text() {
174 let value = Value::Uint32(crate::prelude::Uint32(42));
175 let result = UrlValidator.validate(&value);
176 assert!(result.is_err());
177 }
178}