diff options
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/vcs/src/data/sheet.rs | 22 | ||||
| -rw-r--r-- | crates/vcs/src/data/vault/sheets.rs | 16 | ||||
| -rw-r--r-- | crates/vcs/vcs_test/src/lib.rs | 3 | ||||
| -rw-r--r-- | crates/vcs/vcs_test/src/test_sheet_creation_management_and_persistence.rs | 260 |
4 files changed, 286 insertions, 15 deletions
diff --git a/crates/vcs/src/data/sheet.rs b/crates/vcs/src/data/sheet.rs index 3acc8ff..edf307a 100644 --- a/crates/vcs/src/data/sheet.rs +++ b/crates/vcs/src/data/sheet.rs @@ -14,8 +14,15 @@ use crate::{ pub type SheetName = String; pub type SheetPathBuf = PathBuf; pub type InputName = String; -pub type InputPackage = (InputName, Vec<(InputRaltivePathBuf, VirtualFileId)>); -pub type InputRaltivePathBuf = PathBuf; +pub type InputRelativePathBuf = PathBuf; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct InputPackage { + /// Name of the input package + pub name: InputName, + /// Files in this input package with their relative paths and virtual file IDs + pub files: Vec<(InputRelativePathBuf, VirtualFileId)>, +} const SHEET_NAME: &str = "{sheet-name}"; @@ -62,9 +69,12 @@ impl<'a> Sheet<'a> { pub fn add_input( &mut self, input_name: InputName, - files: Vec<(InputRaltivePathBuf, VirtualFileId)>, + files: Vec<(InputRelativePathBuf, VirtualFileId)>, ) { - self.data.inputs.push((input_name, files)); + self.data.inputs.push(InputPackage { + name: input_name, + files, + }); } /// Remove an input package from the sheet @@ -72,7 +82,7 @@ impl<'a> Sheet<'a> { self.data .inputs .iter() - .position(|(name, _)| name == input_name) + .position(|input| input.name == *input_name) .map(|pos| self.data.inputs.remove(pos)) } @@ -92,7 +102,7 @@ impl<'a> Sheet<'a> { /// Because I don't want a second instance of the sheet to be kept in memory. /// If needed, please deserialize and reload it. pub async fn persist(self) -> Result<(), std::io::Error> { - SheetData::write_to(&self.data, &self.sheet_path()).await + SheetData::write_to(&self.data, self.sheet_path()).await } /// Get the path to the sheet file diff --git a/crates/vcs/src/data/vault/sheets.rs b/crates/vcs/src/data/vault/sheets.rs index ede4077..dfad862 100644 --- a/crates/vcs/src/data/vault/sheets.rs +++ b/crates/vcs/src/data/vault/sheets.rs @@ -53,12 +53,11 @@ impl Vault { let path = entry.path(); // Check if it's a YAML file - if path.is_file() && path.extension().map_or(false, |ext| ext == "yaml") { - if let Some(_file_stem) = path.file_stem().and_then(|s| s.to_str()) { + if path.is_file() && path.extension().is_some_and(|ext| ext == "yaml") + && let Some(file_stem) = path.file_stem().and_then(|s| s.to_str()) { // Create a new SheetName and add it to the result list - sheet_names.push(SheetName::new()); + sheet_names.push(file_stem.to_string()); } - } } Ok(sheet_names) @@ -128,7 +127,7 @@ impl Vault { // Create the sheet file let sheet_data = SheetData { - holder: sheet_name.clone(), + holder: holder.clone(), inputs: Vec::new(), mapping: HashMap::new(), }; @@ -220,7 +219,7 @@ impl Vault { if !trash_dir.exists() { return Err(Error::new( std::io::ErrorKind::NotFound, - format!("Trash directory does not exist!"), + "Trash directory does not exist!".to_string(), )); } @@ -229,15 +228,14 @@ impl Vault { let entry = entry?; let path = entry.path(); - if path.is_file() { - if let Some(file_name) = path.file_stem().and_then(|s| s.to_str()) { + if path.is_file() + && let Some(file_name) = path.file_stem().and_then(|s| s.to_str()) { // Check if the filename starts with the sheet name if file_name.starts_with(&sheet_name) { found_path = Some(path); break; } } - } } let trash_path = found_path.ok_or_else(|| { diff --git a/crates/vcs/vcs_test/src/lib.rs b/crates/vcs/vcs_test/src/lib.rs index d9e6f94..8ad03e1 100644 --- a/crates/vcs/vcs_test/src/lib.rs +++ b/crates/vcs/vcs_test/src/lib.rs @@ -11,6 +11,9 @@ pub mod test_virtual_file_creation_and_update; #[cfg(test)] pub mod test_local_workspace_setup_and_account_management; +#[cfg(test)] +pub mod test_sheet_creation_management_and_persistence; + pub async fn get_test_dir(area: &str) -> Result<PathBuf, std::io::Error> { let dir = current_dir()?.join(".temp").join("test").join(area); if !dir.exists() { diff --git a/crates/vcs/vcs_test/src/test_sheet_creation_management_and_persistence.rs b/crates/vcs/vcs_test/src/test_sheet_creation_management_and_persistence.rs new file mode 100644 index 0000000..7fe6955 --- /dev/null +++ b/crates/vcs/vcs_test/src/test_sheet_creation_management_and_persistence.rs @@ -0,0 +1,260 @@ +use std::io::Error; + +use cfg_file::config::ConfigFile; +use vcs::{ + constants::{SERVER_FILE_SHEET, SERVER_FILE_VAULT}, + data::{ + member::{Member, MemberId}, + sheet::{InputRelativePathBuf, SheetName}, + vault::{Vault, config::VaultConfig, virtual_file::VirtualFileId}, + }, +}; + +use crate::get_test_dir; + +#[tokio::test] +async fn test_sheet_creation_management_and_persistence() -> Result<(), std::io::Error> { + let dir = get_test_dir("sheet_management").await?; + + // Setup vault + Vault::setup_vault(dir.clone()).await?; + + // Get vault + let config = VaultConfig::read_from(dir.join(SERVER_FILE_VAULT)).await?; + let Some(vault) = Vault::init(config, &dir) else { + return Err(Error::new(std::io::ErrorKind::NotFound, "Vault not found!")); + }; + + // Add a member to use as sheet holder + let member_id: MemberId = "test_member".to_string(); + vault + .register_member_to_vault(Member::new(&member_id)) + .await?; + + // Test 1: Create a new sheet + let sheet_name: SheetName = "test_sheet".to_string(); + let sheet = vault.create_sheet(&sheet_name, &member_id).await?; + + // Verify sheet properties + assert_eq!(sheet.holder(), &member_id); + assert_eq!(sheet.holder(), &member_id); + assert!(sheet.inputs().is_empty()); + assert!(sheet.mapping().is_empty()); + + // Verify sheet file was created + const SHEET_NAME_PARAM: &str = "{sheet-name}"; + let sheet_path = dir.join(SERVER_FILE_SHEET.replace(SHEET_NAME_PARAM, &sheet_name)); + assert!(sheet_path.exists()); + + // Test 2: Add input packages to the sheet + let input_name = "source_files".to_string(); + let files = vec![ + ( + InputRelativePathBuf::from("src/main.rs"), + VirtualFileId::new(), + ), + ( + InputRelativePathBuf::from("src/lib.rs"), + VirtualFileId::new(), + ), + ]; + + // Need to get a mutable reference to the sheet + let mut sheet = vault.sheet(&sheet_name).await?; + sheet.add_input(input_name.clone(), files.clone()); + + // Verify input was added + assert_eq!(sheet.inputs().len(), 1); + let added_input = &sheet.inputs()[0]; + assert_eq!(added_input.name, input_name); + assert_eq!(added_input.files.len(), 2); + assert_eq!( + added_input.files[0].0, + InputRelativePathBuf::from("src/main.rs") + ); + assert_eq!( + added_input.files[1].0, + InputRelativePathBuf::from("src/lib.rs") + ); + + // Test 3: Add mapping entries + let mapping_path = vcs::data::sheet::SheetPathBuf::from("output/build.exe"); + let virtual_file_id = VirtualFileId::new(); + sheet.add_mapping(mapping_path.clone(), virtual_file_id.clone()); + + // Verify mapping was added + assert_eq!(sheet.mapping().len(), 1); + assert_eq!(sheet.mapping().get(&mapping_path), Some(&virtual_file_id)); + + // Test 4: Persist sheet to disk + sheet.persist().await?; + + // Verify persistence by reloading the sheet + let reloaded_sheet = vault.sheet(&sheet_name).await?; + assert_eq!(reloaded_sheet.holder(), &member_id); + assert_eq!(reloaded_sheet.inputs().len(), 1); + assert_eq!(reloaded_sheet.mapping().len(), 1); + + // Test 5: Remove input package + let mut sheet_for_removal = vault.sheet(&sheet_name).await?; + let removed_input = sheet_for_removal.remove_input(&input_name); + assert!(removed_input.is_some()); + let removed_input = removed_input.unwrap(); + assert_eq!(removed_input.name, input_name); + assert_eq!(removed_input.files.len(), 2); + assert_eq!(sheet_for_removal.inputs().len(), 0); + + // Test 6: Remove mapping entry + let removed_virtual_file_id = sheet_for_removal.remove_mapping(&mapping_path); + assert_eq!(removed_virtual_file_id, Some(virtual_file_id)); + assert_eq!(sheet_for_removal.mapping().len(), 0); + + // Test 7: List all sheets in vault + let sheet_names = vault.sheet_names()?; + assert_eq!(sheet_names.len(), 1); + assert_eq!(sheet_names[0], sheet_name); + + let all_sheets = vault.sheets().await?; + assert_eq!(all_sheets.len(), 1); + assert_eq!(all_sheets[0].holder(), &member_id); + + // Test 8: Safe deletion (move to trash) + vault.delete_sheet_safely(&sheet_name).await?; + + // Verify sheet is not in normal listing but can be restored + let sheet_names_after_deletion = vault.sheet_names()?; + assert_eq!(sheet_names_after_deletion.len(), 0); + + // Test 9: Restore sheet from trash + let restored_sheet = vault.sheet(&sheet_name).await?; + assert_eq!(restored_sheet.holder(), &member_id); + assert_eq!(restored_sheet.holder(), &member_id); + + // Verify sheet is back in normal listing + let sheet_names_after_restore = vault.sheet_names()?; + assert_eq!(sheet_names_after_restore.len(), 1); + + // Test 10: Permanent deletion + vault.delete_sheet(&sheet_name).await?; + + // Verify sheet is permanently gone + let sheet_names_final = vault.sheet_names()?; + assert_eq!(sheet_names_final.len(), 0); + + // Attempt to access deleted sheet should fail + let result = vault.sheet(&sheet_name).await; + assert!(result.is_err()); + + // Clean up: Remove member + vault.remove_member_from_vault(&member_id)?; + + Ok(()) +} + +#[tokio::test] +async fn test_sheet_error_conditions() -> Result<(), std::io::Error> { + let dir = get_test_dir("sheet_error_conditions").await?; + + // Setup vault + Vault::setup_vault(dir.clone()).await?; + + // Get vault + let config = VaultConfig::read_from(dir.join(SERVER_FILE_VAULT)).await?; + let Some(vault) = Vault::init(config, &dir) else { + return Err(Error::new(std::io::ErrorKind::NotFound, "Vault not found!")); + }; + + // Test 1: Create sheet with non-existent member should fail + let non_existent_member: MemberId = "non_existent_member".to_string(); + let sheet_name: SheetName = "test_sheet".to_string(); + + let result = vault.create_sheet(&sheet_name, &non_existent_member).await; + assert!(result.is_err()); + + // Add a member first + let member_id: MemberId = "test_member".to_string(); + vault + .register_member_to_vault(Member::new(&member_id)) + .await?; + + // Test 2: Create duplicate sheet should fail + vault.create_sheet(&sheet_name, &member_id).await?; + let result = vault.create_sheet(&sheet_name, &member_id).await; + assert!(result.is_err()); + + // Test 3: Delete non-existent sheet should fail + let non_existent_sheet: SheetName = "non_existent_sheet".to_string(); + let result = vault.delete_sheet(&non_existent_sheet).await; + assert!(result.is_err()); + + // Test 4: Safe delete non-existent sheet should fail + let result = vault.delete_sheet_safely(&non_existent_sheet).await; + assert!(result.is_err()); + + // Test 5: Restore non-existent sheet from trash should fail + let result = vault.restore_sheet(&non_existent_sheet).await; + assert!(result.is_err()); + + // Clean up + vault.remove_member_from_vault(&member_id)?; + + Ok(()) +} + +#[tokio::test] +async fn test_sheet_data_serialization() -> Result<(), std::io::Error> { + let dir = get_test_dir("sheet_serialization").await?; + + // Test serialization by creating a sheet through the vault + // Setup vault + Vault::setup_vault(dir.clone()).await?; + + // Get vault + let config = VaultConfig::read_from(dir.join(SERVER_FILE_VAULT)).await?; + let Some(vault) = Vault::init(config, &dir) else { + return Err(Error::new(std::io::ErrorKind::NotFound, "Vault not found!")); + }; + + // Add a member + let member_id: MemberId = "test_member".to_string(); + vault + .register_member_to_vault(Member::new(&member_id)) + .await?; + + // Create a sheet + let sheet_name: SheetName = "test_serialization_sheet".to_string(); + let mut sheet = vault.create_sheet(&sheet_name, &member_id).await?; + + // Add some inputs + let input_name = "source_files".to_string(); + let files = vec![ + ( + InputRelativePathBuf::from("src/main.rs"), + VirtualFileId::new(), + ), + ( + InputRelativePathBuf::from("src/lib.rs"), + VirtualFileId::new(), + ), + ]; + sheet.add_input(input_name, files); + + // Add some mappings + sheet.add_mapping( + vcs::data::sheet::SheetPathBuf::from("output/build.exe"), + VirtualFileId::new(), + ); + + // Persist the sheet + sheet.persist().await?; + + // Verify the sheet file was created + const SHEET_NAME_PARAM: &str = "{sheet-name}"; + let sheet_path = dir.join(SERVER_FILE_SHEET.replace(SHEET_NAME_PARAM, &sheet_name)); + assert!(sheet_path.exists()); + + // Clean up + vault.remove_member_from_vault(&member_id)?; + + Ok(()) +} |
