use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex, OnceLock}; use cc_switch_lib::{update_settings, AppSettings, AppState, Database, MultiAppConfig}; /// 为测试设置隔离的 HOME 目录,避免污染真实用户数据。 pub fn ensure_test_home() -> &'static Path { static HOME: OnceLock = OnceLock::new(); HOME.get_or_init(|| { let base = std::env::temp_dir().join("cc-switch-test-home"); if base.exists() { let _ = std::fs::remove_dir_all(&base); } std::fs::create_dir_all(&base).expect("create test home"); // Windows 上 `dirs::home_dir()` 不受 HOME/USERPROFILE 影响(走 Known Folder API), // 用 CC_SWITCH_TEST_HOME 显式覆盖,以确保测试不会污染真实用户目录。 std::env::set_var("CC_SWITCH_TEST_HOME", &base); std::env::set_var("HOME", &base); #[cfg(windows)] std::env::set_var("USERPROFILE", &base); base }) .as_path() } /// 清理测试目录中生成的配置文件与缓存。 pub fn reset_test_fs() { let home = ensure_test_home(); for sub in [ ".claude", ".codex", ".cc-switch", ".gemini", ".config", ".openclaw", "profiles", ] { let path = home.join(sub); if path.exists() { if let Err(err) = std::fs::remove_dir_all(&path) { eprintln!("failed to clean {}: {}", path.display(), err); } } } let claude_json = home.join(".claude.json"); if claude_json.exists() { let _ = std::fs::remove_file(&claude_json); } // 重置内存中的设置缓存,确保测试环境不受上一次调用影响 let _ = update_settings(AppSettings::default()); } #[allow(dead_code)] pub fn enable_codex_official_auth_preservation() { update_settings(AppSettings { preserve_codex_official_auth_on_switch: true, ..Default::default() }) .expect("enable Codex official auth preservation"); } /// 全局互斥锁,避免多测试并发写入相同的 HOME 目录。 pub fn test_mutex() -> &'static Mutex<()> { static MUTEX: OnceLock> = OnceLock::new(); MUTEX.get_or_init(|| Mutex::new(())) } /// 创建测试用的 AppState,包含一个空的数据库 #[allow(dead_code)] pub fn create_test_state() -> Result> { let db = Arc::new(Database::init()?); Ok(AppState::new(db)) } /// 创建测试用的 AppState,并从 MultiAppConfig 迁移数据 #[allow(dead_code)] pub fn create_test_state_with_config( config: &MultiAppConfig, ) -> Result> { let db = Arc::new(Database::init()?); db.migrate_from_json(config)?; Ok(AppState::new(db)) }