use super::*;
mod prop_tests {
use super::*;
use proptest::prelude::*;
#[cfg(test)]
mod construction {
use super::*;
prop_compose! {
fn point_strategy()(
x in prop_oneof![
Just(i16::MIN),
Just(i16::MIN.saturating_add(1)),
Just(0i16),
Just(1i16),
Just(2i16),
Just(i16::MAX.saturating_sub(2)),
Just(i16::MAX.saturating_sub(1)),
Just(i16::MAX),
any::<i16>(),
]
) -> i16 {
x
}
}
prop_compose! {
fn interval_strategy()(
a in point_strategy(),
b in point_strategy(),
) -> I16CO {
let start = a.min(b);
let end_excl = a.max(b).saturating_add(1);
if let Some(iv) = I16CO::try_new(start, end_excl) {
iv
} else {
I16CO::try_new(i16::MAX - 1, i16::MAX).unwrap()
}
}
}
fn intervals_strategy() -> impl Strategy<Value = Vec<I16CO>> {
prop::collection::vec(interval_strategy(), 0..48)
}
fn probe_points_strategy() -> impl Strategy<Value = Vec<i16>> {
prop::collection::vec(point_strategy(), 0..96)
}
prop_compose! {
fn interval_array_8_strategy()(
xs in prop::array::uniform8(interval_strategy())
) -> [I16CO; 8] {
xs
}
}
#[inline]
fn raw_contains_point(raw: &[I16CO], x: i16) -> bool {
raw.iter().any(|iv| iv.contains(x))
}
#[inline]
fn is_strictly_normalized(xs: &[I16CO]) -> bool {
xs.windows(2).all(|w| {
let a = w[0];
let b = w[1];
a.start() < b.start() && !a.is_contiguous_with(b)
})
}
#[inline]
fn sum_len(xs: &[I16CO]) -> u16 {
xs.iter().fold(0u16, |acc, iv| acc.saturating_add(iv.len()))
}
fn enrich_probes(raw: &[I16CO], extra: &[i16]) -> Vec<i16> {
#[inline]
fn midpoint_i16(a: i16, b: i16) -> i16 {
(a & b) + ((a ^ b) >> 1)
}
let mut out = Vec::with_capacity(extra.len() + raw.len() * 6 + 6);
out.push(i16::MIN);
out.push(i16::MIN.saturating_add(1));
out.push(0);
out.push(1);
out.push(i16::MAX.saturating_sub(1));
out.push(i16::MAX);
out.extend_from_slice(extra);
for &iv in raw {
let s = iv.start();
let e = iv.end_excl();
let ei = iv.end_incl();
out.push(s);
out.push(ei);
out.push(e);
out.push(s.saturating_sub(1));
out.push(ei.saturating_add(1));
out.push(midpoint_i16(s, ei));
}
out.sort_unstable();
out.dedup();
out
}
#[test]
fn empty_input_builds_empty_set() {
let set = I16COBatchSet::default();
assert!(set.as_slice().is_empty());
assert_eq!(set.interval_count(), 0);
assert_eq!(set.point_count(), 0);
let set = I16COBatchSet::from(Vec::<I16CO>::new());
assert!(set.as_slice().is_empty());
assert_eq!(set.interval_count(), 0);
assert_eq!(set.point_count(), 0);
let set: I16COBatchSet = core::iter::empty::<I16CO>().collect();
assert!(set.as_slice().is_empty());
assert_eq!(set.interval_count(), 0);
assert_eq!(set.point_count(), 0);
}
proptest! {
#[test]
fn prop_vec_constructor_normalizes_structure_and_preserves_point_membership(
raw in intervals_strategy(),
extra_probes in probe_points_strategy(),
) {
let set = I16COBatchSet::from(raw.clone());
prop_assert!(is_strictly_normalized(set.as_slice()));
let probes = enrich_probes(&raw, &extra_probes);
for x in probes {
prop_assert_eq!(
set.contains_point(x),
raw_contains_point(&raw, x),
"membership mismatch at point {:?}, raw={:?}, set={:?}",
x,
raw,
set,
);
}
}
#[test]
fn prop_vec_constructor_is_order_invariant(
raw in intervals_strategy(),
) {
let mut sorted = raw.clone();
sorted.sort_unstable_by(|a, b| {
a.start()
.cmp(&b.start())
.then(a.end_excl().cmp(&b.end_excl()))
});
let a = I16COBatchSet::from(raw);
let b = I16COBatchSet::from(sorted);
prop_assert_eq!(a, b);
}
#[test]
fn prop_interval_count_matches_internal_slice_len(
raw in intervals_strategy(),
) {
let set = I16COBatchSet::from(raw);
prop_assert_eq!(set.interval_count(), set.as_slice().len() as i16);
}
#[test]
fn prop_point_count_matches_sum_of_normalized_interval_lengths(
raw in intervals_strategy(),
) {
let set = I16COBatchSet::from(raw);
prop_assert_eq!(set.point_count(), sum_len(set.as_slice()));
}
#[test]
fn prop_from_iter_matches_vec_constructor(
raw in intervals_strategy(),
) {
let a = I16COBatchSet::from(raw.clone());
let b: I16COBatchSet = raw.into_iter().collect();
prop_assert_eq!(a, b);
}
#[test]
fn prop_array_constructor_matches_vec_constructor(
raw in interval_array_8_strategy(),
) {
let a = I16COBatchSet::from(raw);
let b = I16COBatchSet::from(Vec::from(raw));
prop_assert_eq!(a, b);
}
}
}
}