use quickcheck_macros::quickcheck;
use std::io::Cursor;
use crate::{apply, diff, Signature, SignatureOptions};
#[quickcheck]
fn test_signature_creation(data: Vec<u8>, block_size: u32, crypto_hash_size: u32) {
let mut storage = Vec::new();
let signature = Signature::calculate(
&data,
&mut storage,
SignatureOptions {
block_size: block_size.saturating_add(1),
crypto_hash_size: crypto_hash_size % 16,
},
);
let mut serialized = Vec::new();
signature.serialize(&mut serialized);
let deserialized = Signature::deserialize(&serialized).expect("deserialization error");
assert_eq!(signature, deserialized);
}
#[test]
fn test_trivial() {
let data = vec![0; 100000];
let mut storage = Vec::new();
let signature = Signature::calculate(
&data,
&mut storage,
SignatureOptions {
block_size: 64,
crypto_hash_size: 5,
},
);
let indexed = signature.index();
let mut patch = vec![];
diff(&indexed, &data, &mut patch).expect("diff error");
let mut out = vec![];
assert!(patch.len() < 10000);
apply(&data, &patch, &mut out).expect("apply error");
assert_eq!(data, out);
}
#[test]
fn test_delta_size() {
let mut data1 = b"hello".to_vec();
let mut data2 = b"goodbye".to_vec();
data1.resize(1 << 20, 0);
data2.resize(1 << 20, 0);
let mut storage = Vec::new();
let signature = Signature::calculate(
&data1,
&mut storage,
SignatureOptions {
block_size: 4096,
crypto_hash_size: 8,
},
);
let mut patch = vec![];
diff(&signature.index(), &data2, &mut patch).expect("diff error");
let mut out = vec![];
assert!(patch.len() < 10000);
apply(&data1, &patch, &mut out).expect("apply error");
assert_eq!(data2, out);
}
#[test]
fn test_random() {
use rand::Rng;
let mut base = vec![0; 100000];
rand::thread_rng().fill(&mut base[..]);
let mut data = vec![0; 100000];
rand::thread_rng().fill(&mut data[..]);
let mut storage = Vec::new();
let signature = Signature::calculate(
&base,
&mut storage,
SignatureOptions {
block_size: 4,
crypto_hash_size: 8,
},
);
let indexed = signature.index();
let mut patch = vec![];
diff(&indexed, &data, &mut patch).expect("diff error");
let mut out = vec![];
apply(&base, &patch, &mut out).expect("apply error");
assert_eq!(data, out);
let mut serialized_signature = vec![];
signature.serialize(&mut serialized_signature);
let mut librsync_patch = vec![];
librsync::whole::delta(
&mut &data[..],
&mut &serialized_signature[..],
&mut librsync_patch,
)
.unwrap();
out.clear();
apply(&base, &librsync_patch, &mut out).expect("apply error");
assert_eq!(data, out);
out.clear();
librsync::whole::patch(&mut Cursor::new(&base[..]), &mut &patch[..], &mut out).unwrap();
assert_eq!(data, out);
}
#[test]
fn test_signature_interoperability() {
use rand::Rng;
for &block_len in &[10, 1024] {
for &strong_len in &[1, 8, 16] {
for &len in &[0, 1, 2, 10, 128, 500, 1111, 2000, 2048] {
let mut data = vec![0; len];
rand::thread_rng().fill(&mut data[..]);
let mut librsync_out = vec![];
librsync::whole::signature_with_options(
&mut &data[..],
&mut librsync_out,
block_len,
strong_len,
librsync::SignatureType::MD4,
)
.unwrap();
let mut storage = Vec::new();
let signature = Signature::calculate(
&data,
&mut storage,
SignatureOptions {
block_size: block_len as u32,
crypto_hash_size: strong_len as u32,
},
);
let mut serialized = Vec::new();
signature.serialize(&mut serialized);
assert_eq!(
librsync_out, serialized,
"block_len={}, strong_len={}, len={}",
block_len, strong_len, len
);
}
}
}
}
#[test]
fn test_apply_errors() {
let base_data = b"potato";
apply(base_data, &[114, 115, 2, 54, 0], &mut Vec::new()).unwrap();
assert_eq!(
apply(base_data, &[], &mut Vec::new())
.unwrap_err()
.to_string(),
"unexpected end of input when reading magic (expected=4, available=0)",
);
assert_eq!(
apply(base_data, &[1, 2, 3, 4], &mut Vec::new())
.unwrap_err()
.to_string(),
"incorrect magic: 0x01020304",
);
assert_eq!(
apply(
base_data,
&[114, 115, 2, 54, crate::consts::RS_OP_COPY_N1_N1, 0, 0, 0],
&mut Vec::new(),
)
.unwrap_err()
.to_string(),
"copy length is empty",
);
assert_eq!(
apply(
base_data,
&[114, 115, 2, 54, crate::consts::RS_OP_COPY_N1_N1, 10, 1, 0],
&mut Vec::new(),
)
.unwrap_err()
.to_string(),
"requested copy is out of bounds (offset=10, len=1, data_len=6)",
);
assert_eq!(
apply(
base_data,
&[114, 115, 2, 54, crate::consts::RS_OP_COPY_N1_N1, 0, 10, 0],
&mut Vec::new(),
)
.unwrap_err()
.to_string(),
"requested copy is out of bounds (offset=0, len=10, data_len=6)",
);
assert_eq!(
apply(
base_data,
&[114, 115, 2, 54, crate::consts::RS_OP_COPY_N1_N1, 0, 10, 0],
&mut Vec::new(),
)
.unwrap_err()
.to_string(),
"requested copy is out of bounds (offset=0, len=10, data_len=6)",
);
assert_eq!(
apply(base_data, &[114, 115, 2, 54, 0x55], &mut Vec::new(),)
.unwrap_err()
.to_string(),
"unexpected command byte: 0x55",
);
assert_eq!(
apply(base_data, &[114, 115, 2, 54, 0, 1], &mut Vec::new(),)
.unwrap_err()
.to_string(),
"unexpected data after end command (len=1)",
);
}