use super::*;
#[test]
fn put_and_get_basic() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 5, Value::symbol("face"), Value::symbol("bold"));
assert!(table.get_property(0, Value::symbol("face")).is_some());
assert!(table.get_property(2, Value::symbol("face")).is_some());
assert!(table.get_property(4, Value::symbol("face")).is_some());
assert!(table.get_property(5, Value::symbol("face")).is_none()); }
#[test]
fn get_property_returns_correct_value() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
let val = table.get_property(5, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "bold")
);
}
#[test]
fn get_property_nonexistent_name() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
assert!(
table
.get_property(5, Value::symbol("syntax-table"))
.is_none()
);
}
#[test]
fn get_properties_returns_all() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(0, 10, Value::symbol("help-echo"), Value::string("tooltip"));
let props = table.get_properties(5);
assert_eq!(props.len(), 2);
assert!(props.contains_key(&Value::symbol("face")));
assert!(props.contains_key(&Value::symbol("help-echo")));
}
#[test]
fn get_property_outside_any_interval() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
assert!(table.get_property(0, Value::symbol("face")).is_none());
assert!(table.get_property(3, Value::symbol("face")).is_none());
assert!(table.get_property(10, Value::symbol("face")).is_none());
assert!(table.get_property(15, Value::symbol("face")).is_none());
}
#[test]
fn overlapping_put_splits_intervals() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(5, 15, Value::symbol("face"), Value::symbol("italic"));
let val = table.get_property(3, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "bold")
);
let val = table.get_property(7, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "italic")
);
let val = table.get_property(12, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "italic")
);
}
#[test]
fn multiple_properties_on_same_range() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(
0,
10,
Value::symbol("mouse-face"),
Value::symbol("highlight"),
);
let props = table.get_properties(5);
assert_eq!(props.len(), 2);
}
#[test]
fn put_property_inner_range() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 20, Value::symbol("face"), Value::symbol("default"));
table.put_property(5, 15, Value::symbol("face"), Value::symbol("bold"));
let val = table.get_property(3, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "default")
);
let val = table.get_property(10, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "bold")
);
let val = table.get_property(17, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "default")
);
}
#[test]
fn put_different_properties_on_overlapping_ranges() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(5, 15, Value::symbol("syntax-table"), Value::fixnum(42));
let props = table.get_properties(3);
assert_eq!(props.len(), 1);
assert!(props.contains_key(&Value::symbol("face")));
let props = table.get_properties(7);
assert_eq!(props.len(), 2);
let props = table.get_properties(12);
assert_eq!(props.len(), 1);
assert!(props.contains_key(&Value::symbol("syntax-table")));
}
#[test]
fn remove_property_basic() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(0, 10, Value::symbol("help-echo"), Value::string("help"));
table.remove_property(0, 10, Value::symbol("face"));
assert!(table.get_property(5, Value::symbol("face")).is_none());
assert!(table.get_property(5, Value::symbol("help-echo")).is_some());
}
#[test]
fn remove_property_partial_range() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.remove_property(3, 7, Value::symbol("face"));
assert!(table.get_property(2, Value::symbol("face")).is_some());
assert!(table.get_property(5, Value::symbol("face")).is_none());
assert!(table.get_property(8, Value::symbol("face")).is_some());
}
#[test]
fn remove_all_properties_basic() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(0, 10, Value::symbol("help-echo"), Value::string("help"));
table.remove_all_properties(0, 10);
assert!(table.get_property(5, Value::symbol("face")).is_none());
assert!(table.get_property(5, Value::symbol("help-echo")).is_none());
}
#[test]
fn remove_all_properties_partial() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.remove_all_properties(3, 7);
assert!(table.get_property(2, Value::symbol("face")).is_some());
assert!(table.get_property(5, Value::symbol("face")).is_none());
assert!(table.get_property(8, Value::symbol("face")).is_some());
}
#[test]
fn next_property_change_basic() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(15, 20, Value::symbol("face"), Value::symbol("italic"));
assert_eq!(table.next_property_change(0), Some(5));
assert_eq!(table.next_property_change(7), Some(10));
assert_eq!(table.next_property_change(12), Some(15));
assert_eq!(table.next_property_change(17), Some(20));
assert_eq!(table.next_property_change(25), None);
}
#[test]
fn next_property_change_at_boundary() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
assert_eq!(table.next_property_change(5), Some(10));
}
#[test]
fn previous_property_change_basic() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(15, 20, Value::symbol("face"), Value::symbol("italic"));
assert_eq!(table.previous_property_change(25), Some(20));
assert_eq!(table.previous_property_change(17), Some(15));
assert_eq!(table.previous_property_change(12), Some(10));
assert_eq!(table.previous_property_change(7), Some(5));
assert_eq!(table.previous_property_change(3), None);
assert_eq!(table.previous_property_change(0), None);
}
#[test]
fn previous_property_change_at_end() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
assert_eq!(table.previous_property_change(10), Some(5));
}
#[test]
fn next_previous_empty_table() {
crate::test_utils::init_test_tracing();
let table = TextPropertyTable::new();
assert_eq!(table.next_property_change(0), None);
assert_eq!(table.previous_property_change(10), None);
}
#[test]
fn adjust_insert_shifts_intervals_after() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(10, 20, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_insert(5, 3);
assert!(table.get_property(12, Value::symbol("face")).is_none());
assert!(table.get_property(13, Value::symbol("face")).is_some());
assert!(table.get_property(22, Value::symbol("face")).is_some());
assert!(table.get_property(23, Value::symbol("face")).is_none());
}
#[test]
fn adjust_insert_splits_spanning_interval_around_plain_inserted_text() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 15, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_insert(10, 5);
assert!(table.get_property(5, Value::symbol("face")).is_some());
assert!(table.get_property(9, Value::symbol("face")).is_some());
assert!(table.get_property(10, Value::symbol("face")).is_none());
assert!(table.get_property(12, Value::symbol("face")).is_none());
assert!(table.get_property(14, Value::symbol("face")).is_none());
assert!(table.get_property(15, Value::symbol("face")).is_some());
assert!(table.get_property(20, Value::symbol("face")).is_none());
}
#[test]
fn adjust_insert_at_interval_start() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_insert(5, 3);
assert!(table.get_property(7, Value::symbol("face")).is_none());
assert!(table.get_property(8, Value::symbol("face")).is_some());
assert!(table.get_property(12, Value::symbol("face")).is_some());
assert!(table.get_property(13, Value::symbol("face")).is_none());
}
#[test]
fn adjust_insert_before_all() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_insert(0, 2);
assert!(table.get_property(7, Value::symbol("face")).is_some());
assert!(table.get_property(6, Value::symbol("face")).is_none());
}
#[test]
fn adjust_insert_zero_length() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_insert(7, 0);
assert!(table.get_property(5, Value::symbol("face")).is_some());
assert!(table.get_property(9, Value::symbol("face")).is_some());
assert!(table.get_property(10, Value::symbol("face")).is_none());
}
#[test]
fn adjust_delete_shifts_intervals_after() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(10, 20, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_delete(2, 5);
assert!(table.get_property(6, Value::symbol("face")).is_none());
assert!(table.get_property(7, Value::symbol("face")).is_some());
assert!(table.get_property(16, Value::symbol("face")).is_some());
assert!(table.get_property(17, Value::symbol("face")).is_none());
}
#[test]
fn adjust_delete_removes_contained_interval() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_delete(3, 12);
assert!(table.get_property(5, Value::symbol("face")).is_none());
assert!(table.get_property(3, Value::symbol("face")).is_none());
}
#[test]
fn adjust_delete_truncates_start() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 15, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_delete(10, 20);
assert!(table.get_property(5, Value::symbol("face")).is_some());
assert!(table.get_property(9, Value::symbol("face")).is_some());
assert!(table.get_property(10, Value::symbol("face")).is_none());
}
#[test]
fn adjust_delete_shrinks_spanning_interval() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 20, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_delete(10, 15);
assert!(table.get_property(5, Value::symbol("face")).is_some());
assert!(table.get_property(14, Value::symbol("face")).is_some());
assert!(table.get_property(15, Value::symbol("face")).is_none());
}
#[test]
fn adjust_delete_overlaps_interval_start() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 15, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_delete(2, 10);
assert!(table.get_property(2, Value::symbol("face")).is_some());
assert!(table.get_property(6, Value::symbol("face")).is_some());
assert!(table.get_property(7, Value::symbol("face")).is_none());
}
#[test]
fn adjust_delete_empty_range() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
table.adjust_for_delete(7, 7);
assert!(table.get_property(5, Value::symbol("face")).is_some());
assert!(table.get_property(9, Value::symbol("face")).is_some());
}
#[test]
fn merge_adjacent_same_properties() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 5, Value::symbol("face"), Value::symbol("bold"));
table.put_property(5, 10, Value::symbol("face"), Value::symbol("bold"));
assert!(table.get_property(0, Value::symbol("face")).is_some());
assert!(table.get_property(7, Value::symbol("face")).is_some());
assert_eq!(table.intervals_snapshot().len(), 1);
assert_eq!(table.next_property_change(0), Some(10));
assert_eq!(table.next_property_change(5), Some(10));
assert_eq!(table.previous_property_change(10), Some(0));
}
#[test]
fn no_merge_different_properties() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 5, Value::symbol("face"), Value::symbol("bold"));
table.put_property(5, 10, Value::symbol("face"), Value::symbol("italic"));
assert_eq!(table.next_property_change(0), Some(5));
assert_eq!(table.next_property_change(5), Some(10));
}
#[test]
fn put_property_empty_range() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(5, 5, Value::symbol("face"), Value::symbol("bold"));
assert!(table.get_property(5, Value::symbol("face")).is_none());
}
#[test]
fn put_property_overwrites_same_name() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 10, Value::symbol("face"), Value::symbol("bold"));
table.put_property(0, 10, Value::symbol("face"), Value::symbol("italic"));
let val = table.get_property(5, Value::symbol("face")).unwrap();
assert!(
val.as_symbol_id()
.map_or(false, |id| crate::emacs_core::intern::resolve_sym(id)
== "italic")
);
}
#[test]
fn multiple_non_contiguous_intervals() {
crate::test_utils::init_test_tracing();
let mut table = TextPropertyTable::new();
table.put_property(0, 5, Value::symbol("face"), Value::symbol("bold"));
table.put_property(10, 15, Value::symbol("face"), Value::symbol("italic"));
table.put_property(20, 25, Value::symbol("face"), Value::symbol("underline"));
assert!(table.get_property(3, Value::symbol("face")).is_some());
assert!(table.get_property(7, Value::symbol("face")).is_none());
assert!(table.get_property(12, Value::symbol("face")).is_some());
assert!(table.get_property(17, Value::symbol("face")).is_none());
assert!(table.get_property(22, Value::symbol("face")).is_some());
}