mod api; mod local; mod manager; mod schroot; mod ssh; mod unshare; pub use api::{Context, ContextCommand, ContextConfig}; pub use manager::ContextManager; use std::sync::Arc; pub fn manager() -> &'static ContextManager { &manager::MANAGER } pub fn current() -> Arc { manager::MANAGER.current() } #[cfg(test)] mod tests { use super::*; use std::fs; use tempfile::NamedTempFile; #[test] fn test_ensure_available_local() { let temp_dir = tempfile::tempdir().unwrap(); let src_file = temp_dir.path().join("src.txt"); fs::write(&src_file, "local").unwrap(); let ctx = Context::new(ContextConfig::Local); let dest = ctx.ensure_available(&src_file, "/tmp").unwrap(); // Should return a path that exists and has the same content assert!(dest.exists()); let content = fs::read_to_string(&dest).unwrap(); assert_eq!(content, "local"); // The dest should be in the /tmp directory assert!(dest.starts_with("/tmp")); } #[test] fn test_context_manager_crud() { let temp_file = NamedTempFile::new().unwrap(); let path = temp_file.path().to_path_buf(); let mgr = ContextManager::with_path(path.clone()); // Add let ssh_cfg = ContextConfig::Ssh { host: "10.0.0.1".into(), user: Some("admin".into()), port: Some(2222), }; mgr.add_context("myserver", ssh_cfg.clone()).unwrap(); assert!(mgr.list_contexts().contains(&"myserver".to_string())); // List let list = mgr.list_contexts(); assert!(list.contains(&"myserver".to_string())); // Set Current mgr.set_current("myserver").unwrap(); assert_eq!(mgr.current_name(), "myserver".to_string()); // Remove mgr.remove_context("myserver").unwrap(); assert!(!mgr.list_contexts().contains(&"myserver".to_string())); } #[test] fn test_persistence() { let temp_dir = tempfile::tempdir().unwrap(); let config_path = temp_dir.path().join("contexts.json"); { let mgr = ContextManager::with_path(config_path.clone()); mgr.add_context("persistent", ContextConfig::Local).unwrap(); mgr.set_current("persistent").unwrap(); } let content = fs::read_to_string(&config_path).unwrap(); let loaded_config: super::manager::Config = serde_json::from_str(&content).unwrap(); assert_eq!(loaded_config.context, "persistent".to_string()); assert!(loaded_config.contexts.contains_key("persistent")); } #[test] fn test_context_fallback_on_removal() { let temp_file = NamedTempFile::new().unwrap(); let path = temp_file.path().to_path_buf(); let mgr = ContextManager::with_path(path); // 1. Add and set a context mgr.add_context("temp", ContextConfig::Local).unwrap(); mgr.set_current("temp").unwrap(); assert_eq!(mgr.current_name(), "temp"); // 2. Remove it mgr.remove_context("temp").unwrap(); // 3. Should have fallen back to local assert_eq!(mgr.current_name(), "local"); assert!(mgr.list_contexts().contains(&"local".to_string())); } #[test] fn test_context_file_ops() { let temp_dir = tempfile::tempdir().unwrap(); let ctx = Context::new(ContextConfig::Local); let file_path = temp_dir.path().join("test.txt"); let content = "hello world"; // 1. Write file ctx.write_file(&file_path, content).unwrap(); // 2. Read file let read_content = ctx.read_file(&file_path).unwrap(); assert_eq!(read_content, content); // 3. Copy path let dest_path = temp_dir.path().join("test_copy.txt"); ctx.copy_path(&file_path, &dest_path).unwrap(); let copied_content = ctx.read_file(&dest_path).unwrap(); assert_eq!(copied_content, content); // 4. Recursive copy let subdir = temp_dir.path().join("subdir"); std::fs::create_dir_all(&subdir).unwrap(); let subfile = subdir.join("subfile.txt"); ctx.write_file(&subfile, "subcontent").unwrap(); let subdir_copy = temp_dir.path().join("subdir_copy"); ctx.copy_path(&subdir, &subdir_copy).unwrap(); assert!(subdir_copy.exists()); assert!(subdir_copy.join("subfile.txt").exists()); assert_eq!( ctx.read_file(&subdir_copy.join("subfile.txt")).unwrap(), "subcontent" ); } }