use super::*;
mod buffer_id;
mod cache;
mod delimiter;
mod edit;
mod position;
mod saturator;
mod selection;
mod snapshot;
mod word;
mod buffer_id_tests {
use super::*;
#[test]
fn test_unique_ids() {
let id1 = BufferId::new();
let id2 = BufferId::new();
let id3 = BufferId::new();
assert_ne!(id1, id2);
assert_ne!(id2, id3);
assert_ne!(id1, id3);
}
#[test]
fn test_ordering() {
let id1 = BufferId::new();
let id2 = BufferId::new();
assert!(id1 < id2);
}
#[test]
fn test_from_raw() {
let id = BufferId::from_raw(42);
assert_eq!(id.as_usize(), 42);
}
#[test]
#[cfg_attr(coverage_nightly, coverage(off))]
fn test_display() {
let id = BufferId::from_raw(123);
assert_eq!(format!("{id}"), "Buffer(123)");
}
#[test]
fn test_hash() {
use std::collections::HashSet;
let id1 = BufferId::new();
let id2 = BufferId::new();
let mut set = HashSet::new();
set.insert(id1);
set.insert(id2);
set.insert(id1);
assert_eq!(set.len(), 2);
}
}
mod position_tests {
use super::*;
#[test]
fn test_origin() {
let pos = Position::origin();
assert_eq!(pos.line, 0);
assert_eq!(pos.column, 0);
}
#[test]
fn test_new() {
let pos = Position::new(5, 10);
assert_eq!(pos.line, 5);
assert_eq!(pos.column, 10);
}
#[test]
fn test_line_start() {
let pos = Position::line_start(3);
assert_eq!(pos.line, 3);
assert_eq!(pos.column, 0);
}
#[test]
fn test_ordering() {
assert!(Position::new(0, 0) < Position::new(0, 1));
assert!(Position::new(0, 1) < Position::new(1, 0));
assert!(Position::new(1, 5) < Position::new(2, 0));
assert_eq!(Position::new(1, 1), Position::new(1, 1));
}
#[test]
fn test_ordering_same_line() {
assert!(Position::new(5, 0) < Position::new(5, 1));
assert!(Position::new(5, 1) < Position::new(5, 10));
}
#[test]
#[cfg_attr(coverage_nightly, coverage(off))]
fn test_display() {
let pos = Position::new(0, 5);
assert_eq!(format!("{pos}"), "1:6");
}
#[test]
fn test_default() {
let pos = Position::default();
assert_eq!(pos, Position::origin());
}
}
mod cursor_tests {
use super::*;
#[test]
fn test_origin() {
let cursor = Cursor::origin();
assert_eq!(cursor.position, Position::origin());
assert!(cursor.anchor.is_none());
assert!(cursor.preferred_column.is_none());
}
#[test]
fn test_new() {
let cursor = Cursor::new(Position::new(5, 10));
assert_eq!(cursor.position, Position::new(5, 10));
assert!(!cursor.has_selection());
}
#[test]
fn test_selection() {
let mut cursor = Cursor::new(Position::new(0, 5));
assert!(!cursor.has_selection());
cursor.start_selection();
assert!(cursor.has_selection());
assert_eq!(cursor.anchor, Some(Position::new(0, 5)));
cursor.clear_selection();
assert!(!cursor.has_selection());
}
#[test]
fn test_selection_bounds() {
let mut cursor = Cursor::new(Position::new(0, 0));
cursor.start_selection();
cursor.position = Position::new(0, 5);
let bounds = cursor.selection_bounds();
assert_eq!(bounds, Some((Position::new(0, 0), Position::new(0, 5))));
}
#[test]
fn test_selection_bounds_backward() {
let mut cursor = Cursor::new(Position::new(0, 5));
cursor.start_selection();
cursor.position = Position::new(0, 0);
let bounds = cursor.selection_bounds();
assert_eq!(bounds, Some((Position::new(0, 0), Position::new(0, 5))));
}
#[test]
fn test_selection_bounds_multiline() {
let mut cursor = Cursor::new(Position::new(0, 5));
cursor.start_selection();
cursor.position = Position::new(2, 3);
let bounds = cursor.selection_bounds();
assert_eq!(bounds, Some((Position::new(0, 5), Position::new(2, 3))));
}
#[test]
fn test_preferred_column() {
let mut cursor = Cursor::new(Position::new(0, 10));
assert!(cursor.preferred_column.is_none());
assert_eq!(cursor.effective_column(), 10);
cursor.update_preferred_column();
assert_eq!(cursor.preferred_column, Some(10));
assert_eq!(cursor.effective_column(), 10);
cursor.position = Position::new(1, 5);
assert_eq!(cursor.effective_column(), 10);
cursor.clear_preferred_column();
assert!(cursor.preferred_column.is_none());
assert_eq!(cursor.effective_column(), 5); }
}
mod edit_tests {
use super::*;
#[test]
fn test_insert_edit() {
let edit = Edit::insert(Position::new(0, 0), "Hello");
assert!(edit.is_insert());
assert!(!edit.is_delete());
assert_eq!(edit.position(), Position::new(0, 0));
assert_eq!(edit.text(), "Hello");
}
#[test]
fn test_delete_edit() {
let edit = Edit::delete(Position::new(1, 5), "World");
assert!(!edit.is_insert());
assert!(edit.is_delete());
assert_eq!(edit.position(), Position::new(1, 5));
assert_eq!(edit.text(), "World");
}
#[test]
fn test_inverse() {
let insert = Edit::insert(Position::new(0, 0), "Test");
let inverse = insert.inverse();
assert!(inverse.is_delete());
assert_eq!(inverse.position(), Position::new(0, 0));
assert_eq!(inverse.text(), "Test");
let double = inverse.inverse();
assert_eq!(double, insert);
}
#[test]
fn test_is_empty() {
let empty_insert = Edit::insert(Position::origin(), "");
assert!(empty_insert.is_empty());
let non_empty = Edit::insert(Position::origin(), "x");
assert!(!non_empty.is_empty());
}
}
mod buffer_tests {
use super::*;
#[test]
fn test_new_buffer() {
let buf = Buffer::new();
assert_eq!(buf.line_count(), 0);
assert!(buf.is_empty());
assert!(!buf.is_modified());
}
#[test]
fn test_from_string() {
let buf = Buffer::from_string("Hello\nWorld");
assert_eq!(buf.line_count(), 2);
assert_eq!(buf.line(0), Some("Hello"));
assert_eq!(buf.line(1), Some("World"));
}
#[test]
fn test_from_empty_string() {
let buf = Buffer::from_string("");
assert_eq!(buf.line_count(), 0);
assert!(buf.is_empty());
}
#[test]
fn test_from_single_line() {
let buf = Buffer::from_string("Hello");
assert_eq!(buf.line_count(), 1);
assert_eq!(buf.line(0), Some("Hello"));
}
#[test]
fn test_from_trailing_newline() {
let buf = Buffer::from_string("Hello\n");
assert_eq!(buf.line_count(), 1);
assert_eq!(buf.line(0), Some("Hello"));
}
#[test]
fn test_line_len() {
let buf = Buffer::from_string("Hello\nWorld!");
assert_eq!(buf.line_len(0), Some(5));
assert_eq!(buf.line_len(1), Some(6));
assert_eq!(buf.line_len(2), None);
}
#[test]
fn test_content() {
let buf = Buffer::from_string("Hello\nWorld");
assert_eq!(buf.content(), "Hello\nWorld");
}
#[test]
fn test_set_content() {
let mut buf = Buffer::new();
buf.set_content("New\nContent");
assert_eq!(buf.line_count(), 2);
assert_eq!(buf.line(0), Some("New"));
assert!(buf.is_modified());
}
#[test]
fn test_insert_single_char() {
let mut buf = Buffer::from_string("Hello");
buf.insert_at(Position::new(0, 5), "!");
assert_eq!(buf.line(0), Some("Hello!"));
}
#[test]
fn test_insert_at_beginning() {
let mut buf = Buffer::from_string("World");
buf.insert_at(Position::new(0, 0), "Hello ");
assert_eq!(buf.line(0), Some("Hello World"));
}
#[test]
fn test_insert_middle() {
let mut buf = Buffer::from_string("Hllo");
buf.insert_at(Position::new(0, 1), "e");
assert_eq!(buf.line(0), Some("Hello"));
}
#[test]
fn test_insert_newline() {
let mut buf = Buffer::from_string("HelloWorld");
buf.insert_at(Position::new(0, 5), "\n");
assert_eq!(buf.line_count(), 2);
assert_eq!(buf.line(0), Some("Hello"));
assert_eq!(buf.line(1), Some("World"));
}
#[test]
fn test_insert_multiline() {
let mut buf = Buffer::from_string("AC");
buf.insert_at(Position::new(0, 1), "X\nY\nZ");
assert_eq!(buf.line_count(), 3);
assert_eq!(buf.line(0), Some("AX"));
assert_eq!(buf.line(1), Some("Y"));
assert_eq!(buf.line(2), Some("ZC"));
}
#[test]
fn test_insert_into_empty() {
let mut buf = Buffer::new();
buf.insert_at(Position::origin(), "Hello");
assert_eq!(buf.line_count(), 1);
assert_eq!(buf.line(0), Some("Hello"));
}
#[test]
fn test_insert_empty_string() {
let mut buf = Buffer::from_string("Hello");
buf.insert_at(Position::new(0, 2), "");
assert_eq!(buf.line(0), Some("Hello"));
}
#[test]
fn test_delete_single_char() {
let mut buf = Buffer::from_string("Hello");
let deleted = buf.delete_at(Position::new(0, 0), 1);
assert_eq!(buf.line(0), Some("ello"));
assert_eq!(deleted, "H");
}
#[test]
fn test_delete_multiple_chars() {
let mut buf = Buffer::from_string("Hello World");
buf.delete_at(Position::new(0, 0), 6);
assert_eq!(buf.line(0), Some("World"));
}
#[test]
fn test_delete_newline() {
let mut buf = Buffer::from_string("Hello\nWorld");
buf.delete_at(Position::new(0, 5), 1);
assert_eq!(buf.line_count(), 1);
assert_eq!(buf.line(0), Some("HelloWorld"));
}
#[test]
fn test_delete_across_lines() {
let mut buf = Buffer::from_string("Hello\nWorld");
buf.delete_at(Position::new(0, 3), 5); assert_eq!(buf.line_count(), 1);
assert_eq!(buf.line(0), Some("Helrld"));
}
#[test]
fn test_delete_nothing() {
let mut buf = Buffer::from_string("Hello");
let deleted = buf.delete_at(Position::new(0, 2), 0);
assert_eq!(buf.line(0), Some("Hello"));
assert!(deleted.is_empty());
}
#[test]
fn test_delete_past_end() {
let mut buf = Buffer::from_string("Hi");
let deleted = buf.delete_at(Position::new(0, 0), 100);
assert_eq!(deleted, "Hi");
assert!(buf.is_empty());
}
#[test]
fn test_delete_range() {
let mut buf = Buffer::from_string("Hello World");
let deleted = buf.delete_range(Position::new(0, 0), Position::new(0, 5));
assert_eq!(deleted, "Hello");
assert_eq!(buf.line(0), Some(" World"));
}
#[test]
fn test_delete_range_reversed() {
let mut buf = Buffer::from_string("Hello World");
let deleted = buf.delete_range(Position::new(0, 5), Position::new(0, 0));
assert_eq!(deleted, "Hello");
}
#[test]
fn test_delete_range_multiline() {
let mut buf = Buffer::from_string("Hello\nBeautiful\nWorld");
let deleted = buf.delete_range(Position::new(0, 3), Position::new(2, 2));
assert_eq!(deleted, "lo\nBeautiful\nWo");
assert_eq!(buf.line_count(), 1);
assert_eq!(buf.line(0), Some("Helrld"));
}
#[test]
fn test_delete_range_same_position() {
let mut buf = Buffer::from_string("Hello");
let deleted = buf.delete_range(Position::new(0, 2), Position::new(0, 2));
assert_eq!(deleted, "");
assert_eq!(buf.line(0), Some("Hello"));
}
#[test]
fn test_position_to_byte() {
let buf = Buffer::from_string("Hello\nWorld");
assert_eq!(buf.position_to_byte(Position::new(0, 0)), 0);
assert_eq!(buf.position_to_byte(Position::new(0, 5)), 5);
assert_eq!(buf.position_to_byte(Position::new(1, 0)), 6);
assert_eq!(buf.position_to_byte(Position::new(1, 5)), 11);
}
#[test]
fn test_byte_to_position() {
let buf = Buffer::from_string("Hello\nWorld");
assert_eq!(buf.byte_to_position(0), Position::new(0, 0));
assert_eq!(buf.byte_to_position(5), Position::new(0, 5));
assert_eq!(buf.byte_to_position(6), Position::new(1, 0));
assert_eq!(buf.byte_to_position(11), Position::new(1, 5));
}
#[test]
fn test_byte_position_roundtrip() {
let buf = Buffer::from_string("Hello\nWorld\nTest");
for line in 0..buf.line_count() {
for col in 0..=buf.line_len(line).unwrap() {
let pos = Position::new(line, col);
let byte = buf.position_to_byte(pos);
let back = buf.byte_to_position(byte);
assert_eq!(pos, back, "Roundtrip failed for {pos:?}");
}
}
}
#[test]
fn test_unicode_handling() {
let buf = Buffer::from_string("Héllo");
assert_eq!(buf.line_len(0), Some(5));
assert_eq!(buf.position_to_byte(Position::new(0, 0)), 0); assert_eq!(buf.position_to_byte(Position::new(0, 1)), 1); assert_eq!(buf.position_to_byte(Position::new(0, 2)), 3); assert_eq!(buf.position_to_byte(Position::new(0, 5)), 6); }
#[test]
fn test_unicode_insert() {
let mut buf = Buffer::from_string("Héllo");
buf.insert_at(Position::new(0, 5), " World"); assert_eq!(buf.line(0), Some("Héllo World"));
}
#[test]
fn test_modified_flag() {
let mut buf = Buffer::from_string("Hello");
assert!(!buf.is_modified());
buf.insert_at(Position::new(0, 5), "!");
assert!(buf.is_modified());
buf.set_modified(false);
assert!(!buf.is_modified());
}
#[test]
fn test_buffer_id_unique() {
let buf1 = Buffer::new();
let buf2 = Buffer::new();
assert_ne!(buf1.id(), buf2.id());
}
#[test]
fn test_with_id() {
let id = BufferId::from_raw(42);
let buf = Buffer::with_id(id);
assert_eq!(buf.id(), id);
}
}
mod transform_tests {
use super::*;
#[test]
fn test_text_dimensions_single_line() {
let dims = text_dimensions("hello");
assert_eq!(dims.line_count, 0);
assert_eq!(dims.last_line_len, 5);
}
#[test]
fn test_text_dimensions_multi_line() {
let dims = text_dimensions("ab\ncd\ne");
assert_eq!(dims.line_count, 2);
assert_eq!(dims.last_line_len, 1);
}
#[test]
fn test_text_dimensions_trailing_newline() {
let dims = text_dimensions("hello\n");
assert_eq!(dims.line_count, 1);
assert_eq!(dims.last_line_len, 0);
}
#[test]
fn test_text_dimensions_empty() {
let dims = text_dimensions("");
assert_eq!(dims.line_count, 0);
assert_eq!(dims.last_line_len, 0);
}
#[test]
fn test_transform_position_insert_before() {
assert_eq!(
transform_position(Position::new(0, 5), &Edit::insert(Position::new(0, 10), "abc")),
Position::new(0, 5)
);
assert_eq!(
transform_position(Position::new(0, 5), &Edit::insert(Position::new(1, 0), "abc")),
Position::new(0, 5)
);
}
#[test]
fn test_transform_position_insert_after_same_line() {
assert_eq!(
transform_position(Position::new(0, 5), &Edit::insert(Position::new(0, 2), "abc")),
Position::new(0, 8)
);
}
#[test]
fn test_transform_position_insert_after_different_line() {
assert_eq!(
transform_position(Position::new(3, 5), &Edit::insert(Position::new(1, 0), "aa\nbb\n")),
Position::new(5, 5) );
}
#[test]
fn test_transform_position_insert_multiline() {
assert_eq!(
transform_position(Position::new(0, 5), &Edit::insert(Position::new(0, 2), "ab\nc")),
Position::new(1, 4)
);
}
#[test]
fn test_transform_position_same_position_insert() {
assert_eq!(
transform_position(Position::new(0, 5), &Edit::insert(Position::new(0, 5), "abc")),
Position::new(0, 8) );
}
#[test]
fn test_transform_position_delete_before() {
assert_eq!(
transform_position(Position::new(0, 1), &Edit::delete(Position::new(0, 5), "abc")),
Position::new(0, 1)
);
}
#[test]
fn test_transform_position_delete_within() {
assert_eq!(
transform_position(Position::new(0, 3), &Edit::delete(Position::new(0, 2), "abcde")),
Position::new(0, 2)
);
}
#[test]
fn test_transform_position_delete_after_same_line() {
assert_eq!(
transform_position(Position::new(0, 5), &Edit::delete(Position::new(0, 2), "abc")),
Position::new(0, 2)
);
assert_eq!(
transform_position(Position::new(0, 8), &Edit::delete(Position::new(0, 2), "abc")),
Position::new(0, 5) );
}
#[test]
fn test_transform_position_delete_after_different_line() {
assert_eq!(
transform_position(
Position::new(5, 3),
&Edit::delete(Position::new(1, 0), "hello\nworld\n")
),
Position::new(3, 3) );
}
#[test]
fn test_transform_position_delete_multiline() {
assert_eq!(
transform_position(
Position::new(1, 8),
&Edit::delete(Position::new(0, 3), "hello\nworld")
),
Position::new(0, 3 + 8 - 5) );
}
#[test]
fn test_transform_position_delete_multiline_within() {
assert_eq!(
transform_position(
Position::new(1, 5),
&Edit::delete(Position::new(0, 3), "hello\nworld")
),
Position::new(0, 3)
);
}
#[test]
fn test_transform_position_same_position_delete() {
assert_eq!(
transform_position(Position::new(0, 5), &Edit::delete(Position::new(0, 5), "abc")),
Position::new(0, 5) );
}
#[test]
fn test_transform_position_empty_edit() {
assert_eq!(
transform_position(Position::new(0, 5), &Edit::insert(Position::new(0, 2), "")),
Position::new(0, 5)
);
assert_eq!(
transform_position(Position::new(0, 5), &Edit::delete(Position::new(0, 2), "")),
Position::new(0, 5)
);
}
#[test]
fn test_transform_edit_preserves_text() {
let edit = Edit::insert(Position::new(0, 5), "hello");
let against = Edit::insert(Position::new(0, 2), "abc");
let transformed = edit.transform(&against);
assert_eq!(transformed.position(), Position::new(0, 8));
assert_eq!(transformed.text(), "hello"); assert!(transformed.is_insert());
}
#[test]
fn test_transform_edit_delete() {
let edit = Edit::delete(Position::new(0, 5), "xyz");
let against = Edit::insert(Position::new(0, 0), "abc");
let transformed = edit.transform(&against);
assert_eq!(transformed.position(), Position::new(0, 8)); assert_eq!(transformed.text(), "xyz"); assert!(transformed.is_delete());
}
#[test]
fn test_transform_identity_no_shift() {
let edit = Edit::insert(Position::new(0, 0), "hello");
let against = Edit::insert(Position::new(0, 10), "abc");
let transformed = edit.transform(&against);
assert_eq!(transformed.position(), Position::new(0, 0));
assert_eq!(transformed.text(), "hello");
}
#[test]
fn test_delete_end_single_line() {
assert_eq!(delete_end(Position::new(0, 3), "abc"), Position::new(0, 6));
}
#[test]
fn test_delete_end_multi_line() {
assert_eq!(delete_end(Position::new(0, 3), "hello\nworld"), Position::new(1, 5));
}
#[test]
fn test_delete_end_trailing_newline() {
assert_eq!(delete_end(Position::new(2, 0), "hello\n"), Position::new(3, 0));
}
}