use gitbaby::command::env::Env; use std::sync::{Mutex, MutexGuard, PoisonError}; static ENV_LOCK: Mutex<()> = Mutex::new(()); fn lock_or_recover() -> MutexGuard<'static, ()> { match ENV_LOCK.lock() { Ok(g) => g, Err(PoisonError { .. }) => panic!("env lock poisoned"), } } fn unique_key(suffix: &str) -> String { format!("GITBABY_TEST_ENV_{suffix}") } unsafe fn set_var(key: &str, val: &str) { unsafe { std::env::set_var(key, val) } } unsafe fn remove_var(key: &str) { unsafe { std::env::remove_var(key) } } #[test] fn from_current_env_includes_system_var() { let _guard = lock_or_recover(); let key = unique_key("FROM_CUR"); unsafe { set_var(&key, "from-system") }; let env = Env::from_current_env(); assert_eq!(env.get(&key), Some("from-system")); unsafe { remove_var(&key) }; } #[test] fn from_current_env_contains_path_like_var() { let env = Env::from_current_env(); assert!(env.get("PATH").is_some() || env.get("Path").is_some() || !env.is_empty()); } #[test] fn set_overrides_system_var_after_from_current_env() { let _guard = lock_or_recover(); let key = unique_key("OVERRIDE"); unsafe { set_var(&key, "system-value") }; let mut env = Env::from_current_env(); env.set(&key, "user-value"); assert_eq!(env.get(&key), Some("user-value")); unsafe { remove_var(&key) }; } #[test] fn with_current_env_overrides_user_added_var() { let _guard = lock_or_recover(); let key = unique_key("WC_OVERRIDE"); unsafe { set_var(&key, "system-wins") }; let env = Env::new().with(&key, "user-loses").with_current_env(); assert_eq!(env.get(&key), Some("system-wins")); unsafe { remove_var(&key) }; } #[test] fn overlay_current_env_preserves_user_added_var() { let _guard = lock_or_recover(); let key = unique_key("OVERLAY"); unsafe { set_var(&key, "system-value") }; let env = Env::new().with(&key, "user-keeps").overlay_current_env(); assert_eq!(env.get(&key), Some("user-keeps")); unsafe { remove_var(&key) }; } #[test] fn overlay_current_env_fills_missing_keys() { let _guard = lock_or_recover(); let mut iter = std::env::vars_os(); let known = match iter.next() { Some(v) => v, None => panic!("process should have at least one env var"), }; let known_key = known.0.to_string_lossy().into_owned(); let env = Env::new().overlay_current_env(); assert!(env.get(&known_key).is_some()); } #[test] fn unset_removes_system_var_when_loaded() { let _guard = lock_or_recover(); let key = unique_key("UNSET"); unsafe { set_var(&key, "temp") }; let mut env = Env::from_current_env(); assert_eq!(env.get(&key), Some("temp")); env.unset(&key); assert_eq!(env.get(&key), None); unsafe { remove_var(&key) }; } #[test] fn from_current_env_is_cloneable() { let _guard = lock_or_recover(); let key = unique_key("CLONE"); unsafe { set_var(&key, "v") }; let env = Env::from_current_env(); let copy = env.clone(); assert_eq!(env.get(&key), Some("v")); assert_eq!(copy.get(&key), Some("v")); unsafe { remove_var(&key) }; } #[test] fn set_after_from_current_env_does_not_grow_pairs_when_key_known() { let _guard = lock_or_recover(); let key = unique_key("NOGROW"); unsafe { set_var(&key, "system") }; let mut env = Env::from_current_env(); let before = env.len(); env.set(&key, "user"); let after = env.len(); assert_eq!(before, after, "set 应替换而非新增"); assert_eq!(env.get(&key), Some("user")); unsafe { remove_var(&key) }; }