389 lines
12 KiB
Rust
389 lines
12 KiB
Rust
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<usize> {
|
|
(0..len).collect::<Vec<_>>()
|
|
}
|
|
|
|
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<Value = (usize, (usize, usize, usize), (usize, usize, usize))> {
|
|
((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<Value = (usize, usize, usize)> {
|
|
(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);
|
|
}
|
|
}
|