task/
environment_variable.rs

1use alloc::{ffi::CString, format};
2use core::fmt::Debug;
3use synchronization::Arc;
4
5#[derive(Clone, Eq, PartialEq, Hash)]
6pub struct EnvironmentVariable(Arc<CString>, usize);
7
8impl Debug for EnvironmentVariable {
9    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
10        formatter
11            .debug_struct("EnvironmentVariable")
12            .field("Name", &self.get_name())
13            .field("Value", &self.get_value())
14            .finish()
15    }
16}
17
18impl EnvironmentVariable {
19    /// Create a new environment variable.
20    pub fn new(name: &str, value: &str) -> Self {
21        let environment_variable = CString::new(format!("{name}={value}")).unwrap();
22        Self(Arc::new(environment_variable), name.len())
23    }
24
25    /// Create a new environment variable from a raw string.
26    ///
27    /// # Example
28    ///
29    /// ```
30    /// use task::EnvironmentVariable;
31    ///
32    /// let Environment_variable = EnvironmentVariable::new("Name", "Value");
33    ///
34    /// assert_eq!(Environment_variable.get_name(), "Name");
35    /// ```
36    pub fn get_name(&self) -> &str {
37        self.0.to_str().unwrap()[..self.1].trim_end_matches('\0')
38    }
39
40    /// Get the value of the environment variable.
41    ///
42    /// # Example
43    ///
44    /// ```
45    /// use task::EnvironmentVariable;
46    ///
47    /// let Environment_variable = EnvironmentVariable::new("Name", "Value");
48    ///
49    /// assert_eq!(Environment_variable.get_value(), "Value");
50    /// ```
51    pub fn get_value(&self) -> &str {
52        self.0.to_str().unwrap()[self.1 + 1..].trim_end_matches('\0')
53    }
54
55    /// Get the inner raw CString.
56    pub fn get_raw(&self) -> &CString {
57        &self.0
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_environment_variable_creation() {
67        let env_var = EnvironmentVariable::new("PATH", "/usr/bin:/bin");
68
69        assert_eq!(env_var.get_name(), "PATH");
70        assert_eq!(env_var.get_value(), "/usr/bin:/bin");
71    }
72
73    #[test]
74    fn test_environment_variable_empty_name() {
75        let env_var = EnvironmentVariable::new("", "some_value");
76
77        assert_eq!(env_var.get_name(), "");
78        assert_eq!(env_var.get_value(), "some_value");
79    }
80
81    #[test]
82    fn test_environment_variable_empty_value() {
83        let env_var = EnvironmentVariable::new("EMPTY_VAR", "");
84
85        assert_eq!(env_var.get_name(), "EMPTY_VAR");
86        assert_eq!(env_var.get_value(), "");
87    }
88
89    #[test]
90    fn test_environment_variable_both_empty() {
91        let env_var = EnvironmentVariable::new("", "");
92
93        assert_eq!(env_var.get_name(), "");
94        assert_eq!(env_var.get_value(), "");
95    }
96
97    #[test]
98    fn test_environment_variable_special_characters() {
99        let name = "TEST_VAR";
100        let value = "value with spaces and !@#$%^&*()";
101        let env_var = EnvironmentVariable::new(name, value);
102
103        assert_eq!(env_var.get_name(), name);
104        assert_eq!(env_var.get_value(), value);
105    }
106
107    #[test]
108    fn test_environment_variable_equals_in_value() {
109        let name = "CONFIG";
110        let value = "key=value=another=part";
111        let env_var = EnvironmentVariable::new(name, value);
112
113        assert_eq!(env_var.get_name(), name);
114        assert_eq!(env_var.get_value(), value);
115    }
116
117    #[test]
118    fn test_environment_variable_unicode() {
119        let name = "UNICODE_VAR";
120        let value = "🦀 Rust is awesome! 中文测试";
121        let env_var = EnvironmentVariable::new(name, value);
122
123        assert_eq!(env_var.get_name(), name);
124        assert_eq!(env_var.get_value(), value);
125    }
126
127    #[test]
128    fn test_environment_variable_clone() {
129        let env_var1 = EnvironmentVariable::new("HOME", "/home/user");
130        let env_var2 = env_var1.clone();
131
132        assert_eq!(env_var1.get_name(), env_var2.get_name());
133        assert_eq!(env_var1.get_value(), env_var2.get_value());
134        assert_eq!(env_var1, env_var2);
135    }
136
137    #[test]
138    fn test_environment_variable_equality() {
139        let env_var1 = EnvironmentVariable::new("USER", "alice");
140        let env_var2 = EnvironmentVariable::new("USER", "alice");
141        let env_var3 = EnvironmentVariable::new("USER", "bob");
142        let env_var4 = EnvironmentVariable::new("HOME", "alice");
143
144        assert_eq!(env_var1, env_var2);
145        assert_ne!(env_var1, env_var3);
146        assert_ne!(env_var1, env_var4);
147    }
148
149    #[test]
150    fn test_environment_variable_hash() {
151        use std::collections::HashMap;
152
153        let env_var1 = EnvironmentVariable::new("PATH", "/usr/bin");
154        let env_var2 = EnvironmentVariable::new("HOME", "/home/user");
155        let env_var3 = EnvironmentVariable::new("PATH", "/usr/bin"); // Same as env_var1
156
157        let mut map = HashMap::new();
158        map.insert(env_var1.clone(), "first");
159        map.insert(env_var2.clone(), "second");
160
161        // Should not create a new entry since it's the same as env_var1
162        map.insert(env_var3.clone(), "third");
163
164        assert_eq!(map.len(), 2);
165        assert_eq!(map.get(&env_var1), Some(&"third")); // Should be overwritten
166        assert_eq!(map.get(&env_var2), Some(&"second"));
167        assert_eq!(map.get(&env_var3), Some(&"third"));
168    }
169
170    #[test]
171    fn test_environment_variable_debug_format() {
172        let env_var = EnvironmentVariable::new("DEBUG_VAR", "debug_value");
173        let debug_string = format!("{env_var:?}");
174
175        assert!(debug_string.contains("EnvironmentVariable"));
176        assert!(debug_string.contains("DEBUG_VAR"));
177        assert!(debug_string.contains("debug_value"));
178    }
179
180    #[test]
181    fn test_environment_variable_get_raw() {
182        let name = "RAW_TEST";
183        let value = "raw_value";
184        let env_var = EnvironmentVariable::new(name, value);
185        let raw_cstring = env_var.get_raw();
186
187        assert_eq!(raw_cstring.to_str().unwrap(), "RAW_TEST=raw_value");
188    }
189
190    #[test]
191    fn test_environment_variable_long_name_and_value() {
192        let long_name = "A".repeat(1000);
193        let long_value = "B".repeat(2000);
194        let env_var = EnvironmentVariable::new(&long_name, &long_value);
195
196        assert_eq!(env_var.get_name(), long_name);
197        assert_eq!(env_var.get_value(), long_value);
198    }
199
200    #[test]
201    fn test_environment_variable_single_character() {
202        let env_var = EnvironmentVariable::new("A", "B");
203
204        assert_eq!(env_var.get_name(), "A");
205        assert_eq!(env_var.get_value(), "B");
206    }
207
208    #[test]
209    fn test_environment_variable_newlines_and_tabs() {
210        let name = "MULTILINE";
211        let value = "line1\nline2\tvalue";
212        let env_var = EnvironmentVariable::new(name, value);
213
214        assert_eq!(env_var.get_name(), name);
215        assert_eq!(env_var.get_value(), value);
216    }
217
218    #[test]
219    fn test_environment_variable_arc_sharing() {
220        let env_var1 = EnvironmentVariable::new("SHARED", "value");
221        let env_var2 = env_var1.clone();
222
223        // Both should point to the same Arc
224        assert_eq!(Arc::as_ptr(&env_var1.0), Arc::as_ptr(&env_var2.0));
225
226        // Values should be identical
227        assert_eq!(env_var1.get_name(), env_var2.get_name());
228        assert_eq!(env_var1.get_value(), env_var2.get_value());
229    }
230}