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