use yrs::updates::decoder::Decode; use yrs::{Doc, GetString, Options, ReadTxn, StateVector, Text, Transact, Update}; #[test] fn partially_known_delete_range_remains_deleted_when_tail_arrives() { check_missing_tail(false, false); } #[test] fn partially_known_delete_range_survives_snapshot_before_tail_arrives() { check_missing_tail(true, false); } #[test] fn deletion_received_before_any_source_update_is_preserved() { check_missing_tail(false, true); } #[test] fn unknown_client_deletion_survives_snapshot_before_source_arrives() { check_missing_tail(true, true); } fn check_missing_tail(reload: bool, deletion_first: bool) { let sender = Doc::with_options(Options::with_guid_and_client_id( "delete-tail-review".into(), 111, )); let text = sender.get_or_insert_text("text"); text.insert(&mut sender.transact_mut(), 0, "abcdef"); let first = sender .transact() .encode_state_as_update_v1(&StateVector::default()); let before_tail = sender.transact().state_vector(); text.insert(&mut sender.transact_mut(), 6, "ghij"); let delayed = sender.transact().encode_state_as_update_v1(&before_tail); let before_delete = sender.transact().state_vector(); text.remove_range(&mut sender.transact_mut(), 2, 8); let deletion = sender.transact().encode_state_as_update_v1(&before_delete); let mut receiver = Doc::with_options(Options::with_guid_and_client_id( "delete-tail-review".into(), 222, )); let updates = if deletion_first { [deletion, first] } else { [first, deletion] }; for (index, update) in updates.into_iter().enumerate() { receiver .transact_mut() .apply_update(Update::decode_v1(&update).unwrap()) .unwrap(); if reload && index == if deletion_first { 0 } else { 1 } { let snapshot = receiver .transact() .encode_state_as_update_v1(&StateVector::default()); receiver = Doc::with_options(Options::with_guid_and_client_id( "delete-tail-review".into(), 333, )); receiver .transact_mut() .apply_update(Update::decode_v1(&snapshot).unwrap()) .unwrap(); } } receiver .transact_mut() .apply_update(Update::decode_v1(&delayed).unwrap()) .unwrap(); let received = receiver.get_or_insert_text("text"); assert_eq!(text.get_string(&sender.transact()), "ab"); assert_eq!( received.get_string(&receiver.transact()), "ab", "A deletion covering an unseen suffix must survive until that suffix arrives" ); }