extern crate text_document_editing as document_editing;
use anyhow::Result;
use test_harness::{export_text, get_block_ids, get_document_stats, setup_with_text};
use document_editing::document_editing_controller;
use document_editing::*;
#[test]
fn test_insert_text_empty_string_is_noop() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello")?;
let result = document_editing_controller::insert_text(
&db,
&hub,
&mut urm,
None,
&InsertTextDto {
position: 3,
anchor: 3,
text: "".to_string(),
},
)?;
assert_eq!(result.new_position, 3);
assert_eq!(export_text(&db, &hub)?, "Hello");
Ok(())
}
#[test]
fn test_insert_text_at_beyond_document_end_clamps() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello")?;
let result = document_editing_controller::insert_text(
&db,
&hub,
&mut urm,
None,
&InsertTextDto {
position: 999,
anchor: 999,
text: "!".to_string(),
},
)?;
assert_eq!(export_text(&db, &hub)?, "Hello!");
let stats = get_document_stats(&db)?;
assert_eq!(stats.character_count, 6);
assert_eq!(result.new_position, 6);
Ok(())
}
#[test]
fn test_delete_text_empty_range_is_noop() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello")?;
let result = document_editing_controller::delete_text(
&db,
&hub,
&mut urm,
None,
&DeleteTextDto {
position: 3,
anchor: 3,
},
)?;
assert_eq!(result.new_position, 3);
assert_eq!(result.deleted_text, "");
assert_eq!(export_text(&db, &hub)?, "Hello");
Ok(())
}
#[test]
fn test_delete_all_text_leaves_one_block() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello\nWorld")?;
document_editing_controller::delete_text(
&db,
&hub,
&mut urm,
None,
&DeleteTextDto {
position: 0,
anchor: 11,
},
)?;
let stats = get_document_stats(&db)?;
assert!(
stats.block_count >= 1,
"Should have at least 1 block after deleting all"
);
assert_eq!(stats.character_count, 0);
Ok(())
}
#[test]
fn test_insert_block_at_position_zero() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello")?;
let result = document_editing_controller::insert_block(
&db,
&hub,
&mut urm,
None,
&InsertBlockDto {
position: 0,
anchor: 0,
},
)?;
assert!(result.new_block_id > 0);
let stats = get_document_stats(&db)?;
assert_eq!(stats.block_count, 2);
urm.undo(None)?;
let stats = get_document_stats(&db)?;
assert_eq!(stats.block_count, 1);
assert_eq!(export_text(&db, &hub)?, "Hello");
Ok(())
}
#[test]
fn test_insert_block_in_empty_document() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let result = document_editing_controller::insert_block(
&db,
&hub,
&mut urm,
None,
&InsertBlockDto {
position: 0,
anchor: 0,
},
)?;
assert!(result.new_block_id > 0);
let stats = get_document_stats(&db)?;
assert_eq!(stats.block_count, 2);
Ok(())
}
#[test]
fn test_insert_table_zero_dimensions_errors() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let result = document_editing_controller::insert_table(
&db,
&hub,
&mut urm,
None,
&InsertTableDto {
position: 0,
anchor: 0,
rows: 0,
columns: 0,
},
);
assert!(result.is_err(), "0x0 table should fail");
Ok(())
}
#[test]
fn test_insert_table_negative_dimensions_errors() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let result = document_editing_controller::insert_table(
&db,
&hub,
&mut urm,
None,
&InsertTableDto {
position: 0,
anchor: 0,
rows: -1,
columns: 2,
},
);
assert!(result.is_err(), "Negative row count should fail");
Ok(())
}
#[test]
fn test_remove_table_nonexistent_errors() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello")?;
let result = document_editing_controller::remove_table(
&db,
&hub,
&mut urm,
None,
&RemoveTableDto { table_id: 999999 },
);
assert!(result.is_err(), "Removing non-existent table should fail");
Ok(())
}
#[test]
fn test_merge_cells_invalid_range_errors() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let insert_result = document_editing_controller::insert_table(
&db,
&hub,
&mut urm,
None,
&InsertTableDto {
position: 0,
anchor: 0,
rows: 2,
columns: 2,
},
)?;
let result = document_editing_controller::merge_table_cells(
&db,
&hub,
&mut urm,
None,
&MergeTableCellsDto {
table_id: insert_result.table_id,
start_row: 1,
start_column: 1,
end_row: 0,
end_column: 0,
},
);
assert!(result.is_err(), "Inverted merge range should fail");
Ok(())
}
#[test]
fn test_merge_cells_out_of_bounds_errors() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let insert_result = document_editing_controller::insert_table(
&db,
&hub,
&mut urm,
None,
&InsertTableDto {
position: 0,
anchor: 0,
rows: 2,
columns: 2,
},
)?;
let result = document_editing_controller::merge_table_cells(
&db,
&hub,
&mut urm,
None,
&MergeTableCellsDto {
table_id: insert_result.table_id,
start_row: 0,
start_column: 0,
end_row: 5,
end_column: 5,
},
);
assert!(result.is_err(), "Out-of-bounds merge should fail");
Ok(())
}
#[test]
fn test_remove_last_row_errors_or_removes_table() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let insert_result = document_editing_controller::insert_table(
&db,
&hub,
&mut urm,
None,
&InsertTableDto {
position: 0,
anchor: 0,
rows: 1,
columns: 2,
},
)?;
let result = document_editing_controller::remove_table_row(
&db,
&hub,
&mut urm,
None,
&RemoveTableRowDto {
table_id: insert_result.table_id,
row_index: 0,
},
);
if let Ok(r) = result {
assert_eq!(r.new_row_count, 0);
}
Ok(())
}
#[test]
fn test_remove_last_column_errors_or_removes_table() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let insert_result = document_editing_controller::insert_table(
&db,
&hub,
&mut urm,
None,
&InsertTableDto {
position: 0,
anchor: 0,
rows: 2,
columns: 1,
},
)?;
let result = document_editing_controller::remove_table_column(
&db,
&hub,
&mut urm,
None,
&RemoveTableColumnDto {
table_id: insert_result.table_id,
column_index: 0,
},
);
if let Ok(r) = result {
assert_eq!(r.new_column_count, 0);
}
Ok(())
}
#[test]
fn test_remove_row_out_of_bounds_errors() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("")?;
let insert_result = document_editing_controller::insert_table(
&db,
&hub,
&mut urm,
None,
&InsertTableDto {
position: 0,
anchor: 0,
rows: 2,
columns: 2,
},
)?;
let result = document_editing_controller::remove_table_row(
&db,
&hub,
&mut urm,
None,
&RemoveTableRowDto {
table_id: insert_result.table_id,
row_index: 99,
},
);
assert!(result.is_err(), "Removing out-of-bounds row should fail");
Ok(())
}
#[test]
fn test_add_block_to_nonexistent_list_errors() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello")?;
let block_ids = get_block_ids(&db)?;
let result = document_editing_controller::add_block_to_list(
&db,
&hub,
&mut urm,
None,
&AddBlockToListDto {
block_id: block_ids[0] as i64,
list_id: 999999,
},
);
assert!(
result.is_err(),
"Adding block to non-existent list should fail"
);
Ok(())
}
#[test]
fn test_remove_block_from_list_when_not_in_list() -> Result<()> {
let (db, hub, mut urm) = setup_with_text("Hello")?;
let block_ids = get_block_ids(&db)?;
let result = document_editing_controller::remove_block_from_list(
&db,
&hub,
&mut urm,
None,
&RemoveBlockFromListDto {
block_id: block_ids[0] as i64,
},
);
if let Ok(()) = result {
assert_eq!(export_text(&db, &hub)?, "Hello");
}
Ok(())
}