use super::*;
use proptest::prelude::*;
proptest!{
#[test] fn test_write_write(
a in ".*",
b in ".*",
) {
let mvcc = Mvcc::new();
let slot:MvccCell<String> = MvccCell::new(&mvcc, Default::default());
let mut t1 = mvcc.begin();
let mut t2 = mvcc.begin();
assert_eq!(t1[&slot], "");
assert_eq!(t2[&slot], "");
t1[&slot] = a.clone();
assert_eq!(&t1[&slot], &a);
assert_eq!(&t2[&slot], "");
t2[&slot] = b.clone();
assert_eq!(&t1[&slot], &a);
assert_eq!(&t2[&slot], &b);
assert!(t1.try_commit().is_ok());
assert_eq!(&mvcc.begin()[&slot], &a);
assert_eq!(&t2[&slot], &b);
let t2 = t2.try_commit().unwrap_err();
assert_eq!(&mvcc.begin()[&slot], &a);
assert_eq!(&t2[&slot], &b);
let mut t3 = mvcc.begin();
t3[&slot] = t2[&slot].clone();
assert_eq!(&t3[&slot], &b);
assert!(t3.try_commit().is_ok());
assert_eq!(&mvcc.begin()[&slot], &b);
}
#[test] fn test_disjoint_cells(
a in ".*",
b in ".*",
) {
let mvcc = Mvcc::new();
let slot1:MvccCell<String> = MvccCell::new(&mvcc, Default::default());
let slot2:MvccCell<String> = MvccCell::new(&mvcc, Default::default());
let mut t1 = mvcc.begin();
let mut t2 = mvcc.begin();
assert_eq!(&t1[&slot1], "");
assert_eq!(&t2[&slot2], "");
t1[&slot1] = a.clone();
t2[&slot2] = b.clone();
assert_eq!(&t1[&slot1], &a);
assert_eq!(&t2[&slot2], &b);
assert_eq!(&mvcc.begin()[&slot1], "");
assert_eq!(&mvcc.begin()[&slot2], "");
assert!(t1.try_commit().is_ok());
assert_eq!(&t2[&slot2], &b);
assert_eq!(&mvcc.begin()[&slot1], &a);
assert_eq!(&mvcc.begin()[&slot2], "");
assert!(t2.try_commit().is_ok());
assert_eq!(&mvcc.begin()[&slot1], &a);
assert_eq!(&mvcc.begin()[&slot2], &b);
}
#[test] fn test_read_write(
a in ".*",
) {
let mvcc = Mvcc::new();
let slot:MvccCell<String> = MvccCell::new(&mvcc, Default::default());
let mut t1 = mvcc.begin();
let t2 = mvcc.begin();
assert_eq!(t1[&slot], "");
assert_eq!(t2[&slot], "");
t1[&slot] = a.clone();
assert_eq!(&t1[&slot], &a);
assert_eq!(&t2[&slot], "");
assert!(t2.try_commit().is_ok());
assert!(t1.try_commit().is_ok());
}
#[test] fn test_write_read(
a in ".*",
) {
let mvcc = Mvcc::new();
let slot:MvccCell<String> = MvccCell::new(&mvcc, Default::default());
let mut t1 = mvcc.begin();
let t2 = mvcc.begin();
assert_eq!(t1[&slot], "");
assert_eq!(t2[&slot], "");
t1[&slot] = a.clone();
assert_eq!(&t1[&slot], &a);
assert_eq!(&t2[&slot], "");
assert!(t1.try_commit().is_ok());
assert!(t2.try_commit().is_err());
}
}
#[derive(Debug,Copy,Clone)]
enum Fuzzer {
Read(usize),
Write(usize,u32),
Vac(usize),
}
impl Fuzzer {
fn strategy(slots: impl Clone + Strategy<Value=usize>)->impl Strategy<Value=Self> {
prop_oneof![
slots.clone().prop_map(Self::Read),
(slots.clone(), any::<u32>()).prop_map(|(slot,val)| Self::Write(slot, val)),
slots.clone().prop_map(Self::Vac),
]
}
}
proptest! {
#[test] fn fuzz_vacuum(ops in prop::collection::vec(Fuzzer::strategy(0_usize..4), 0..1024)) {
use Fuzzer::*;
let mvcc = Mvcc::new();
let slots = vec![
MvccCell::new(&mvcc, Box::new(0)),
MvccCell::new(&mvcc, Box::new(0)),
MvccCell::new(&mvcc, Box::new(0)),
MvccCell::new(&mvcc, Box::new(0)),
];
let mut reads = vec![];
for op in ops {
let mut txn = mvcc.begin();
match op {
Write(i, val) => {
txn[&slots[i]] = val;
assert!(txn.try_commit().is_ok());
}
Read(i) => {
reads.push((i, txn[&slots[i]], txn));
}
Vac(i) => {
let v = Vacuum::new(&mvcc);
v.clean(&slots[i]);
}
}
}
for &(i, val, ref txn) in &reads {
assert_eq!(txn[&slots[i]], val);
}
}
}