diff --git a/01.workspace/heave/src/str/catalog.rs b/01.workspace/heave/src/str/catalog.rs index 263dec3..d5255bd 100644 --- a/01.workspace/heave/src/str/catalog.rs +++ b/01.workspace/heave/src/str/catalog.rs @@ -882,25 +882,145 @@ mod tests { #[test] fn load_by_id_should_load_entity_from_db() { // Should load a single entity from the database into the 'items' map. - todo!(); + let db_path = "target/test_dbs/load_by_id_should_load_entity_from_db.db"; + let path = std::path::Path::new(db_path); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + if path.exists() { + std::fs::remove_file(path).unwrap(); + } + // 1. Create a catalog, insert an item, and persist it to the DB. + let mut catalog1 = Catalog::new(db_path); + catalog1.init().unwrap(); + let item_to_persist = Item { + id: "item-1".to_string(), + name: "Test Item".to_string(), + price: 123, + in_stock: true, + }; + catalog1.upsert(item_to_persist.clone()); + catalog1.persist().unwrap(); + // 2. Create a new, empty catalog instance for the same DB. + let mut catalog2 = Catalog::new(db_path); + assert!(catalog2.items.is_empty()); + // 3. Load the item by its ID. + let result = catalog2.load_by_id("item-1"); + assert!(result.is_ok()); + // 4. Verify the item is now in the in-memory 'items' map. + assert_eq!(catalog2.items.len(), 1); + let loaded_entity = catalog2.items.get("item-1").unwrap(); + // 5. Verify the loaded entity's data and state. + assert_eq!(loaded_entity.id, "item-1"); + assert_eq!(loaded_entity.class, "item"); + assert_eq!( + loaded_entity.value_of("name"), + Some(&Value::from("Test Item")) + ); + assert_eq!( + loaded_entity.value_of("price"), + Some(&Value::from(123u64)) + ); + assert_eq!( + loaded_entity.value_of("in_stock"), + Some(&Value::from(true)) + ); + assert_eq!(loaded_entity.state, EntityState::Loaded); // Should be Synced after loading. + // 6. Also verify by using the public 'get' method. + let retrieved_item: Option = catalog2.get("item-1"); + assert_eq!(retrieved_item, Some(item_to_persist)); + // Clean up + std::fs::remove_file(path).unwrap(); } #[test] fn load_by_id_should_overwrite_in_memory_entity() { // Should overwrite an existing in-memory entity with the same ID. - todo!(); + let db_path = "target/test_dbs/load_by_id_should_overwrite_in_memory_entity.db"; + let path = std::path::Path::new(db_path); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + if path.exists() { + std::fs::remove_file(path).unwrap(); + } + // 1. Persist an item to the database. + let mut catalog1 = Catalog::new(db_path); + catalog1.init().unwrap(); + let item_in_db = Item { + id: "item-1".to_string(), + name: "Item from DB".to_string(), + price: 100, + in_stock: true, + }; + catalog1.upsert(item_in_db.clone()); + catalog1.persist().unwrap(); + // 2. Create a new catalog and add a *different* in-memory version of the same item. + let mut catalog2 = Catalog::new(db_path); + let item_in_memory = Item { + id: "item-1".to_string(), + name: "In-memory version".to_string(), + price: 200, + in_stock: false, + }; + catalog2.upsert(item_in_memory); + let entity_before_load = catalog2.items.get("item-1").unwrap(); + assert_eq!(entity_before_load.state, EntityState::New); + assert_eq!( + entity_before_load.value_of("name"), + Some(&Value::from("In-memory version")) + ); + // 3. Load the item from the database, which should overwrite the in-memory version. + let result = catalog2.load_by_id("item-1"); + assert!(result.is_ok()); + // 4. Verify that the in-memory entity has been replaced with the one from the DB. + let entity_after_load = catalog2.items.get("item-1").unwrap(); + assert_eq!(entity_after_load.state, EntityState::Loaded); + assert_eq!( + entity_after_load.value_of("name"), + Some(&Value::from("Item from DB")) + ); + assert_eq!( + entity_after_load.value_of("price"), + Some(&Value::from(100u64)) + ); + // 5. Verify using the public 'get' method. + let retrieved_item: Item = catalog2.get("item-1").unwrap(); + assert_eq!(retrieved_item, item_in_db); + // Clean up + std::fs::remove_file(path).unwrap(); } #[test] fn load_by_id_should_do_nothing_if_not_found() { // Should do nothing if the entity is not found in the database. - todo!(); + let db_path = "target/test_dbs/load_by_id_should_do_nothing_if_not_found.db"; + let path = std::path::Path::new(db_path); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + if path.exists() { + std::fs::remove_file(path).unwrap(); + } + // 1. Create an empty, initialized database. + let mut catalog = Catalog::new(db_path); + catalog.init().unwrap(); + // 2. Attempt to load an ID that does not exist. + let result = catalog.load_by_id("nonexistent-id"); + // 3. Verify that the operation succeeded and the catalog remains empty. + assert!(result.is_ok()); + assert!(catalog.items.is_empty()); + // Clean up + std::fs::remove_file(path).unwrap(); } #[test] fn load_by_id_should_return_error_on_db_failure() { // Should return an error if the database operation fails. - todo!(); + // Using a directory as a path should cause a failure. + let invalid_path = "target/test_dbs/a_directory_for_load_fail"; + std::fs::create_dir_all(invalid_path).unwrap(); + let mut catalog = Catalog::new(invalid_path); + // Attempt to load from the invalid path. + let result = catalog.load_by_id("any-id"); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), FailedTo::LoadFromDB); + // Clean up + std::fs::remove_dir_all(invalid_path).unwrap(); } // ## 'load_by_class()'