otvec/tests/util/mod.rs
2024-09-13 20:47:52 +02:00

159 lines
4.2 KiB
Rust

#![allow(dead_code)]
use std::{
fmt::{Debug, Display},
sync::atomic::AtomicUsize,
};
use otvec::{transform, Operation};
pub fn test_transform<T: PartialEq + Clone + Debug + Display>(
a: &Operation<T>,
b: &Operation<T>,
input: &[T],
expect: &[T],
) {
// Print operations
println!("A/B:");
a.print_on(input);
b.print_on(input);
let (mut a2, mut b2) = (a.clone(), b.clone());
transform(&mut a2, &mut b2);
dbg!(&a2, &b2);
check_op(&a2, a, b);
check_op(&b2, a, b);
let mut data = input.to_vec();
a.clone().apply(&mut data);
b2.apply(&mut data);
let mut data2 = input.to_vec();
b.clone().apply(&mut data2);
a2.apply(&mut data2);
assert_eq!(data, data2, "OT condition unfulfilled");
assert_eq!(data, expect, "a, b2");
assert_eq!(data2, expect, "b, a2");
}
#[derive(Default)]
pub struct CondCatchCtr {
total: AtomicUsize,
ok: AtomicUsize,
}
pub fn test_transform_cond_catch<
T: PartialEq + Clone + Debug + Display + std::panic::RefUnwindSafe,
>(
a: &Operation<T>,
b: &Operation<T>,
input: &[T],
ctr: Option<&CondCatchCtr>,
) {
let do_count = !a.is_empty() && !b.is_empty();
if do_count {
if let Some(ctr) = ctr {
ctr.total.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
}
let res = std::panic::catch_unwind(|| {
let (mut a2, mut b2) = (a.clone(), b.clone());
transform(&mut a2, &mut b2);
(a2, b2)
});
if let Ok((a2, b2)) = res {
// check_op(&a2, a, b);
// check_op(&b2, a, b);
let mut data = input.to_vec();
a.clone().apply(&mut data);
b2.apply(&mut data);
let mut data2 = input.to_vec();
b.clone().apply(&mut data2);
a2.apply(&mut data2);
if data != data2 {
// Print operations
println!("A/B: Operation::{a:?}, Operation::{b:?}");
a.print_on(input);
b.print_on(input);
if let Some(ctr) = ctr {
let total = ctr.total.load(std::sync::atomic::Ordering::Relaxed);
let success = ctr.ok.load(std::sync::atomic::Ordering::Relaxed);
let perc = (success as f64 / total as f64) * 100.0;
println!("Cases passed: {success}/{total} ({perc:0.2}%)");
}
panic!("OT condition unfulfilled");
}
if do_count {
if let Some(ctr) = ctr {
ctr.ok.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
}
}
}
pub fn print_cond_catch_ctr(ctr: &CondCatchCtr) {
let total = ctr.total.load(std::sync::atomic::Ordering::Relaxed);
let success = ctr.ok.load(std::sync::atomic::Ordering::Relaxed);
let perc = (success as f64 / total as f64) * 100.0;
if success < total {
panic!("❌ Cases passed: {success}/{total} ({perc:0.2}%)");
} else {
println!("✅ Cases passed: {success}/{total} ({perc:0.2}%)");
}
}
pub fn test_transform_sym<T: PartialEq + Clone + Debug + Display>(
a: &Operation<T>,
b: &Operation<T>,
input: &[T],
expect: &[T],
) {
test_transform(a, b, input, expect);
test_transform(b, a, input, expect);
}
pub fn test_transform_cond<T: PartialEq + Clone + Debug>(
a: &Operation<T>,
b: &Operation<T>,
input: &[T],
) {
let (mut a2, mut b2) = (a.clone(), b.clone());
transform(&mut a2, &mut b2);
// dbg!(&a2, &b2);
check_op(&a2, a, b);
check_op(&b2, a, b);
let mut data = input.to_vec();
a.clone().apply(&mut data);
b2.apply(&mut data);
let mut data2 = input.to_vec();
b.clone().apply(&mut data2);
a2.apply(&mut data2);
assert_eq!(data, data2, "ops:\nA: {a:?}\nB: {b:?}");
}
fn check_op<T: Debug>(op: &Operation<T>, a: &Operation<T>, b: &Operation<T>) {
match op {
Operation::Nop => {}
Operation::Ins { val, .. } => {
assert!(val.len() > 0, "empty op: {op:?}\nfrom: {a:?}; {b:?}")
}
Operation::Del { n, .. } => assert!(*n > 0, "empty op: {op:?}\nfrom: {a:?}; {b:?}"),
Operation::Mov { pos, n, to } => {
assert!(pos != to && *n > 0, "empty op: {op:?}\nfrom: {a:?}; {b:?}")
}
Operation::Seq { ops } => ops.iter().for_each(|op| check_op(op, a, b)),
}
}