mod util; use proptest::prelude::*; use rayon::prelude::*; use otvec::Operation; use util::{print_cond_catch_ctr, test_transform_cond, test_transform_cond_catch, CondCatchCtr}; const ALL_SIZE: usize = 20; const MIN_RANGE_LEN: usize = 1; const TEST_SIZE: usize = 9; const TEST_MIN_RANGE_LEN: usize = 1; const VEC_SIZE: usize = 100; fn testvec(len: usize) -> Vec { (0..len).collect::>() } fn t_ins_ins(size: usize, a_pos: usize, a_len: usize, b_pos: usize, b_len: usize) { let input = testvec(size); let a = Operation::Ins { pos: a_pos, val: testvec(a_len), }; let b = Operation::Ins { pos: b_pos, val: testvec(b_len), }; test_transform_cond(&a, &b, &input); test_transform_cond(&b, &a, &input); } fn t_del_del(size: usize, a_pos: usize, a_len: usize, b_pos: usize, b_len: usize) { let input = testvec(size); let a = Operation::Del { pos: a_pos, n: a_len, }; let b = Operation::Del { pos: b_pos, n: b_len, }; test_transform_cond(&a, &b, &input); test_transform_cond(&b, &a, &input); } fn t_ins_del(size: usize, a_pos: usize, a_len: usize, b_pos: usize, b_len: usize) { let input = testvec(size); let a = Operation::Ins { pos: a_pos, val: testvec(a_len), }; let b = Operation::Del { pos: b_pos, n: b_len, }; test_transform_cond(&a, &b, &input); test_transform_cond(&b, &a, &input); } fn t_mov_ins(size: usize, a_pos: usize, a_len: usize, a_to: usize, b_pos: usize, b_len: usize) { let input = testvec(size); let a = Operation::Mov { pos: a_pos, n: a_len, to: a_to, }; let b = Operation::Ins { pos: b_pos, val: testvec(b_len), }; test_transform_cond(&a, &b, &input); test_transform_cond(&b, &a, &input); } fn t_mov_del(size: usize, a_pos: usize, a_len: usize, a_to: usize, b_pos: usize, b_len: usize) { let input = testvec(size); let a = Operation::Mov { pos: a_pos, n: a_len, to: a_to, }; let b = Operation::Del { pos: b_pos, n: b_len, }; test_transform_cond(&a, &b, &input); test_transform_cond(&b, &a, &input); } fn t_mov_mov_catch( size: usize, a_pos: usize, a_len: usize, a_to: usize, b_pos: usize, b_len: usize, b_to: usize, ctr: Option<&CondCatchCtr>, ) { let input = testvec(size); let a = Operation::Mov { pos: a_pos, n: a_len, to: a_to, }; let b = Operation::Mov { pos: b_pos, n: b_len, to: b_to, }; test_transform_cond_catch(&a, &b, &input, ctr); test_transform_cond_catch(&b, &a, &input, ctr); } fn t_mov_mov( size: usize, a_pos: usize, a_len: usize, a_to: usize, b_pos: usize, b_len: usize, b_to: usize, ) { let input = testvec(size); let a = Operation::Mov { pos: a_pos, n: a_len, to: a_to, }; let b = Operation::Mov { pos: b_pos, n: b_len, to: b_to, }; test_transform_cond(&a, &b, &input); test_transform_cond(&b, &a, &input); } #[test] fn all_ins_ins() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) .into_par_iter() .for_each(|a_len| { (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) .into_par_iter() .for_each(|b_len| { t_ins_ins(ALL_SIZE, a_pos, a_len, b_pos, b_len); }); }); }); }); } #[test] fn all_del_del() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) .into_par_iter() .for_each(|a_len| { (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) .into_par_iter() .for_each(|b_len| { t_del_del(ALL_SIZE, a_pos, a_len, b_pos, b_len); }); }); }); }); } #[test] fn all_ins_del() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) .into_par_iter() .for_each(|a_len| { (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) .into_par_iter() .for_each(|b_len| { t_ins_del(ALL_SIZE, a_pos, a_len, b_pos, b_len); }); }); }); }); } #[test] fn all_mov_ins() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) .into_par_iter() .for_each(|a_len| { (0..a_pos) .into_par_iter() .chain((a_pos + a_len + 1)..=ALL_SIZE) .for_each(|a_to| { (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) .into_par_iter() .for_each(|b_len| { t_mov_ins(ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len); }); }); }); }); }); } #[test] fn all_mov_del() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) .into_par_iter() .for_each(|a_len| { (0..a_pos) .into_par_iter() .chain((a_pos + a_len + 1)..=ALL_SIZE) .for_each(|a_to| { (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) .into_par_iter() .for_each(|b_len| { t_mov_del(ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len); }); }); }); }); }); } // For development (non-parallel and panic-catching) #[test] fn dev_all_mov_mov() { let ctr = CondCatchCtr::default(); (0..TEST_SIZE).into_iter().for_each(|a_pos| { (TEST_MIN_RANGE_LEN..=(TEST_SIZE - a_pos)) .into_iter() // .rev() .for_each(|a_len| { (0..a_pos) .into_iter() .chain((a_pos + a_len + 1)..=TEST_SIZE) .for_each(|a_to| { (0..TEST_SIZE).into_iter().for_each(|b_pos| { (TEST_MIN_RANGE_LEN..=(TEST_SIZE - b_pos)) .into_iter() // .rev() .for_each(|b_len| { (0..b_pos) .into_iter() .chain((b_pos + b_len + 1)..=TEST_SIZE) .for_each(|b_to| { t_mov_mov_catch( TEST_SIZE, a_pos, a_len, a_to, b_pos, b_len, b_to, Some(&ctr), ); }); }); }); }); }); }); print_cond_catch_ctr(&ctr); } #[test] fn all_mov_mov() { (0..ALL_SIZE).into_par_iter().for_each(|a_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - a_pos)) .into_par_iter() .for_each(|a_len| { (0..a_pos) .into_par_iter() .chain((a_pos + a_len + 1)..=ALL_SIZE) .for_each(|a_to| { (0..ALL_SIZE).into_par_iter().for_each(|b_pos| { (MIN_RANGE_LEN..=(ALL_SIZE - b_pos)) .into_par_iter() .for_each(|b_len| { (0..b_pos) .into_par_iter() .chain((b_pos + b_len + 1)..=ALL_SIZE) .for_each(|b_to| { t_mov_mov( ALL_SIZE, a_pos, a_len, a_to, b_pos, b_len, b_to, ); }); }); }); }); }); }); } fn test_params() -> impl Strategy { ((MIN_RANGE_LEN + 1)..=VEC_SIZE) .prop_flat_map(|vec_size| (Just(vec_size), mov_params(vec_size), mov_params(vec_size))) } /// Parameters for a single test operation fn mov_params(vec_size: usize) -> impl Strategy { (0..(vec_size - MIN_RANGE_LEN)) .prop_flat_map(move |pos| (Just(pos), MIN_RANGE_LEN..=(vec_size - pos))) .prop_flat_map(move |(pos, len)| { let rb = (pos + len + 1)..(vec_size + 1); ( Just(pos), Just(len), match (pos > 0, rb.end > rb.start) { (true, true) => Strategy::boxed((0..pos).prop_union(rb)), (true, false) => Strategy::boxed(0..pos), (false, true) => Strategy::boxed(rb), (false, false) => Strategy::boxed(Just(pos)), }, ) }) } proptest! { #[test] fn transform_ins_ins((vec_len, a, b) in test_params(), a_len in 1usize..VEC_SIZE, b_len in 1usize..VEC_SIZE) { t_ins_ins(vec_len, a.0, a_len, b.0, b_len) } #[test] fn transform_del_del((vec_len, a, b) in test_params()) { t_del_del(vec_len, a.0, a.1, b.0, b.1) } #[test] fn transform_ins_del((vec_len, a, b) in test_params(), i_len in 1usize..VEC_SIZE) { t_ins_del(vec_len, a.0, i_len, b.0, b.1) } #[test] fn transform_mov_ins((vec_len, a, b) in test_params(), i_len in 1usize..VEC_SIZE) { t_mov_ins(vec_len, a.0, a.1, a.2, b.0, i_len) } #[test] fn transform_mov_del((vec_len, a, b) in test_params()) { t_mov_del(vec_len, a.0, a.1, a.2, b.0, b.1) } #[test] fn transform_mov_mov((vec_len, a, b) in test_params()) { t_mov_mov(vec_len, a.0, a.1, a.2, b.0, b.1, b.2); } #[test] fn transform_seq((vec_len, a, b, a2, b2, a3, b3) in test_params().prop_flat_map(|(vec_len, a, b)| (Just(vec_len), Just(a), Just(b), mov_params(vec_len), mov_params(vec_len), mov_params(vec_len), mov_params(vec_len))) ) { let input = testvec(vec_len); let a = Operation::Seq { ops: vec![ Operation::Mov { pos: a.0, n: a.1, to: a.2, }, Operation::Ins { pos: a2.0, val: testvec(a3.1) }, Operation::Del { pos: a3.0, n: a3.1 }, ] }; let b = Operation::Seq { ops: vec![ Operation::Mov { pos: b.0, n: b.1, to: b.2, }, Operation::Ins { pos: b2.0, val: testvec(b3.1) }, Operation::Del { pos: b3.0, n: b3.1 }, ] }; test_transform_cond(&a, &b, &input); test_transform_cond(&b, &a, &input); } }