159 lines
4.2 KiB
Rust
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)),
|
|
}
|
|
}
|