diff --git a/base/src/test/user_model/test_batch_row_column_diff.rs b/base/src/test/user_model/test_batch_row_column_diff.rs index ae445dc..3819ed9 100644 --- a/base/src/test/user_model/test_batch_row_column_diff.rs +++ b/base/src/test/user_model/test_batch_row_column_diff.rs @@ -64,7 +64,7 @@ fn undo_redo_after_batch_delete() { model.set_user_input(0, 20, 1, "A").unwrap(); model.set_user_input(0, 1, 20, "B").unwrap(); - // Fill the rows we are about to delete so the diff list can be produced + // Fill some of the rows we are about to delete for testing for r in 10..15 { model.set_user_input(0, r, 1, "tmp").unwrap(); } @@ -153,3 +153,75 @@ fn edge_case_single_operation() { let list = last_diff_list(&mut model); assert_eq!(list.len(), 1); } + +#[test] +fn delete_empty_rows() { + let base = new_empty_model(); + let mut model = UserModel::from_model(base); + + // Set data in rows 1 and 10, leaving rows 5-8 empty + model.set_user_input(0, 1, 1, "Before").unwrap(); + model.set_user_input(0, 10, 1, "After").unwrap(); + + // Delete empty rows 5-8 + assert!(model.delete_rows(0, 5, 4).is_ok()); + + // Verify shift + assert_eq!(model.get_formatted_cell_value(0, 1, 1).unwrap(), "Before"); + assert_eq!(model.get_formatted_cell_value(0, 6, 1).unwrap(), "After"); + + // Verify diffs are in reverse order with empty data + let list = last_diff_list(&mut model); + assert_eq!(list.len(), 4); + let mut expected_row = 8; + for diff in &list { + match diff { + Diff::DeleteRow { row, old_data, .. } => { + assert_eq!(*row, expected_row); + assert!(old_data.data.is_empty()); + expected_row -= 1; + } + _ => panic!("Unexpected diff variant"), + } + } + + // Undo/redo + model.undo().unwrap(); + assert_eq!(model.get_formatted_cell_value(0, 10, 1).unwrap(), "After"); + model.redo().unwrap(); + assert_eq!(model.get_formatted_cell_value(0, 6, 1).unwrap(), "After"); +} + +#[test] +fn delete_mixed_empty_and_filled_rows() { + let base = new_empty_model(); + let mut model = UserModel::from_model(base); + + // Alternating filled and empty rows + model.set_user_input(0, 5, 1, "Row5").unwrap(); + model.set_user_input(0, 7, 1, "Row7").unwrap(); + model.set_user_input(0, 9, 1, "Row9").unwrap(); + model.set_user_input(0, 10, 1, "After").unwrap(); + + assert!(model.delete_rows(0, 5, 5).is_ok()); + assert_eq!(model.get_formatted_cell_value(0, 5, 1).unwrap(), "After"); + + // Verify mix of empty and filled row diffs + let list = last_diff_list(&mut model); + assert_eq!(list.len(), 5); + let filled_count = list + .iter() + .filter(|diff| match diff { + Diff::DeleteRow { old_data, .. } => !old_data.data.is_empty(), + _ => false, + }) + .count(); + assert_eq!(filled_count, 3); + + // Undo + model.undo().unwrap(); + assert_eq!(model.get_formatted_cell_value(0, 5, 1).unwrap(), "Row5"); + assert_eq!(model.get_formatted_cell_value(0, 7, 1).unwrap(), "Row7"); + assert_eq!(model.get_formatted_cell_value(0, 9, 1).unwrap(), "Row9"); + assert_eq!(model.get_formatted_cell_value(0, 10, 1).unwrap(), "After"); +} diff --git a/base/src/user_model/common.rs b/base/src/user_model/common.rs index b19ae5b..629bc6a 100644 --- a/base/src/user_model/common.rs +++ b/base/src/user_model/common.rs @@ -933,7 +933,7 @@ impl UserModel { } let data = match worksheet.sheet_data.get(&r) { Some(s) => s.clone(), - None => return Err(format!("Row number '{r}' is not valid.")), + None => HashMap::new(), }; diff_list.push(Diff::DeleteRow { sheet,