led/sub_crates/backend/tests/change.rs

66 lines
2.0 KiB
Rust

#[macro_use]
extern crate proptest;
use proptest::collection::vec;
use proptest::test_runner::Config;
use ropey::Rope;
use backend::change::{ApplyChange, Change};
fn make_edit_list_valid(edits: &mut Vec<(usize, usize, String)>, start_text: &str) {
edits.sort_by_key(|e| e.0);
let mut tail = 0;
for e in edits.iter_mut() {
e.0 = e.0.max(tail);
while e.0 < start_text.len() && !start_text.is_char_boundary(e.0) {
e.0 += 1;
}
while (e.0 + e.1) < start_text.len() && !start_text.is_char_boundary(e.0 + e.1) {
e.1 += 1;
}
tail = e.0 + e.1;
}
for i in (0..edits.len()).rev() {
if edits[i].0 > start_text.len() {
edits.remove(i);
} else if (edits[i].0 + edits[i].1) > start_text.len() {
edits[i].1 = start_text.len() - edits[i].0;
}
}
}
proptest! {
#![proptest_config(Config::with_cases(512))]
#[test]
fn compose(
ref start_text in "\\PC{0, 200}",
mut edits1 in vec((0usize..100, 0usize..10, "\\PC{0, 10}"), 0..5),
mut edits2 in vec((0usize..100, 0usize..10, "\\PC{0, 10}"), 0..5),
) {
// Make edits1 valid and compute the post-edits1 string.
make_edit_list_valid(&mut edits1, start_text);
let change1 = Change::from_ordered_edit_set(edits1.iter().map(|e| {
(e.0, &start_text[e.0..(e.0+e.1)], &e.2[..])
}));
let mut r1 = Rope::from_str(start_text);
r1.apply_change(&change1);
let text1: String = r1.clone().into();
// Make edits2 valid and compute the post-edits2 string.
make_edit_list_valid(&mut edits2, &text1);
let change2 = Change::from_ordered_edit_set(edits2.iter().map(|e| {
(e.0, &text1[e.0..(e.0+e.1)], &e.2[..])
}));
r1.apply_change(&change2);
// Do the test!
let change3 = change1.compose(&change2);
let mut r2 = Rope::from_str(start_text);
r2.apply_change(&change3);
assert_eq!(r1, r2);
}
}