domain_check_lib/
utils.rs1use crate::error::DomainCheckError;
7
8pub fn validate_domain(domain: &str) -> Result<(), DomainCheckError> {
21 let domain = domain.trim();
22
23 if domain.is_empty() {
24 return Err(DomainCheckError::invalid_domain(
25 domain,
26 "Domain name cannot be empty",
27 ));
28 }
29
30 if !domain.contains('.') && domain.len() < 2 {
33 return Err(DomainCheckError::invalid_domain(
34 domain,
35 "Domain name too short",
36 ));
37 }
38
39 Ok(())
40}
41
42#[allow(dead_code)]
54pub fn extract_domain_parts(domain: &str) -> (String, Option<String>) {
55 let parts: Vec<&str> = domain.split('.').collect();
56
57 if parts.len() >= 2 {
58 let base_name = parts[0].to_string();
59 let tld = parts[1..].join(".");
60 (base_name, Some(tld))
61 } else {
62 (domain.to_string(), None)
63 }
64}
65
66pub fn expand_domain_inputs(domains: &[String], tlds: &Option<Vec<String>>) -> Vec<String> {
82 let mut results = Vec::new();
83
84 for domain in domains {
85 let trimmed = domain.trim();
86
87 if trimmed.is_empty() {
89 continue;
90 }
91
92 if trimmed.contains('.') {
93 if is_valid_fqdn(trimmed) {
96 results.push(trimmed.to_string());
97 }
98 } else {
99 if is_valid_base_name(trimmed) {
102 match tlds {
103 Some(tld_list) => {
104 for tld in tld_list {
105 let tld_clean = tld.trim();
106 if !tld_clean.is_empty() {
107 results.push(format!("{}.{}", trimmed, tld_clean));
108 }
109 }
110 }
111 None => {
112 results.push(format!("{}.com", trimmed));
114 }
115 }
116 }
117 }
118 }
119
120 results
121}
122
123fn is_valid_base_name(domain: &str) -> bool {
125 if domain.len() < 2 {
127 return false;
128 }
129
130 if domain.starts_with('-') || domain.ends_with('-') {
133 return false;
134 }
135
136 domain.chars().all(|c| c.is_alphanumeric() || c == '-')
138}
139
140fn is_valid_fqdn(domain: &str) -> bool {
142 if domain.len() < 4 || domain.len() > 253 {
144 return false;
145 }
146
147 if !domain.contains('.') {
149 return false;
150 }
151
152 if domain.starts_with('.')
154 || domain.ends_with('.')
155 || domain.starts_with('-')
156 || domain.ends_with('-')
157 {
158 return false;
159 }
160
161 let parts: Vec<&str> = domain.split('.').collect();
163 if parts.len() < 2 {
164 return false;
165 }
166
167 for part in parts {
169 if part.is_empty() || part.len() > 63 {
170 return false;
171 }
172
173 if part.starts_with('-') || part.ends_with('-') {
175 return false;
176 }
177
178 if !part.chars().all(|c| c.is_alphanumeric() || c == '-') {
180 return false;
181 }
182 }
183
184 true
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_validate_domain() {
193 assert!(validate_domain("example.com").is_ok());
194 assert!(validate_domain("test").is_ok());
195 assert!(validate_domain("").is_err());
196 assert!(validate_domain("a").is_err());
197 }
198
199 #[test]
200 fn test_extract_domain_parts() {
201 assert_eq!(
202 extract_domain_parts("example.com"),
203 ("example".to_string(), Some("com".to_string()))
204 );
205 assert_eq!(
206 extract_domain_parts("test.co.uk"),
207 ("test".to_string(), Some("co.uk".to_string()))
208 );
209 assert_eq!(
210 extract_domain_parts("example"),
211 ("example".to_string(), None)
212 );
213 }
214
215 #[test]
216 fn test_expand_domain_inputs() {
217 let domains = vec!["example".to_string(), "test.com".to_string()];
218 let tlds = Some(vec!["com".to_string(), "org".to_string()]);
219
220 let result = expand_domain_inputs(&domains, &tlds);
221 assert_eq!(
222 result,
223 vec![
224 "example.com",
225 "example.org",
226 "test.com" ]
228 );
229 }
230
231 #[test]
232 fn test_expand_domain_inputs_with_invalid() {
233 let domains = vec![
234 "".to_string(),
235 "a".to_string(),
236 "valid".to_string(),
237 "test.com".to_string(),
238 ];
239 let tlds = Some(vec!["com".to_string(), "org".to_string()]);
240
241 let result = expand_domain_inputs(&domains, &tlds);
242 assert_eq!(result, vec!["valid.com", "valid.org", "test.com"]);
244 }
245
246 #[test]
247 fn test_is_valid_base_name() {
248 assert!(is_valid_base_name("example"));
249 assert!(is_valid_base_name("test-domain"));
250 assert!(is_valid_base_name("abc123"));
251
252 assert!(!is_valid_base_name(""));
253 assert!(!is_valid_base_name("a"));
254 assert!(!is_valid_base_name("-example"));
255 assert!(!is_valid_base_name("example-"));
256 assert!(!is_valid_base_name("test.com")); }
258
259 #[test]
260 fn test_is_valid_fqdn() {
261 assert!(is_valid_fqdn("example.com"));
262 assert!(is_valid_fqdn("test.co.uk"));
263 assert!(is_valid_fqdn("sub.example.com"));
264
265 assert!(!is_valid_fqdn("example"));
266 assert!(!is_valid_fqdn(".com"));
267 assert!(!is_valid_fqdn("example."));
268 assert!(!is_valid_fqdn("-example.com"));
269 assert!(!is_valid_fqdn("example.com-"));
270 assert!(!is_valid_fqdn("ex."));
271 }
272}