use super::*;
mod unit_tests {
use super::*;
fn span(lo: u64, hi: u64) -> U64CO {
U64CO::try_new(lo, hi).unwrap()
}
#[test]
fn disjoint() {
let a = span(1, 3);
let b = span(5, 7);
assert_eq!(a.convex_hull(b), span(1, 7));
}
#[test]
fn overlap() {
let a = span(2, 6);
let b = span(4, 9);
assert_eq!(a.convex_hull(b), span(2, 9));
}
#[test]
fn containment() {
let a = span(2, 10);
let b = span(4, 6);
assert_eq!(a.convex_hull(b), a);
}
#[test]
fn symmetric_case() {
let a = span(4, 6);
let b = span(2, 10);
assert_eq!(a.convex_hull(b), b);
}
}
mod prop_tests {
use std::{vec, vec::Vec};
use super::*;
use proptest::prelude::*;
fn span(a: u64, b: u64) -> Option<U64CO> {
let lo = a.min(b);
let hi = a.max(b);
U64CO::try_new(lo, hi)
}
fn edge_values() -> Vec<u64> {
let mut v = vec![u64::MIN, u64::MAX, 0, 1];
if u64::MIN < u64::MAX {
v.push(u64::MIN.saturating_add(1));
v.push(u64::MAX.saturating_sub(1));
}
v.sort_unstable();
v.dedup();
v
}
fn edge_scalar() -> impl Strategy<Value = u64> {
prop::sample::select(edge_values())
}
fn mixed_scalar() -> impl Strategy<Value = u64> {
prop_oneof! {
3 => edge_scalar(),
7 => any::<u64>(),
}
}
fn span_strategy() -> impl Strategy<Value = U64CO> {
(mixed_scalar(), mixed_scalar()).prop_filter_map("non-empty interval", |(a, b)| span(a, b))
}
proptest! {
#![proptest_config(ProptestConfig {
cases: 64,
.. ProptestConfig::default()
})]
#[test]
fn hull_contains_inputs(
x in span_strategy(),
y in span_strategy(),
p in mixed_scalar(),
q in mixed_scalar(),
) {
let h = x.convex_hull(y);
if x.contains(p) {
prop_assert!(h.contains(p));
}
if y.contains(q) {
prop_assert!(h.contains(q));
}
}
#[test]
fn hull_bounds_correct(
x in span_strategy(),
y in span_strategy(),
) {
let h = x.convex_hull(y);
prop_assert_eq!(
h,
U64CO::try_new(
x.start().min(y.start()),
x.end_excl().max(y.end_excl())
).unwrap()
);
}
#[test]
fn commutative(
x in span_strategy(),
y in span_strategy(),
) {
prop_assert_eq!(x.convex_hull(y), y.convex_hull(x));
}
#[test]
fn idempotent(
x in span_strategy(),
) {
prop_assert_eq!(x.convex_hull(x), x);
}
#[test]
fn hull_contains_interval_bounds(
x in span_strategy(),
y in span_strategy(),
) {
let h = x.convex_hull(y);
prop_assert!(h.start() <= x.start());
prop_assert!(h.start() <= y.start());
prop_assert!(h.end_excl() >= x.end_excl());
prop_assert!(h.end_excl() >= y.end_excl());
}
}
}