riglr_config/
environment.rs

1//! Environment-specific configuration support
2
3use std::env;
4
5/// Custom environment variable resolver function type
6pub type EnvResolver = Box<dyn Fn(&str) -> Option<String> + Send + Sync>;
7
8/// Source of environment variables (for testing and custom providers)
9pub enum EnvironmentSource {
10    /// Use system environment variables
11    System,
12    /// Use custom environment provider (for testing)
13    #[allow(dead_code)]
14    Custom(EnvResolver),
15}
16
17impl std::fmt::Debug for EnvironmentSource {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        match self {
20            Self::System => write!(f, "System"),
21            Self::Custom(_) => write!(f, "Custom(...)"),
22        }
23    }
24}
25
26impl Clone for EnvironmentSource {
27    fn clone(&self) -> Self {
28        match self {
29            Self::System => Self::System,
30            // For Custom variant, we can't clone the function, so we just return System
31            // This is only used in tests anyway
32            Self::Custom(_) => Self::System,
33        }
34    }
35}
36
37impl Default for EnvironmentSource {
38    fn default() -> Self {
39        Self::System
40    }
41}
42
43impl EnvironmentSource {
44    /// Get environment variable value
45    pub fn get(&self, key: &str) -> Option<String> {
46        match self {
47            Self::System => env::var(key).ok(),
48            Self::Custom(provider) => provider(key),
49        }
50    }
51
52    /// Check if environment variable exists
53    #[allow(dead_code)]
54    pub fn exists(&self, key: &str) -> bool {
55        self.get(key).is_some()
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use std::collections::HashMap;
63
64    // Constants for environment variable names used in tests
65    const TEST_VAR_EXISTS: &str = "TEST_VAR_EXISTS";
66    const TEST_VAR_NOT_EXISTS: &str = "TEST_VAR_NOT_EXISTS";
67    const CUSTOM_VAR: &str = "CUSTOM_VAR";
68    const NON_EXISTENT_VAR: &str = "NON_EXISTENT_VAR";
69    const EXISTS_VAR: &str = "EXISTS_VAR";
70    const NOT_EXISTS_VAR: &str = "NOT_EXISTS_VAR";
71
72    // Helper to create a custom environment source for testing
73    fn create_test_env(vars: HashMap<String, String>) -> EnvironmentSource {
74        EnvironmentSource::Custom(Box::new(move |key: &str| vars.get(key).cloned()))
75    }
76
77    #[test]
78    fn test_environment_source_system_get_when_var_exists_should_return_some() {
79        // Set a test environment variable
80        env::set_var(TEST_VAR_EXISTS, "test_value");
81
82        let source = EnvironmentSource::System;
83        let result = source.get(TEST_VAR_EXISTS);
84
85        assert_eq!(result, Some("test_value".to_string()));
86
87        // Clean up
88        env::remove_var(TEST_VAR_EXISTS);
89    }
90
91    #[test]
92    fn test_environment_source_system_get_when_var_not_exists_should_return_none() {
93        let source = EnvironmentSource::System;
94        let result = source.get(TEST_VAR_NOT_EXISTS);
95
96        assert_eq!(result, None);
97    }
98
99    #[test]
100    fn test_environment_source_custom_get_when_var_exists_should_return_some() {
101        let mut vars = HashMap::new();
102        vars.insert(CUSTOM_VAR.to_string(), "custom_value".to_string());
103
104        let source = create_test_env(vars);
105        let result = source.get(CUSTOM_VAR);
106
107        assert_eq!(result, Some("custom_value".to_string()));
108    }
109
110    #[test]
111    fn test_environment_source_custom_get_when_var_not_exists_should_return_none() {
112        let vars = HashMap::new();
113
114        let source = create_test_env(vars);
115        let result = source.get(NON_EXISTENT_VAR);
116
117        assert_eq!(result, None);
118    }
119
120    #[test]
121    fn test_environment_source_default_should_be_system() {
122        let source = EnvironmentSource::default();
123
124        match source {
125            EnvironmentSource::System => {
126                // Expected
127            }
128            _ => panic!("Default should be System"),
129        }
130    }
131
132    #[test]
133    fn test_environment_source_exists_when_var_exists_should_return_true() {
134        let mut vars = HashMap::new();
135        vars.insert(EXISTS_VAR.to_string(), "value".to_string());
136
137        let source = create_test_env(vars);
138        let result = source.exists(EXISTS_VAR);
139
140        assert!(result);
141    }
142
143    #[test]
144    fn test_environment_source_exists_when_var_not_exists_should_return_false() {
145        let vars = HashMap::new();
146
147        let source = create_test_env(vars);
148        let result = source.exists(NOT_EXISTS_VAR);
149
150        assert!(!result);
151    }
152}