#[cfg(test)]
mod tests {
use crate::crdt::{Crdt, GCounter, LwwRegister, OrSet, PnCounter};
#[test]
fn test_multi_device_g_counter_sync() {
let mut device1 = GCounter::new("device-1".to_string());
let mut device2 = GCounter::new("device-2".to_string());
let mut device3 = GCounter::new("device-3".to_string());
for _ in 0..10 {
device1.increment(1);
}
for _ in 0..15 {
device2.increment(1);
}
for _ in 0..20 {
device3.increment(1);
}
device1.merge(&device2).ok();
assert_eq!(device1.value(), 25);
device1.merge(&device3).ok();
assert_eq!(device1.value(), 45);
device2.merge(&device3).ok();
assert_eq!(device2.value(), 35);
device2.merge(&device1).ok();
assert_eq!(device2.value(), 45); }
#[test]
fn test_pn_counter_concurrent_operations() {
let mut counter1 = PnCounter::new("device-1".to_string());
let mut counter2 = PnCounter::new("device-2".to_string());
counter1.increment(50);
counter1.decrement(10);
counter2.increment(30);
counter2.decrement(5);
assert_eq!(counter1.value(), 40); assert_eq!(counter2.value(), 25);
counter1.merge(&counter2).ok();
assert_eq!(counter1.value(), 65);
}
#[test]
fn test_lww_register_conflicts() {
let mut reg1 = LwwRegister::new("device-1".to_string(), "initial".to_string());
let mut reg2 = LwwRegister::new("device-2".to_string(), "initial".to_string());
reg1.set("update-from-device-1".to_string());
reg2.set("update-from-device-2".to_string());
reg1.merge(®2).ok();
assert_eq!(reg1.get(), "update-from-device-2");
}
#[test]
fn test_or_set_concurrent_add_remove_scenarios() {
let mut set1 = OrSet::new("device-1".to_string());
let mut set2 = OrSet::new("device-2".to_string());
set1.insert("a".to_string());
set1.insert("b".to_string());
set2.insert("b".to_string());
set2.insert("c".to_string());
set1.remove(&"b".to_string());
set1.merge(&set2).ok();
assert!(set1.contains(&"a".to_string()));
assert!(set1.contains(&"b".to_string())); assert!(set1.contains(&"c".to_string()));
}
#[test]
fn test_mixed_crdt_workflow() {
let mut title1 = LwwRegister::new("device-1".to_string(), "Untitled".to_string());
let mut title2 = LwwRegister::new("device-2".to_string(), "Untitled".to_string());
title1.set("My Document".to_string());
title2.set("Our Document".to_string());
title1.merge(&title2).ok();
let mut tags1 = OrSet::new("device-1".to_string());
let mut tags2 = OrSet::new("device-2".to_string());
tags1.insert("rust".to_string());
tags1.insert("sync".to_string());
tags2.insert("crdt".to_string());
tags2.insert("distributed".to_string());
tags1.merge(&tags2).ok();
let mut views1 = GCounter::new("device-1".to_string());
let mut views2 = GCounter::new("device-2".to_string());
for _ in 0..5 {
views1.increment(1);
}
for _ in 0..3 {
views2.increment(1);
}
views1.merge(&views2).ok();
assert_eq!(tags1.len(), 4);
assert_eq!(views1.value(), 8);
}
#[test]
fn test_crdt_convergence() {
let mut counters: Vec<GCounter> = (0..5)
.map(|i| GCounter::new(format!("device-{}", i)))
.collect();
for (i, counter) in counters.iter_mut().enumerate() {
for _ in 0..(i + 1) * 10 {
counter.increment(1);
}
}
let mut final_values = Vec::new();
for i in 0..5 {
let mut merged = counters[i].clone();
for (j, counter) in counters.iter().enumerate().take(5) {
if i != j {
merged.merge(counter).ok();
}
}
final_values.push(merged.value());
}
let expected = 10 + 20 + 30 + 40 + 50; for value in final_values {
assert_eq!(value, expected);
}
}
#[test]
fn test_crdt_idempotence() {
let mut counter1 = GCounter::new("device-1".to_string());
let mut counter2 = GCounter::new("device-2".to_string());
counter1.increment(10);
counter2.increment(20);
counter1.merge(&counter2).ok();
let value1 = counter1.value();
counter1.merge(&counter2).ok();
let value2 = counter1.value();
assert_eq!(value1, value2);
}
#[test]
fn test_crdt_commutativity() {
let mut counter1a = GCounter::new("device-1".to_string());
let mut counter1b = GCounter::new("device-1".to_string());
let counter2 = {
let mut c = GCounter::new("device-2".to_string());
c.increment(10);
c
};
let counter3 = {
let mut c = GCounter::new("device-3".to_string());
c.increment(20);
c
};
counter1a.merge(&counter2).ok();
counter1a.merge(&counter3).ok();
counter1b.merge(&counter3).ok();
counter1b.merge(&counter2).ok();
assert_eq!(counter1a.value(), counter1b.value());
}
#[test]
fn test_or_set_element_resurrection() {
let mut set1 = OrSet::new("device-1".to_string());
let mut set2 = OrSet::new("device-2".to_string());
set1.insert("item".to_string());
set2.insert("item".to_string());
set1.remove(&"item".to_string());
let mut set3 = set2.clone();
set3.insert("item".to_string());
set1.merge(&set3).ok();
assert!(set1.contains(&"item".to_string()));
}
}