loro/crates/delta/tests/test_text_delta.rs

310 lines
8.7 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
use loro_delta::{
text_delta::{TextChunk, TextDelta},
DeltaRopeBuilder,
};
use tracing_subscriber::fmt::format::FmtSpan;
#[ctor::ctor]
fn init_color_backtrace() {
color_backtrace::install();
use tracing_subscriber::{prelude::*, registry::Registry};
if option_env!("DEBUG").is_some() {
tracing::subscriber::set_global_default(
Registry::default().with(
tracing_subscriber::fmt::Layer::default()
.with_file(true)
.with_line_number(true)
.with_span_events(FmtSpan::ACTIVE),
),
)
.unwrap();
}
}
#[test]
fn text_delta() {
let mut text = TextDelta::new();
text.push_str_insert("123456789");
assert_eq!(text.try_to_string().unwrap(), "123456789");
let mut delta = TextDelta::new();
delta
.push_str_insert("abc")
.push_retain(3, ())
.push_delete(3);
text.compose(&delta);
assert_eq!(text.try_to_string().unwrap(), "abc123789");
}
#[test]
fn delete_delta_compose() {
let mut a: TextDelta = DeltaRopeBuilder::new().delete(5).build();
let b: TextDelta = DeltaRopeBuilder::new().delete(5).build();
a.compose(&b);
assert_eq!(a, DeltaRopeBuilder::new().delete(10).build());
}
#[test]
fn insert_long() {
let mut a: TextDelta = TextDelta::new();
a.push_str_insert("1234567890");
a.insert_str(3, &"abc".repeat(10));
assert_eq!(
a,
DeltaRopeBuilder::new()
.insert(TextChunk::try_from_str("123abc").unwrap(), ())
.insert(TextChunk::try_from_str("abcabcabc").unwrap(), ())
.insert(TextChunk::try_from_str("abcabcabc").unwrap(), ())
.insert(TextChunk::try_from_str("abcabcabc").unwrap(), ())
.insert(TextChunk::try_from_str("4567890").unwrap(), ())
.build()
);
}
#[test]
fn retain_delete_delta_compose() {
let mut a: TextDelta = DeltaRopeBuilder::new().retain(5, ()).build();
let b: TextDelta = DeltaRopeBuilder::new().delete(5).build();
a.compose(&b);
assert_eq!(a, DeltaRopeBuilder::new().delete(5).build());
}
#[test]
fn retain_delete_delta_compose_1() {
let mut a: TextDelta = DeltaRopeBuilder::new().retain(10, ()).build();
let b: TextDelta = DeltaRopeBuilder::new().retain(2, ()).delete(5).build();
a.compose(&b);
assert_eq!(
a,
DeltaRopeBuilder::new()
.retain(2, ())
.delete(5)
.retain(3, ())
.build()
);
}
#[test]
fn compose_long_delete() {
let mut a: TextDelta = TextDelta::new();
a.push_retain(5, ());
a.push_str_insert("1234567890");
a.push_retain(5, ());
a.push_delete(1);
a.push_str_insert("1234567890");
let b: TextDelta = DeltaRopeBuilder::new().retain(2, ()).delete(20).build();
a.compose(&b);
assert_eq!(
a,
DeltaRopeBuilder::new()
.retain(2, ())
.replace(TextChunk::try_from_str("34567890").unwrap(), (), 9)
.build()
);
}
type RichTextDelta = TextDelta<HashMap<String, bool>>;
#[test]
fn rich_text_delta() {
let mut text = RichTextDelta::new();
text.push_str_insert("123456789");
assert_eq!(text.try_to_string().unwrap(), "123456789");
let mut delta = RichTextDelta::new();
let mut styles = HashMap::new();
styles.insert("bold".to_string(), true);
delta
.push_str_insert("abc")
.push_retain(3, styles.clone())
.push_delete(3);
text.compose(&delta);
let mut expected = RichTextDelta::new();
expected
.push_str_insert("abc")
.push_insert(TextChunk::try_from_str("123").unwrap(), styles.clone())
.push_str_insert("789");
assert_eq!(text, expected);
}
#[test]
fn insert_plus_insert() {
let mut a: TextDelta = TextDelta::new();
a.push_str_insert("A");
let mut b = TextDelta::new();
b.push_str_insert("B");
let expected = {
let mut delta = TextDelta::new();
delta.push_str_insert("B").push_str_insert("A");
delta
};
a.compose(&b);
assert_eq!(a, expected);
}
#[test]
fn insert_plus_retain() {
let mut a: RichTextDelta = TextDelta::new();
a.push_str_insert("A");
let mut b: RichTextDelta = TextDelta::new();
let mut attrs = HashMap::new();
attrs.insert("bold".to_string(), true);
attrs.insert("color".to_string(), true);
b.push_retain(1, attrs.clone());
let expected = {
let mut delta = TextDelta::new();
delta.push_insert(TextChunk::try_from_str("A").unwrap(), attrs);
delta
};
a.compose(&b);
assert_eq!(a, expected);
}
#[test]
fn insert_plus_delete() {
let mut a: TextDelta = TextDelta::new();
a.push_str_insert("A");
let mut b: TextDelta = TextDelta::new();
b.push_delete(1);
let expected = TextDelta::new();
a.compose(&b);
assert_eq!(a, expected);
}
#[test]
fn delete_plus_delete() {
let mut a: TextDelta = TextDelta::new();
a.push_delete(1);
let mut b: TextDelta = TextDelta::new();
b.push_delete(1);
let expected = {
let mut delta = TextDelta::new();
delta.push_delete(2);
delta
};
a.compose(&b);
assert_eq!(a, expected);
}
#[test]
fn retain_plus_insert() {
let mut a: RichTextDelta = TextDelta::new();
let mut attrs = HashMap::new();
attrs.insert("color".to_string(), true);
a.push_retain(1, attrs.clone());
let mut b = TextDelta::new();
b.push_str_insert("B");
let expected = {
let mut delta = TextDelta::new();
delta.push_str_insert("B").push_retain(1, attrs);
delta
};
a.compose(&b);
assert_eq!(a, expected);
}
#[test]
fn retain_plus_retain() {
let mut a: RichTextDelta = TextDelta::new();
let mut attrs_a = HashMap::new();
attrs_a.insert("color".to_string(), true);
a.push_retain(1, attrs_a.clone());
let mut b = TextDelta::new();
let mut attrs_b = HashMap::new();
attrs_b.insert("bold".to_string(), true);
attrs_b.insert("color".to_string(), true);
b.push_retain(1, attrs_b.clone());
let expected = {
let mut delta = TextDelta::new();
delta.push_retain(1, attrs_b);
delta
};
a.compose(&b);
assert_eq!(a, expected);
}
#[test]
fn retain_plus_delete() {
let mut a: RichTextDelta = TextDelta::new();
let mut attrs = HashMap::new();
attrs.insert("color".to_string(), true);
a.push_retain(1, attrs);
let mut b = TextDelta::new();
b.push_delete(1);
let mut expected: RichTextDelta = TextDelta::new();
expected.push_delete(1);
a.compose(&b);
assert_eq!(a, expected);
}
// Test for inserting in the middle of text
#[test]
fn insert_in_middle_of_text() {
let mut a: TextDelta = TextDelta::new();
a.push_str_insert("Hello");
let mut b: TextDelta = TextDelta::new();
b.push_retain(3, ()).push_str_insert("X");
let mut expected: TextDelta = TextDelta::new();
expected.push_str_insert("HelXlo");
a.compose(&b);
assert_eq!(a, expected);
}
// Test for insert and delete ordering
#[test]
fn insert_and_delete_ordering() {
let mut a: TextDelta = TextDelta::new();
a.push_str_insert("Hello");
let mut insert_first: TextDelta = TextDelta::new();
insert_first
.push_retain(3, ())
.push_str_insert("X")
.push_delete(1);
let mut delete_first = TextDelta::new();
delete_first
.push_retain(3, ())
.push_delete(1)
.push_str_insert("X");
let mut expected: TextDelta = TextDelta::new();
expected.push_str_insert("HelXo");
a.compose(&insert_first);
a.compose(&delete_first);
assert_eq!(a, expected);
}
#[test]
fn retain_start_optimization_split() {
let mut a: RichTextDelta = TextDelta::new();
let mut attrs_bold = HashMap::new();
attrs_bold.insert("bold".to_string(), true);
a.push_insert(TextChunk::try_from_str("A").unwrap(), attrs_bold.clone())
.push_str_insert("B")
.push_insert(TextChunk::try_from_str("C").unwrap(), attrs_bold)
.push_retain(5, Default::default())
.push_delete(1);
let mut b: RichTextDelta = TextDelta::new();
b.push_retain(4, Default::default()).push_str_insert("D");
let expected = {
let mut delta = TextDelta::new();
let mut attrs_bold = HashMap::new();
attrs_bold.insert("bold".to_string(), true);
delta
.push_insert(TextChunk::try_from_str("A").unwrap(), attrs_bold.clone())
.push_str_insert("B")
.push_insert(TextChunk::try_from_str("C").unwrap(), attrs_bold)
.push_retain(1, Default::default())
.push_str_insert("D")
.push_retain(4, Default::default())
.push_delete(1);
delta
};
a.compose(&b);
assert_eq!(a, expected);
}