use crate::Diff;
use proptest::prelude::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Replacement {
old: usize,
old_len: usize,
new: usize,
new_len: usize,
}
#[derive(Debug)]
struct AccumDiff(Vec<Replacement>);
impl Diff for AccumDiff {
type Error = ();
fn delete(&mut self, old: usize, len: usize, new: usize) -> Result<(), ()> {
Ok(self.0.push(Replacement {
old,
old_len: len,
new,
new_len: 0,
}))
}
fn insert(&mut self, old: usize, new: usize, new_len: usize) -> Result<(), ()> {
Ok(self.0.push(Replacement {
old,
old_len: 0,
new,
new_len,
}))
}
fn replace(
&mut self,
old: usize,
old_len: usize,
new: usize,
new_len: usize,
) -> Result<(), ()> {
Ok(self.0.push(Replacement {
old,
old_len,
new,
new_len,
}))
}
}
impl AccumDiff {
pub fn replay_rev<D: Diff>(&self, d: &mut D) -> Result<(), D::Error> {
for &Replacement {
old,
old_len,
new,
new_len,
} in self.0.iter().rev()
{
d.replace(old, old_len, new, new_len)?;
}
Ok(())
}
}
#[derive(Debug)]
struct ApplyDiff(Vec<u8>, Vec<u8>);
impl Diff for ApplyDiff {
type Error = ();
fn replace(
&mut self,
old: usize,
old_len: usize,
new: usize,
new_len: usize,
) -> Result<(), ()> {
let mut v = self.0[..old].to_vec();
v.extend_from_slice(&self.1[new..new + new_len]);
v.extend_from_slice(&self.0[old + old_len..]);
self.0 = v;
Ok(())
}
}
prop_compose! {
fn vec_and_range()(vec in prop::collection::vec(1u8..10, 2..100))
(ix1 in 0..vec.len()-1, ix2 in 0..vec.len(), vec in Just(vec))
-> (Vec<u8>, usize, usize) {
(vec, ix1.min(ix2), ix1.max(ix2)+1)
}
}
proptest! {
#[test]
fn myers_proptest((v, i1, i2) in vec_and_range(), (w, j1, j2) in vec_and_range()) {
let mut accum = AccumDiff(Vec::new());
let mut apply = ApplyDiff(v.to_vec(), w.to_vec());
crate::myers::diff(&mut accum, &v, i1, i2, &w, j1, j2).unwrap();
accum.replay_rev(&mut apply).unwrap();
assert_eq!(apply.0[i1..i1+j2-j1], apply.1[j1..j2]);
}
#[test]
fn optimized_proptest((v, i1, i2) in vec_and_range(), (w, j1, j2) in vec_and_range()) {
let mut accum = AccumDiff(Vec::new());
let mut apply = ApplyDiff(v.to_vec(), w.to_vec());
crate::optimized::diff(&mut accum, &v, i1, i2, &w, j1, j2).unwrap();
accum.replay_rev(&mut apply).unwrap();
assert_eq!(apply.0[i1..i1+j2-j1], apply.1[j1..j2]);
}
#[test]
fn patience_proptest((v, i1, i2) in vec_and_range(), (w, j1, j2) in vec_and_range()) {
let mut accum = AccumDiff(Vec::new());
let mut apply = ApplyDiff(v.to_vec(), w.to_vec());
crate::patience::diff(&mut accum, &v, i1, i2, &w, j1, j2).unwrap();
accum.replay_rev(&mut apply).unwrap();
assert_eq!(apply.0[i1..i1+j2-j1], apply.1[j1..j2]);
}
#[test]
fn replace_proptest((v, i1, i2) in vec_and_range(), (w, j1, j2) in vec_and_range()) {
let accum = AccumDiff(Vec::new());
let mut apply = ApplyDiff(v.to_vec(), w.to_vec());
let mut replace = crate::replace::Replace::new(accum);
crate::myers::diff(&mut replace, &v, i1, i2, &w, j1, j2).unwrap();
replace.as_ref().replay_rev(&mut apply).unwrap();
assert_eq!(apply.0[i1..i1+j2-j1], apply.1[j1..j2]);
}
}