source_traits_tests.rs
1 use abundantis::source::{ 2 ParsedVariable, Priority, SourceCapabilities, SourceId, SourceSnapshot, SourceType, 3 VariableSource, 4 }; 5 use std::path::PathBuf; 6 7 #[test] 8 fn test_source_id_creation() { 9 let id = SourceId::new("test-source"); 10 assert_eq!(id.as_str(), "test-source"); 11 12 let id2: SourceId = "test-source".into(); 13 assert_eq!(id, id2); 14 15 let id3: SourceId = String::from("test-source").into(); 16 assert_eq!(id, id3); 17 } 18 19 #[test] 20 fn test_source_id_display() { 21 let id = SourceId::new("test"); 22 let s = format!("{}", id); 23 assert_eq!(s, "test"); 24 } 25 26 #[test] 27 fn test_source_priorities() { 28 assert!(Priority::SHELL > Priority::FILE); 29 assert!(Priority::FILE > Priority::MEMORY); 30 assert_eq!(Priority::SHELL.0, 100); 31 assert_eq!(Priority::FILE.0, 50); 32 assert_eq!(Priority::MEMORY.0, 30); 33 assert_eq!(Priority::REMOTE.0, 75); 34 } 35 36 #[test] 37 fn test_source_capabilities() { 38 let caps = SourceCapabilities::READ | SourceCapabilities::CACHEABLE; 39 assert!(caps.contains(SourceCapabilities::READ)); 40 assert!(caps.contains(SourceCapabilities::CACHEABLE)); 41 assert!(!caps.contains(SourceCapabilities::WRITE)); 42 assert!(!caps.contains(SourceCapabilities::ASYNC_ONLY)); 43 } 44 45 #[test] 46 fn test_source_capabilities_defaults() { 47 let caps = SourceCapabilities::default(); 48 assert!(caps.contains(SourceCapabilities::READ)); 49 assert!(caps.contains(SourceCapabilities::CACHEABLE)); 50 assert!(!caps.contains(SourceCapabilities::WRITE)); 51 } 52 53 #[test] 54 fn test_source_type_equality() { 55 assert_eq!(SourceType::File, SourceType::File); 56 assert_eq!(SourceType::Shell, SourceType::Shell); 57 assert_eq!(SourceType::Memory, SourceType::Memory); 58 assert_eq!(SourceType::Remote, SourceType::Remote); 59 } 60 61 #[test] 62 fn test_source_type_hashing() { 63 use std::collections::HashSet; 64 let mut set = HashSet::new(); 65 set.insert(SourceType::File); 66 set.insert(SourceType::Shell); 67 set.insert(SourceType::Memory); 68 set.insert(SourceType::Remote); 69 assert_eq!(set.len(), 4); 70 } 71 72 #[test] 73 fn test_parsed_variable_simple() { 74 let var = ParsedVariable::simple("KEY", "value", VariableSource::Memory); 75 76 assert_eq!(var.key.as_str(), "KEY"); 77 assert_eq!(var.raw_value.as_str(), "value"); 78 assert!(matches!(var.source, VariableSource::Memory)); 79 assert_eq!(var.description, None); 80 assert!(!var.is_commented); 81 } 82 83 #[test] 84 fn test_parsed_variable_with_description() { 85 let var = ParsedVariable { 86 key: "KEY".into(), 87 raw_value: "value".into(), 88 source: VariableSource::Memory, 89 description: Some("Test description".into()), 90 is_commented: false, 91 }; 92 93 assert_eq!(var.description.as_deref(), Some("Test description")); 94 } 95 96 #[test] 97 fn test_variable_source_file() { 98 let source = VariableSource::File { 99 path: PathBuf::from("/path/to/.env"), 100 offset: 42, 101 }; 102 103 assert_eq!(source.file_path(), Some(&PathBuf::from("/path/to/.env"))); 104 assert_eq!( 105 source.file_path().unwrap().display().to_string(), 106 "/path/to/.env" 107 ); 108 } 109 110 #[test] 111 fn test_variable_source_shell() { 112 let source = VariableSource::Shell; 113 assert_eq!(source.file_path(), None); 114 } 115 116 #[test] 117 fn test_variable_source_remote() { 118 let source = VariableSource::Remote { 119 provider: "doppler".into(), 120 path: Some("secret/path".into()), 121 }; 122 123 assert_eq!(source.file_path(), None); 124 } 125 126 #[test] 127 fn test_source_snapshot_creation() { 128 let vars = vec![ 129 ParsedVariable::simple("KEY1", "val1", VariableSource::Memory), 130 ParsedVariable::simple("KEY2", "val2", VariableSource::Memory), 131 ]; 132 133 let snapshot = SourceSnapshot { 134 source_id: SourceId::new("test"), 135 variables: vars.into(), 136 timestamp: std::time::Instant::now(), 137 version: Some(1), 138 }; 139 140 assert_eq!(snapshot.variables.len(), 2); 141 assert_eq!(snapshot.source_id.as_str(), "test"); 142 assert_eq!(snapshot.version, Some(1)); 143 assert!(snapshot.timestamp.elapsed().as_secs() < 1); 144 } 145 146 #[test] 147 fn test_source_snapshot_arc_conversion() { 148 let vars = vec![ParsedVariable::simple( 149 "KEY", 150 "value", 151 VariableSource::Memory, 152 )]; 153 154 let snapshot = SourceSnapshot { 155 source_id: SourceId::new("test"), 156 variables: vars.into(), 157 timestamp: std::time::Instant::now(), 158 version: None, 159 }; 160 161 let arc_vars = std::sync::Arc::clone(&snapshot.variables); 162 assert_eq!(arc_vars.len(), 1); 163 assert_eq!(arc_vars[0].key.as_str(), "KEY"); 164 } 165 166 #[test] 167 fn test_source_id_clone() { 168 let id1 = SourceId::new("test"); 169 let id2 = id1.clone(); 170 assert_eq!(id1, id2); 171 assert_eq!(id1.as_str(), id2.as_str()); 172 } 173 174 #[test] 175 fn test_source_id_hash() { 176 use std::collections::HashMap; 177 let id1 = SourceId::new("test1"); 178 let id2 = SourceId::new("test2"); 179 180 let mut map = HashMap::new(); 181 map.insert(id1.clone(), "value1"); 182 map.insert(id2.clone(), "value2"); 183 184 assert_eq!(map.get(&id1), Some(&"value1")); 185 assert_eq!(map.get(&id2), Some(&"value2")); 186 } 187 188 #[test] 189 fn test_priority_ordering() { 190 let priorities = [Priority::MEMORY, Priority::FILE, Priority::SHELL]; 191 192 let mut sorted = priorities.to_vec(); 193 sorted.sort(); 194 195 assert_eq!(sorted[0], Priority::MEMORY); 196 assert_eq!(sorted[1], Priority::FILE); 197 assert_eq!(sorted[2], Priority::SHELL); 198 } 199 200 #[test] 201 fn test_priority_comparison() { 202 assert!(Priority::SHELL > Priority::FILE); 203 assert!(Priority::FILE > Priority::MEMORY); 204 assert!(Priority::REMOTE > Priority::FILE); 205 assert!(Priority::SHELL > Priority::MEMORY); 206 207 assert_eq!(Priority::SHELL, Priority::SHELL); 208 assert_ne!(Priority::SHELL, Priority::FILE); 209 } 210 211 #[test] 212 fn test_source_capabilities_combinations() { 213 let _all_caps = SourceCapabilities::all(); 214 215 let read_caps = SourceCapabilities::READ; 216 let write_caps = SourceCapabilities::WRITE; 217 let combined = read_caps | write_caps; 218 219 assert!(combined.contains(SourceCapabilities::READ)); 220 assert!(combined.contains(SourceCapabilities::WRITE)); 221 assert!(!combined.contains(SourceCapabilities::WATCH)); 222 } 223 224 #[test] 225 fn test_source_capabilities_bits() { 226 let caps = SourceCapabilities::READ | SourceCapabilities::WRITE | SourceCapabilities::WATCH; 227 assert_eq!(caps.bits(), 0b00000111); 228 } 229 230 #[test] 231 fn test_variable_source_debug() { 232 let source = VariableSource::File { 233 path: PathBuf::from("/test/.env"), 234 offset: 42, 235 }; 236 237 let debug_str = format!("{:?}", source); 238 assert!(debug_str.contains("File")); 239 assert!(debug_str.contains("/test/.env")); 240 } 241 242 #[test] 243 fn test_parsed_variable_debug() { 244 let var = ParsedVariable::simple("KEY", "value", VariableSource::Memory); 245 let debug_str = format!("{:?}", var); 246 assert!(debug_str.contains("KEY")); 247 assert!(debug_str.contains("value")); 248 assert!(debug_str.contains("Memory")); 249 } 250 251 #[test] 252 fn test_source_snapshot_display() { 253 let snapshot = SourceSnapshot { 254 source_id: SourceId::new("test-source"), 255 variables: vec![].into(), 256 timestamp: std::time::Instant::now(), 257 version: Some(42), 258 }; 259 260 let display = format!("{:?}", snapshot); 261 assert!(display.contains("test-source")); 262 } 263 264 #[test] 265 fn test_multiple_source_ids() { 266 let ids = [ 267 SourceId::new("source1"), 268 SourceId::new("source2"), 269 SourceId::new("source3"), 270 ]; 271 272 assert_eq!(ids.len(), 3); 273 assert_ne!(ids[0], ids[1]); 274 assert_ne!(ids[1], ids[2]); 275 assert_ne!(ids[0], ids[2]); 276 } 277 278 #[test] 279 fn test_source_id_with_special_chars() { 280 let id = SourceId::new("my-source_v1"); 281 assert_eq!(id.as_str(), "my-source_v1"); 282 } 283 284 #[test] 285 fn test_source_timestamp_creation() { 286 let snapshot = SourceSnapshot { 287 source_id: SourceId::new("test"), 288 variables: vec![].into(), 289 timestamp: std::time::Instant::now(), 290 version: None, 291 }; 292 293 let elapsed = snapshot.timestamp.elapsed(); 294 assert!(elapsed.as_millis() < 100); 295 } 296 297 #[test] 298 fn test_variable_source_equality() { 299 let source1 = VariableSource::Shell; 300 let source2 = VariableSource::Shell; 301 assert_eq!(source1, source2); 302 303 let source3 = VariableSource::Memory; 304 assert_ne!(source1, source3); 305 } 306 307 #[test] 308 fn test_parsed_variable_with_commented() { 309 let var = ParsedVariable { 310 key: "KEY".into(), 311 raw_value: "value".into(), 312 source: VariableSource::Memory, 313 description: None, 314 is_commented: true, 315 }; 316 317 assert!(var.is_commented); 318 } 319 320 #[test] 321 fn test_source_version_tracking() { 322 let snapshot1 = SourceSnapshot { 323 source_id: SourceId::new("test"), 324 variables: vec![].into(), 325 timestamp: std::time::Instant::now(), 326 version: Some(1), 327 }; 328 329 let snapshot2 = SourceSnapshot { 330 source_id: SourceId::new("test"), 331 variables: vec![].into(), 332 timestamp: std::time::Instant::now(), 333 version: Some(2), 334 }; 335 336 assert!(snapshot1.version.unwrap() < snapshot2.version.unwrap()); 337 } 338 339 #[test] 340 fn test_source_capabilities_iterators() { 341 let caps = SourceCapabilities::READ | SourceCapabilities::WRITE; 342 343 assert!(caps.contains(SourceCapabilities::READ)); 344 assert!(caps.contains(SourceCapabilities::WRITE)); 345 } 346 347 #[test] 348 fn test_priority_ord() { 349 assert!(Priority::SHELL > Priority::FILE); 350 assert!(Priority::FILE > Priority::MEMORY); 351 assert!(Priority::REMOTE > Priority::FILE); 352 353 let mut vec = vec![Priority::FILE, Priority::SHELL, Priority::MEMORY]; 354 vec.sort(); 355 356 assert_eq!(vec, vec![Priority::MEMORY, Priority::FILE, Priority::SHELL]); 357 } 358 359 #[test] 360 fn test_source_id_partial_eq() { 361 let id = SourceId::new("test-source-123"); 362 assert!(id.as_str().starts_with("test-source")); 363 assert!(id.as_str().ends_with("123")); 364 }