aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-31 19:57:31 +0100
committertv <tv@krebsco.de>2026-10-31 19:57:31 +0100
commitddcdabbe3c3f8f53ea8ed3fc21c55bd6eb8cafba (patch)
tree9916e2de8e7791f26dab9ec20f9b3f984cdb61ea /src
parent6105507200231e67ba544c12aa10b988e1c23826 (diff)
add save-after-rollback test
Diffstat (limited to 'src')
-rw-r--r--src/document/replica.rs34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/document/replica.rs b/src/document/replica.rs
index 20c02e5..27c81ad 100644
--- a/src/document/replica.rs
+++ b/src/document/replica.rs
@@ -225,6 +225,40 @@ mod tests {
assert_eq!(local.relation_to(&epoch(3, 2)), EpochRelation::Diverged);
}
+ /// A rolled-back write leaves its writer unused in the document; saving must not
+ /// trip over it (Automerge refuses to save a document with unused writers).
+ #[test]
+ fn saves_after_a_rolled_back_write() {
+ use crate::clock::UnixMillis;
+ use crate::document::store;
+ use serde_json::json;
+
+ let path = vec!["a".to_owned()];
+ let mut replica = Replica::new(Epoch::GENESIS, Document::new());
+
+ let refused: Result<(), &str> = replica.transact(UnixMillis(1), |doc| {
+ store::write_path(doc, &path, &json!(1)).unwrap();
+ Err("refused")
+ });
+ assert!(refused.is_err());
+ let loaded = super::super::load(&super::super::save(&replica.doc)).unwrap();
+ assert!(loaded.get_heads().is_empty());
+ assert_eq!(store::read_path(&loaded, &path).unwrap(), None);
+
+ // The same writer commits afterwards, and that saves too.
+ replica
+ .transact(UnixMillis(2), |doc| {
+ store::write_path(doc, &path, &json!(2))
+ })
+ .unwrap();
+ replica.refresh_heads();
+ let loaded = super::super::load(&super::super::save(&replica.doc)).unwrap();
+ let mut heads = loaded.get_heads();
+ heads.sort_unstable();
+ assert_eq!(heads, replica.heads());
+ assert_eq!(store::read_path(&loaded, &path).unwrap(), Some(json!(2)));
+ }
+
#[test]
fn display() {
assert_eq!(Epoch::GENESIS.to_string(), "0:genesis");