Skip to main content

ai_agent/utils/
env_validation.rs

1// Source: ~/claudecode/openclaudecode/src/utils/envValidation.rs
2
3use serde::Serialize;
4
5/// Result of validating a bounded integer environment variable.
6#[derive(Debug, Clone, Serialize)]
7pub struct EnvVarValidationResult {
8    /// The effective value to use.
9    pub effective: i64,
10    /// Validation status.
11    pub status: ValidationStatus,
12    /// Optional message describing what happened.
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub message: Option<String>,
15}
16
17/// Validation status for environment variable.
18#[derive(Debug, Clone, Serialize)]
19#[serde(rename_all = "snake_case")]
20pub enum ValidationStatus {
21    Valid,
22    Capped,
23    Invalid,
24}
25
26/// Validate a bounded integer environment variable.
27pub fn validate_bounded_int_env_var(
28    name: &str,
29    value: Option<&str>,
30    default_value: i64,
31    upper_limit: i64,
32) -> EnvVarValidationResult {
33    let Some(value) = value else {
34        return EnvVarValidationResult {
35            effective: default_value,
36            status: ValidationStatus::Valid,
37            message: None,
38        };
39    };
40
41    let parsed = value.parse::<i64>();
42    if let Ok(parsed) = parsed {
43        if parsed <= 0 {
44            let message =
45                format!("Invalid value \"{}\" (using default: {})", value, default_value);
46            eprintln!("{} {}", name, message);
47            return EnvVarValidationResult {
48                effective: default_value,
49                status: ValidationStatus::Invalid,
50                message: Some(message),
51            };
52        }
53
54        if parsed > upper_limit {
55            let message = format!("Capped from {} to {}", parsed, upper_limit);
56            eprintln!("{} {}", name, message);
57            return EnvVarValidationResult {
58                effective: upper_limit,
59                status: ValidationStatus::Capped,
60                message: Some(message),
61            };
62        }
63
64        return EnvVarValidationResult {
65            effective: parsed,
66            status: ValidationStatus::Valid,
67            message: None,
68        };
69    }
70
71    let message = format!("Invalid value \"{}\" (using default: {})", value, default_value);
72    eprintln!("{} {}", name, message);
73    EnvVarValidationResult {
74        effective: default_value,
75        status: ValidationStatus::Invalid,
76        message: Some(message),
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn test_default_when_none() {
86        let result = validate_bounded_int_env_var("TEST_VAR", None, 10, 100);
87        assert_eq!(result.effective, 10);
88        assert!(matches!(result.status, ValidationStatus::Valid));
89    }
90
91    #[test]
92    fn test_valid_value() {
93        let result = validate_bounded_int_env_var("TEST_VAR", Some("50"), 10, 100);
94        assert_eq!(result.effective, 50);
95        assert!(matches!(result.status, ValidationStatus::Valid));
96    }
97
98    #[test]
99    fn test_capped_value() {
100        let result = validate_bounded_int_env_var("TEST_VAR", Some("200"), 10, 100);
101        assert_eq!(result.effective, 100);
102        assert!(matches!(result.status, ValidationStatus::Capped));
103    }
104
105    #[test]
106    fn test_invalid_value() {
107        let result = validate_bounded_int_env_var("TEST_VAR", Some("abc"), 10, 100);
108        assert_eq!(result.effective, 10);
109        assert!(matches!(result.status, ValidationStatus::Invalid));
110    }
111
112    #[test]
113    fn test_negative_value() {
114        let result = validate_bounded_int_env_var("TEST_VAR", Some("-5"), 10, 100);
115        assert_eq!(result.effective, 10);
116        assert!(matches!(result.status, ValidationStatus::Invalid));
117    }
118}