vtcode_commons/
validation.rs1use anyhow::{Result, bail};
4use std::path::Path;
5
6pub fn validate_non_empty(value: &str, field_name: &str) -> Result<()> {
8 if value.trim().is_empty() {
9 bail!("{} cannot be empty", field_name);
10 }
11 Ok(())
12}
13
14pub fn validate_non_empty_string(value: String, field_name: &str) -> Result<String> {
16 if value.trim().is_empty() {
17 bail!("{} cannot be empty", field_name);
18 }
19 Ok(value)
20}
21
22pub fn validate_optional_non_empty(value: &Option<String>, field_name: &str) -> Result<()> {
24 if let Some(v) = value {
25 validate_non_empty(v, field_name)?;
26 }
27 Ok(())
28}
29
30pub fn validate_non_empty_collection<T>(collection: &[T], field_name: &str) -> Result<()> {
32 if collection.is_empty() {
33 bail!("{} collection cannot be empty", field_name);
34 }
35 Ok(())
36}
37
38pub fn validate_all_non_empty(values: &[String], field_name: &str) -> Result<()> {
40 for (i, value) in values.iter().enumerate() {
41 if value.trim().is_empty() {
42 bail!("{}[{}] cannot be empty", field_name, i);
43 }
44 }
45 Ok(())
46}
47
48pub fn validate_path_exists(path: &Path, field_name: &str) -> Result<()> {
50 if !path.exists() {
51 bail!("{} path does not exist: {}", field_name, path.display());
52 }
53 Ok(())
54}
55
56pub fn validate_is_file(path: &Path, field_name: &str) -> Result<()> {
58 validate_path_exists(path, field_name)?;
59 if !path.is_file() {
60 bail!("{} is not a file: {}", field_name, path.display());
61 }
62 Ok(())
63}
64
65pub fn validate_is_directory(path: &Path, field_name: &str) -> Result<()> {
67 validate_path_exists(path, field_name)?;
68 if !path.is_dir() {
69 bail!("{} is not a directory: {}", field_name, path.display());
70 }
71 Ok(())
72}
73
74pub fn validate_url_format(url: &str, field_name: &str) -> Result<()> {
76 if !url.starts_with("http://") && !url.starts_with("https://") {
77 bail!(
78 "{} must be a valid URL starting with http:// or https://",
79 field_name
80 );
81 }
82 Ok(())
83}
84
85pub fn validate_identifier(id: &str, field_name: &str) -> Result<()> {
87 if id.is_empty() {
88 bail!("{} cannot be empty", field_name);
89 }
90 if !id
91 .chars()
92 .all(|c| c.is_alphanumeric() || c == '_' || c == '-')
93 {
94 bail!("{} must be alphanumeric (can include _ or -)", field_name);
95 }
96 Ok(())
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_validate_non_empty() {
105 assert!(validate_non_empty("test", "field").is_ok());
106 assert!(validate_non_empty("", "field").is_err());
107 assert!(validate_non_empty(" ", "field").is_err());
108 }
109
110 #[test]
111 fn test_validate_all_non_empty() {
112 assert!(validate_all_non_empty(&["a".to_string(), "b".to_string()], "field").is_ok());
113 assert!(validate_all_non_empty(&["a".to_string(), "".to_string()], "field").is_err());
114 assert!(validate_all_non_empty(&[], "field").is_ok());
115 }
116}