Description
I've noticed what I think is a bug in autosurgeon
.
In the test that follows, I create a data structure with a Vec
of 3 strings, fork it, remove one element in one document and another in the other document, then merge them back and get a document where both elements are removed, as expected:
#[test]
fn remove_vec_of_strings() {
#[derive(Hydrate, Reconcile)]
struct Data {
rows: Vec<String>,
}
// Create data with 3 rows
let mut data1 = Data {
rows: vec!["hello".to_owned(), "world".to_owned(), "foobar".to_owned()],
};
let mut doc1 = AutoCommit::new();
reconcile(&mut doc1, &data1).unwrap();
// Fork into another document
let mut doc2 = doc1.fork();
let mut data2: Data = hydrate(&doc2).unwrap();
// Remove row 0 in first document, and row 1 in second
data1.rows.remove(0);
data2.rows.remove(1);
reconcile(&mut doc1, data1).unwrap();
reconcile(&mut doc2, data2).unwrap();
// Merge documents
doc1.merge(&mut doc2).unwrap();
let data_merged: Data = hydrate(&doc1).unwrap();
// Both rows 0 and 1 have been removed
assert_eq!(data_merged.rows.len(), 1);
assert_eq!(&data_merged.rows[0], "foobar");
}
However, in the next test, I do the exact same, but the document contains a Vec
of three Vec
s of bytes. Here, the results are different: we get a document with two elements, in which some values are scrambled. Note that I'm aware of the existence of ByteVec
, but for this example I'm not using them.
#[test]
fn remove_vec_of_bytes() {
#[derive(Hydrate, Reconcile)]
struct Data {
rows: Vec<Vec<u8>>,
}
// Same as above
let mut data1 = Data {
rows: vec![b"hello".to_vec(), b"world".to_vec(), b"foobar".to_vec()],
};
let mut doc1 = AutoCommit::new();
reconcile(&mut doc1, &data1).unwrap();
let mut doc2 = doc1.fork();
let mut data2: Data = hydrate(&doc2).unwrap();
data1.rows.remove(0);
data2.rows.remove(1);
reconcile(&mut doc1, data1).unwrap();
reconcile(&mut doc2, data2).unwrap();
doc1.merge(&mut doc2).unwrap();
let data_merged: Data = hydrate(&doc1).unwrap();
// There are two rows, with the following values:
assert_eq!(data_merged.rows.len(), 2);
assert_eq!(&data_merged.rows[0], b"world");
assert_eq!(&data_merged.rows[1], b"ffoobaobar");
// Instead, I'd expect to have the same results as the previous test
}
I tried doing things manually with automerge
, i.e. creating a document with nested lists, forking, removing elements, and merging again, but I don't get any weird results there, which leads me to conclude that autosurgeon
's implementation must have an issue somewhere---or perhaps that I misunderstood something.
Same test again, using `automerge` directly:
#[test]
fn remove_vec_of_bytes_automerge() {
let mut doc1 = AutoCommit::new();
let rows = doc1
.put_object(automerge::ROOT, "rows", automerge::ObjType::List)
.unwrap();
let row = doc1
.insert_object(&rows, 0, automerge::ObjType::List)
.unwrap();
for (i, b) in b"hello".into_iter().enumerate() {
doc1.insert(&row, i, *b as u64).unwrap();
}
let row = doc1
.insert_object(&rows, 1, automerge::ObjType::List)
.unwrap();
for (i, b) in b"world".into_iter().enumerate() {
doc1.insert(&row, i, *b as u64).unwrap();
}
let row = doc1
.insert_object(&rows, 2, automerge::ObjType::List)
.unwrap();
for (i, b) in b"foobar".into_iter().enumerate() {
doc1.insert(&row, i, *b as u64).unwrap();
}
let mut doc2 = doc1.fork();
doc1.delete(&rows, 0).unwrap();
doc2.delete(&rows, 1).unwrap();
assert_eq!(doc1.length(&rows), 2);
assert_eq!(doc2.length(&rows), 2);
doc1.merge(&mut doc2).unwrap();
assert_eq!(doc1.length(&rows), 1);
assert_eq!(
doc1.list_range(doc1.get(&rows, 0).unwrap().unwrap().1, ..)
.map(|(_, value, _)| value.to_u64().unwrap() as u8)
.collect::<Vec<_>>(),
b"foobar"
);
}
Activity