diff --git a/src-tauri/src/api_client.rs b/src-tauri/src/api_client.rs index 70eb5d7..72ab57d 100644 --- a/src-tauri/src/api_client.rs +++ b/src-tauri/src/api_client.rs @@ -1,4 +1,3 @@ -use directories::BaseDirs; use reqwest::Client; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -464,13 +463,7 @@ impl ApiClient { } fn get_cache_dir() -> Result> { - let base_dirs = BaseDirs::new().ok_or("Failed to get base directories")?; - let app_name = if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }; - let cache_dir = base_dirs.cache_dir().join(app_name).join("version_cache"); + let cache_dir = crate::app_dirs::cache_dir().join("version_cache"); fs::create_dir_all(&cache_dir)?; Ok(cache_dir) } diff --git a/src-tauri/src/app_dirs.rs b/src-tauri/src/app_dirs.rs new file mode 100644 index 0000000..9728bb8 --- /dev/null +++ b/src-tauri/src/app_dirs.rs @@ -0,0 +1,185 @@ +use directories::BaseDirs; +use std::path::PathBuf; +use std::sync::OnceLock; + +static BASE_DIRS: OnceLock = OnceLock::new(); + +fn base_dirs() -> &'static BaseDirs { + BASE_DIRS.get_or_init(|| BaseDirs::new().expect("Failed to get base directories")) +} + +pub fn app_name() -> &'static str { + if cfg!(debug_assertions) { + "DonutBrowserDev" + } else { + "DonutBrowser" + } +} + +pub fn data_dir() -> PathBuf { + #[cfg(test)] + { + if let Some(dir) = TEST_DATA_DIR.with(|cell| cell.borrow().clone()) { + return dir; + } + } + + if let Ok(dir) = std::env::var("DONUTBROWSER_DATA_DIR") { + return PathBuf::from(dir); + } + + base_dirs().data_local_dir().join(app_name()) +} + +pub fn cache_dir() -> PathBuf { + #[cfg(test)] + { + if let Some(dir) = TEST_CACHE_DIR.with(|cell| cell.borrow().clone()) { + return dir; + } + } + + if let Ok(dir) = std::env::var("DONUTBROWSER_CACHE_DIR") { + return PathBuf::from(dir); + } + + base_dirs().cache_dir().join(app_name()) +} + +pub fn profiles_dir() -> PathBuf { + data_dir().join("profiles") +} + +pub fn binaries_dir() -> PathBuf { + data_dir().join("binaries") +} + +pub fn data_subdir() -> PathBuf { + data_dir().join("data") +} + +pub fn settings_dir() -> PathBuf { + data_dir().join("settings") +} + +pub fn proxies_dir() -> PathBuf { + data_dir().join("proxies") +} + +#[cfg(test)] +thread_local! { + static TEST_DATA_DIR: std::cell::RefCell> = const { std::cell::RefCell::new(None) }; + static TEST_CACHE_DIR: std::cell::RefCell> = const { std::cell::RefCell::new(None) }; +} + +#[cfg(test)] +pub struct TestDirGuard { + kind: TestDirKind, +} + +#[cfg(test)] +enum TestDirKind { + Data, + Cache, +} + +#[cfg(test)] +impl Drop for TestDirGuard { + fn drop(&mut self) { + match self.kind { + TestDirKind::Data => TEST_DATA_DIR.with(|cell| *cell.borrow_mut() = None), + TestDirKind::Cache => TEST_CACHE_DIR.with(|cell| *cell.borrow_mut() = None), + } + } +} + +#[cfg(test)] +pub fn set_test_data_dir(dir: PathBuf) -> TestDirGuard { + TEST_DATA_DIR.with(|cell| *cell.borrow_mut() = Some(dir)); + TestDirGuard { + kind: TestDirKind::Data, + } +} + +#[cfg(test)] +pub fn set_test_cache_dir(dir: PathBuf) -> TestDirGuard { + TEST_CACHE_DIR.with(|cell| *cell.borrow_mut() = Some(dir)); + TestDirGuard { + kind: TestDirKind::Cache, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_app_name() { + let name = app_name(); + assert!( + name == "DonutBrowser" || name == "DonutBrowserDev", + "app_name should be DonutBrowser or DonutBrowserDev, got: {name}" + ); + } + + #[test] + fn test_data_dir_returns_path() { + let dir = data_dir(); + assert!( + dir.to_string_lossy().contains(app_name()), + "data_dir should contain app_name" + ); + } + + #[test] + fn test_cache_dir_returns_path() { + let dir = cache_dir(); + assert!( + dir.to_string_lossy().contains(app_name()), + "cache_dir should contain app_name" + ); + } + + #[test] + fn test_subdirectory_helpers() { + assert!(profiles_dir().ends_with("profiles")); + assert!(binaries_dir().ends_with("binaries")); + assert!(data_subdir().ends_with("data")); + assert!(settings_dir().ends_with("settings")); + assert!(proxies_dir().ends_with("proxies")); + } + + #[test] + fn test_set_test_data_dir() { + let tmp = PathBuf::from("/tmp/test-donut-data"); + let _guard = set_test_data_dir(tmp.clone()); + assert_eq!(data_dir(), tmp); + assert_eq!(profiles_dir(), tmp.join("profiles")); + assert_eq!(binaries_dir(), tmp.join("binaries")); + } + + #[test] + fn test_set_test_cache_dir() { + let tmp = PathBuf::from("/tmp/test-donut-cache"); + let _guard = set_test_cache_dir(tmp.clone()); + assert_eq!(cache_dir(), tmp); + } + + #[test] + fn test_guard_cleanup() { + let original_data = data_dir(); + let original_cache = cache_dir(); + + { + let _guard = set_test_data_dir(PathBuf::from("/tmp/test-cleanup-data")); + assert_eq!(data_dir(), PathBuf::from("/tmp/test-cleanup-data")); + } + assert_eq!(data_dir(), original_data); + + { + let _guard = set_test_cache_dir(PathBuf::from("/tmp/test-cleanup-cache")); + assert_eq!(cache_dir(), PathBuf::from("/tmp/test-cleanup-cache")); + } + assert_eq!(cache_dir(), original_cache); + } +} diff --git a/src-tauri/src/browser_runner.rs b/src-tauri/src/browser_runner.rs index c26dd4d..0434e52 100644 --- a/src-tauri/src/browser_runner.rs +++ b/src-tauri/src/browser_runner.rs @@ -6,13 +6,11 @@ use crate::platform_browser; use crate::profile::{BrowserProfile, ProfileManager}; use crate::proxy_manager::PROXY_MANAGER; use crate::wayfern_manager::{WayfernConfig, WayfernManager}; -use directories::BaseDirs; use serde::Serialize; use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; use sysinfo::System; pub struct BrowserRunner { - base_dirs: BaseDirs, pub profile_manager: &'static ProfileManager, pub downloaded_browsers_registry: &'static DownloadedBrowsersRegistry, auto_updater: &'static crate::auto_updater::AutoUpdater, @@ -23,7 +21,6 @@ pub struct BrowserRunner { impl BrowserRunner { fn new() -> Self { Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), profile_manager: ProfileManager::instance(), downloaded_browsers_registry: DownloadedBrowsersRegistry::instance(), auto_updater: crate::auto_updater::AutoUpdater::instance(), @@ -37,14 +34,7 @@ impl BrowserRunner { } pub fn get_binaries_dir(&self) -> PathBuf { - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("binaries"); - path + crate::app_dirs::binaries_dir() } /// Get the executable path for a browser profile diff --git a/src-tauri/src/camoufox_manager.rs b/src-tauri/src/camoufox_manager.rs index 1d8609f..ba9d35c 100644 --- a/src-tauri/src/camoufox_manager.rs +++ b/src-tauri/src/camoufox_manager.rs @@ -1,7 +1,6 @@ use crate::browser_runner::BrowserRunner; use crate::camoufox::{CamoufoxConfigBuilder, GeoIPOption, ScreenConstraints}; use crate::profile::BrowserProfile; -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; @@ -74,7 +73,6 @@ struct CamoufoxManagerInner { pub struct CamoufoxManager { inner: Arc>, - base_dirs: BaseDirs, } impl CamoufoxManager { @@ -83,7 +81,6 @@ impl CamoufoxManager { inner: Arc::new(AsyncMutex::new(CamoufoxManagerInner { instances: HashMap::new(), })), - base_dirs: BaseDirs::new().expect("Failed to get base directories"), } } @@ -92,14 +89,7 @@ impl CamoufoxManager { } pub fn get_profiles_dir(&self) -> PathBuf { - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("profiles"); - path + crate::app_dirs::profiles_dir() } /// Generate Camoufox fingerprint configuration during profile creation diff --git a/src-tauri/src/downloaded_browsers_registry.rs b/src-tauri/src/downloaded_browsers_registry.rs index 75d03dd..2290202 100644 --- a/src-tauri/src/downloaded_browsers_registry.rs +++ b/src-tauri/src/downloaded_browsers_registry.rs @@ -1,4 +1,3 @@ -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; @@ -71,16 +70,7 @@ impl DownloadedBrowsersRegistry { } fn get_registry_path() -> Result> { - let base_dirs = BaseDirs::new().ok_or("Failed to get base directories")?; - let mut path = base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("data"); - path.push("downloaded_browsers.json"); - Ok(path) + Ok(crate::app_dirs::data_subdir().join("downloaded_browsers.json")) } pub fn add_browser(&self, info: DownloadedBrowserInfo) { @@ -128,19 +118,7 @@ impl DownloadedBrowsersRegistry { }; let browser_instance = create_browser(browser_type.clone()); - // Get binaries directory - let binaries_dir = if let Some(base_dirs) = directories::BaseDirs::new() { - let mut path = base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("binaries"); - path - } else { - return false; - }; + let binaries_dir = crate::app_dirs::binaries_dir(); let files_exist = browser_instance.is_version_downloaded(version, &binaries_dir); @@ -535,15 +513,7 @@ impl DownloadedBrowsersRegistry { browser: &str, version: &str, ) -> Result<(), Box> { - // Get binaries directory path - let base_dirs = directories::BaseDirs::new().ok_or("Failed to get base directories")?; - let mut binaries_dir = base_dirs.data_local_dir().to_path_buf(); - binaries_dir.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - binaries_dir.push("binaries"); + let binaries_dir = crate::app_dirs::binaries_dir(); let version_dir = binaries_dir.join(browser).join(version); @@ -830,19 +800,7 @@ impl DownloadedBrowsersRegistry { let browser = create_browser(browser_type.clone()); - // Get binaries directory - let binaries_dir = if let Some(base_dirs) = directories::BaseDirs::new() { - let mut path = base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("binaries"); - path - } else { - return Err("Failed to get base directories".into()); - }; + let binaries_dir = crate::app_dirs::binaries_dir(); log::info!( "binaries_dir: {binaries_dir:?} for profile: {}", diff --git a/src-tauri/src/downloader.rs b/src-tauri/src/downloader.rs index a89edb5..d9db2f9 100644 --- a/src-tauri/src/downloader.rs +++ b/src-tauri/src/downloader.rs @@ -681,21 +681,7 @@ impl Downloader { // Use injected registry instance - // Get binaries directory - we need to get it from somewhere - // This is a bit tricky since we don't have access to BrowserRunner's get_binaries_dir - // We'll need to replicate this logic - let binaries_dir = if let Some(base_dirs) = directories::BaseDirs::new() { - let mut path = base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("binaries"); - path - } else { - return Err("Failed to get base directories".into()); - }; + let binaries_dir = crate::app_dirs::binaries_dir(); // Check if registry thinks it's downloaded, but also verify files actually exist if self.registry.is_browser_downloaded(&browser_str, &version) { diff --git a/src-tauri/src/group_manager.rs b/src-tauri/src/group_manager.rs index 8fef804..625bcc6 100644 --- a/src-tauri/src/group_manager.rs +++ b/src-tauri/src/group_manager.rs @@ -1,8 +1,6 @@ -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; -use std::path::{Path, PathBuf}; use std::sync::Mutex; use crate::events; @@ -33,48 +31,15 @@ struct GroupsData { groups: Vec, } -pub struct GroupManager { - base_dirs: BaseDirs, - data_dir_override: Option, -} +pub struct GroupManager; impl GroupManager { pub fn new() -> Self { - Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), - data_dir_override: std::env::var("DONUTBROWSER_DATA_DIR") - .ok() - .map(PathBuf::from), - } + Self } - // Helper for tests to override data directory without global env var - #[allow(dead_code)] - pub fn with_data_dir_override(dir: &Path) -> Self { - Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), - data_dir_override: Some(dir.to_path_buf()), - } - } - - fn get_groups_file_path(&self) -> PathBuf { - if let Some(dir) = &self.data_dir_override { - let mut override_path = dir.clone(); - // Ensure the directory exists before returning the path - let _ = fs::create_dir_all(&override_path); - override_path.push("groups.json"); - return override_path; - } - - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("data"); - path.push("groups.json"); - path + fn get_groups_file_path(&self) -> std::path::PathBuf { + crate::app_dirs::data_subdir().join("groups.json") } fn load_groups_data(&self) -> Result> { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 3bf5b2c..8a682c1 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -11,6 +11,7 @@ static PENDING_URLS: Mutex> = Mutex::new(Vec::new()); mod api_client; mod api_server; mod app_auto_updater; +pub mod app_dirs; mod auto_updater; mod browser; mod browser_runner; @@ -706,12 +707,7 @@ pub fn run() { pending.push(url.clone()); } - // Configure logging plugin with separate logs for dev and production - let log_file_name = if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }; + let log_file_name = app_dirs::app_name(); tauri::Builder::default() .plugin( diff --git a/src-tauri/src/profile/manager.rs b/src-tauri/src/profile/manager.rs index 04e5189..3245b2d 100644 --- a/src-tauri/src/profile/manager.rs +++ b/src-tauri/src/profile/manager.rs @@ -6,13 +6,11 @@ use crate::events; use crate::profile::types::{get_host_os, BrowserProfile}; use crate::proxy_manager::PROXY_MANAGER; use crate::wayfern_manager::WayfernConfig; -use directories::BaseDirs; use std::fs::{self, create_dir_all}; use std::path::{Path, PathBuf}; use sysinfo::{Pid, System}; pub struct ProfileManager { - base_dirs: BaseDirs, camoufox_manager: &'static crate::camoufox_manager::CamoufoxManager, wayfern_manager: &'static crate::wayfern_manager::WayfernManager, } @@ -20,7 +18,6 @@ pub struct ProfileManager { impl ProfileManager { fn new() -> Self { Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), camoufox_manager: crate::camoufox_manager::CamoufoxManager::instance(), wayfern_manager: crate::wayfern_manager::WayfernManager::instance(), } @@ -31,25 +28,11 @@ impl ProfileManager { } pub fn get_profiles_dir(&self) -> PathBuf { - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("profiles"); - path + crate::app_dirs::profiles_dir() } pub fn get_binaries_dir(&self) -> PathBuf { - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("binaries"); - path + crate::app_dirs::binaries_dir() } #[allow(clippy::too_many_arguments)] diff --git a/src-tauri/src/proxy_manager.rs b/src-tauri/src/proxy_manager.rs index 87f5b99..98fbf76 100644 --- a/src-tauri/src/proxy_manager.rs +++ b/src-tauri/src/proxy_manager.rs @@ -1,5 +1,4 @@ use chrono::Utc; -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; @@ -149,18 +148,15 @@ pub struct ProxyManager { // Track active proxy IDs by profile name for targeted cleanup profile_active_proxy_ids: Mutex>, // Maps profile name to proxy id stored_proxies: Mutex>, // Maps proxy ID to stored proxy - base_dirs: BaseDirs, } impl ProxyManager { pub fn new() -> Self { - let base_dirs = BaseDirs::new().expect("Failed to get base directories"); let manager = Self { active_proxies: Mutex::new(HashMap::new()), profile_proxies: Mutex::new(HashMap::new()), profile_active_proxy_ids: Mutex::new(HashMap::new()), stored_proxies: Mutex::new(HashMap::new()), - base_dirs, }; // Load stored proxies on initialization @@ -171,27 +167,12 @@ impl ProxyManager { manager } - // Get the path to the proxies directory fn get_proxies_dir(&self) -> PathBuf { - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("proxies"); - path + crate::app_dirs::proxies_dir() } - // Get the path to the proxy check cache directory fn get_proxy_check_cache_dir(&self) -> Result> { - let mut path = self.base_dirs.cache_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("proxy_checks"); + let path = crate::app_dirs::cache_dir().join("proxy_checks"); fs::create_dir_all(&path)?; Ok(path) } diff --git a/src-tauri/src/proxy_storage.rs b/src-tauri/src/proxy_storage.rs index f8cda0d..4cfb132 100644 --- a/src-tauri/src/proxy_storage.rs +++ b/src-tauri/src/proxy_storage.rs @@ -1,4 +1,3 @@ -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; @@ -35,15 +34,7 @@ impl ProxyConfig { } pub fn get_storage_dir() -> PathBuf { - let base_dirs = BaseDirs::new().expect("Failed to get base directories"); - let mut path = base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("proxies"); - path + crate::app_dirs::proxies_dir() } pub fn save_proxy_config(config: &ProxyConfig) -> Result<(), Box> { diff --git a/src-tauri/src/settings_manager.rs b/src-tauri/src/settings_manager.rs index d7eb2e7..e850df5 100644 --- a/src-tauri/src/settings_manager.rs +++ b/src-tauri/src/settings_manager.rs @@ -1,4 +1,3 @@ -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::fs::{self, create_dir_all}; use std::path::PathBuf; @@ -91,27 +90,11 @@ impl Default for AppSettings { } } -pub struct SettingsManager { - base_dirs: BaseDirs, - data_dir_override: Option, -} +pub struct SettingsManager; impl SettingsManager { - fn new() -> Self { - Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), - data_dir_override: std::env::var("DONUTBROWSER_DATA_DIR") - .ok() - .map(PathBuf::from), - } - } - - #[cfg(test)] - fn with_data_dir_override(dir: &std::path::Path) -> Self { - Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), - data_dir_override: Some(dir.to_path_buf()), - } + pub(crate) fn new() -> Self { + Self } pub fn instance() -> &'static SettingsManager { @@ -119,18 +102,7 @@ impl SettingsManager { } pub fn get_settings_dir(&self) -> PathBuf { - if let Some(dir) = &self.data_dir_override { - return dir.join("settings"); - } - - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("settings"); - path + crate::app_dirs::settings_dir() } pub fn get_settings_file(&self) -> PathBuf { @@ -950,16 +922,16 @@ mod tests { use super::*; use tempfile::TempDir; - fn create_test_settings_manager() -> (SettingsManager, TempDir) { + fn create_test_settings_manager() -> (SettingsManager, TempDir, crate::app_dirs::TestDirGuard) { let temp_dir = TempDir::new().expect("Failed to create temp directory"); - let manager = SettingsManager::with_data_dir_override(temp_dir.path()); - (manager, temp_dir) + let guard = crate::app_dirs::set_test_data_dir(temp_dir.path().to_path_buf()); + let manager = SettingsManager::new(); + (manager, temp_dir, guard) } #[test] fn test_settings_manager_creation() { - let (_manager, _temp_dir) = create_test_settings_manager(); - // Test passes if no panic occurs + let (_manager, _temp_dir, _guard) = create_test_settings_manager(); } #[test] @@ -992,7 +964,7 @@ mod tests { #[test] fn test_load_settings_nonexistent_file() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); let result = manager.load_settings(); assert!( @@ -1010,7 +982,7 @@ mod tests { #[test] fn test_save_and_load_settings() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); let test_settings = AppSettings { set_as_default_browser: true, @@ -1029,11 +1001,9 @@ mod tests { language: None, }; - // Save settings let save_result = manager.save_settings(&test_settings); assert!(save_result.is_ok(), "Should save settings successfully"); - // Load settings back let load_result = manager.load_settings(); assert!(load_result.is_ok(), "Should load settings successfully"); @@ -1050,7 +1020,7 @@ mod tests { #[test] fn test_load_table_sorting_nonexistent_file() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); let result = manager.load_table_sorting(); assert!( @@ -1065,18 +1035,16 @@ mod tests { #[test] fn test_save_and_load_table_sorting() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); let test_sorting = TableSortingSettings { column: "browser".to_string(), direction: "desc".to_string(), }; - // Save sorting let save_result = manager.save_table_sorting(&test_sorting); assert!(save_result.is_ok(), "Should save sorting successfully"); - // Load sorting back let load_result = manager.load_table_sorting(); assert!(load_result.is_ok(), "Should load sorting successfully"); @@ -1093,45 +1061,37 @@ mod tests { #[test] fn test_should_show_launch_on_login_prompt() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); let result = manager.should_show_launch_on_login_prompt(); assert!(result.is_ok(), "Should not fail"); - // By default, should show prompt (not declined, autostart not enabled) let _should_show = result.unwrap(); - // Note: The actual value depends on system autostart state, so we just test it doesn't fail } #[test] fn test_decline_launch_on_login() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); - // Initially not declined let settings = manager.load_settings().unwrap(); assert!(!settings.launch_on_login_declined); - // Decline manager.decline_launch_on_login().unwrap(); - // Should be declined now let settings = manager.load_settings().unwrap(); assert!(settings.launch_on_login_declined); } #[test] fn test_load_corrupted_settings_file() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); - // Create settings directory let settings_dir = manager.get_settings_dir(); fs::create_dir_all(&settings_dir).expect("Should create settings directory"); - // Write corrupted JSON let settings_file = manager.get_settings_file(); fs::write(&settings_file, "{ invalid json }").expect("Should write corrupted file"); - // Should handle corrupted file gracefully let result = manager.load_settings(); assert!( result.is_ok(), @@ -1151,7 +1111,7 @@ mod tests { #[test] fn test_settings_file_paths() { - let (manager, _temp_dir) = create_test_settings_manager(); + let (manager, _temp_dir, _guard) = create_test_settings_manager(); let settings_dir = manager.get_settings_dir(); let settings_file = manager.get_settings_file(); diff --git a/src-tauri/src/tag_manager.rs b/src-tauri/src/tag_manager.rs index 7577d6e..5b53207 100644 --- a/src-tauri/src/tag_manager.rs +++ b/src-tauri/src/tag_manager.rs @@ -1,56 +1,22 @@ use crate::profile::BrowserProfile; -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; use std::fs; -use std::path::{Path, PathBuf}; #[derive(Debug, Serialize, Deserialize, Default, Clone)] struct TagsData { tags: Vec, } -pub struct TagManager { - base_dirs: BaseDirs, - data_dir_override: Option, -} +pub struct TagManager; impl TagManager { pub fn new() -> Self { - Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), - data_dir_override: std::env::var("DONUTBROWSER_DATA_DIR") - .ok() - .map(PathBuf::from), - } + Self } - // Helper for tests to override data directory without global env var - #[allow(dead_code)] - pub fn with_data_dir_override(dir: &Path) -> Self { - Self { - base_dirs: BaseDirs::new().expect("Failed to get base directories"), - data_dir_override: Some(dir.to_path_buf()), - } - } - - fn get_tags_file_path(&self) -> PathBuf { - if let Some(dir) = &self.data_dir_override { - let mut override_path = dir.clone(); - let _ = fs::create_dir_all(&override_path); - override_path.push("tags.json"); - return override_path; - } - - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("data"); - path.push("tags.json"); - path + fn get_tags_file_path(&self) -> std::path::PathBuf { + crate::app_dirs::data_subdir().join("tags.json") } fn load_tags_data(&self) -> Result> { diff --git a/src-tauri/src/traffic_stats.rs b/src-tauri/src/traffic_stats.rs index 3d4416a..e7c52a1 100644 --- a/src-tauri/src/traffic_stats.rs +++ b/src-tauri/src/traffic_stats.rs @@ -1,4 +1,3 @@ -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; @@ -328,17 +327,8 @@ fn acquire_file_lock(lock_path: &PathBuf) -> Result PathBuf { - let base_dirs = BaseDirs::new().expect("Failed to get base directories"); - let mut path = base_dirs.cache_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("traffic_stats"); - path + crate::app_dirs::cache_dir().join("traffic_stats") } /// Get the storage key for traffic stats (profile_id if available, otherwise proxy_id) diff --git a/src-tauri/src/version_updater.rs b/src-tauri/src/version_updater.rs index ff943f7..d672ed1 100644 --- a/src-tauri/src/version_updater.rs +++ b/src-tauri/src/version_updater.rs @@ -1,4 +1,3 @@ -use directories::BaseDirs; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; @@ -67,13 +66,7 @@ impl VersionUpdater { } fn get_cache_dir() -> Result> { - let base_dirs = BaseDirs::new().ok_or("Failed to get base directories")?; - let app_name = if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }; - let cache_dir = base_dirs.cache_dir().join(app_name).join("version_cache"); + let cache_dir = crate::app_dirs::cache_dir().join("version_cache"); fs::create_dir_all(&cache_dir)?; Ok(cache_dir) } diff --git a/src-tauri/src/wayfern_manager.rs b/src-tauri/src/wayfern_manager.rs index 69f4aa6..81a7f16 100644 --- a/src-tauri/src/wayfern_manager.rs +++ b/src-tauri/src/wayfern_manager.rs @@ -1,6 +1,5 @@ use crate::browser_runner::BrowserRunner; use crate::profile::BrowserProfile; -use directories::BaseDirs; use reqwest::Client; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -72,8 +71,6 @@ struct WayfernManagerInner { pub struct WayfernManager { inner: Arc>, - #[allow(dead_code)] - base_dirs: BaseDirs, http_client: Client, } @@ -91,7 +88,6 @@ impl WayfernManager { inner: Arc::new(AsyncMutex::new(WayfernManagerInner { instances: HashMap::new(), })), - base_dirs: BaseDirs::new().expect("Failed to get base directories"), http_client: Client::new(), } } @@ -102,26 +98,12 @@ impl WayfernManager { #[allow(dead_code)] pub fn get_profiles_dir(&self) -> PathBuf { - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("profiles"); - path + crate::app_dirs::profiles_dir() } #[allow(dead_code)] fn get_binaries_dir(&self) -> PathBuf { - let mut path = self.base_dirs.data_local_dir().to_path_buf(); - path.push(if cfg!(debug_assertions) { - "DonutBrowserDev" - } else { - "DonutBrowser" - }); - path.push("binaries"); - path + crate::app_dirs::binaries_dir() } async fn find_free_port() -> Result> { diff --git a/src-tauri/tests/donut_proxy_integration.rs b/src-tauri/tests/donut_proxy_integration.rs index 4469127..cfb9403 100644 --- a/src-tauri/tests/donut_proxy_integration.rs +++ b/src-tauri/tests/donut_proxy_integration.rs @@ -516,13 +516,7 @@ async fn test_traffic_tracking() -> Result<(), Box