use super::*;
#[cfg(test)]
mod unit_tests {
use core::u64;
use super::*;
#[test]
fn test_minkowski_add_basic() {
let a = U64CO::try_new(1, 5).unwrap();
let b = U64CO::try_new(2, 4).unwrap();
let res = a.checked_minkowski_add(b).unwrap();
assert_eq!(res.start(), 3);
assert_eq!(res.end_excl(), 8);
}
#[test]
fn test_minkowski_sub_basic() {
let a = U64CO::try_new(5, 10).unwrap();
let b = U64CO::try_new(2, 4).unwrap();
let res = a.checked_minkowski_sub(b).unwrap();
assert_eq!(res.start(), 2); assert_eq!(res.end_excl(), 8); }
#[test]
fn test_minkowski_mul_basic() {
let a = U64CO::try_new(1, 4).unwrap(); let b = U64CO::try_new(2, 3).unwrap(); let res = a.checked_minkowski_mul_hull(b).unwrap();
assert_eq!(res.start(), 2); assert_eq!(res.end_excl(), 7); }
#[test]
fn test_minkowski_div_basic() {
let a = U64CO::try_new(4, 10).unwrap();
let b = U64CO::try_new(2, 5).unwrap();
let res = a.checked_minkowski_div_hull(b).unwrap();
assert_eq!(res.start(), 1); assert_eq!(res.end_excl(), 5); }
#[test]
fn test_minkowski_div_by_zero() {
let a = U64CO::try_new(1, 5).unwrap();
let b = U64CO::try_new(0, 3).unwrap();
assert!(a.checked_minkowski_div_hull(b).is_none());
}
#[test]
fn test_minkowski_overflow() {
let a = U64CO::try_new(250, u64::MAX).unwrap();
let b = U64CO::try_new(10, 20).unwrap();
assert!(a.checked_minkowski_add(b).is_none());
assert!(a.checked_minkowski_mul_hull(b).is_none());
}
}
#[cfg(test)]
mod prop_tests {
use super::*;
use proptest::prelude::*;
fn interval_strategy() -> impl Strategy<Value = U64CO> {
prop_oneof![
Just(U64CO::try_new(u64::MIN, u64::MIN + 1).unwrap()), Just(U64CO::try_new(u64::MIN, u64::MAX).unwrap()), Just(U64CO::try_new(u64::MAX - 1, u64::MAX).unwrap()), (u64::MIN..=u64::MAX, u64::MIN..=u64::MAX)
.prop_filter_map("valid interval", |(s, e)| U64CO::try_new(s, e))
]
}
#[inline]
fn endpoints(x: U64CO) -> [u64; 2] {
[x.start(), x.end_incl()]
}
proptest! {
#[test]
fn prop_checked_add_semantics(a in interval_strategy(), b in interval_strategy()) {
let got = a.checked_minkowski_add(b);
let expect_none =
a.start().checked_add(b.start()).is_none()
|| a.end_excl().checked_add(b.end_incl()).is_none();
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), a.start() + b.start());
prop_assert_eq!(c.end_incl(), a.end_incl() + b.end_incl());
for &x in &endpoints(a) {
for &y in &endpoints(b) {
let z = x.checked_add(y).unwrap();
prop_assert!(c.contains(z));
}
}
}
}
#[test]
fn prop_checked_sub_semantics(a in interval_strategy(), b in interval_strategy()) {
let got = a.checked_minkowski_sub(b);
let expect_none =
a.start().checked_sub(b.end_incl()).is_none()
|| a.end_excl().checked_sub(b.start()).is_none();
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), a.start() - b.end_incl());
prop_assert_eq!(c.end_incl(), a.end_incl() - b.start());
for &x in &endpoints(a) {
for &y in &endpoints(b) {
let Some(z) = x.checked_sub(y) else {
continue;
};
prop_assert!(c.contains(z));
}
}
}
}
#[test]
fn prop_checked_mul_semantics(a in interval_strategy(), b in interval_strategy()) {
let got = a.checked_minkowski_mul_hull(b);
let expect_none =
a.start().checked_mul(b.start()).is_none()
|| a.end_incl().checked_mul(b.end_incl()).is_none()
|| a.end_incl()
.checked_mul(b.end_incl())
.and_then(|x| x.checked_add(1))
.is_none();
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), a.start() * b.start());
prop_assert_eq!(c.end_incl(), a.end_incl() * b.end_incl());
for &x in &endpoints(a) {
for &y in &endpoints(b) {
let Some(z) = x.checked_mul(y) else {
continue;
};
prop_assert!(c.contains(z));
}
}
}
}
#[test]
fn prop_checked_div_semantics(
a in interval_strategy(),
b in interval_strategy().prop_filter("non-zero start", |b| b.start() != 0)
) {
let got = a.checked_minkowski_div_hull(b);
prop_assert!(got.is_some());
let c = got.unwrap();
prop_assert_eq!(c.start(), a.start() / b.end_incl());
prop_assert_eq!(c.end_incl(), a.end_incl() / b.start());
for &x in &endpoints(a) {
for &y in &endpoints(b) {
let z = x / y;
prop_assert!(c.contains(z));
}
}
}
#[test]
fn prop_add_commutative(a in interval_strategy(), b in interval_strategy()) {
prop_assert_eq!(a.checked_minkowski_add(b), b.checked_minkowski_add(a));
}
#[test]
fn prop_mul_commutative(a in interval_strategy(), b in interval_strategy()) {
prop_assert_eq!(a.checked_minkowski_mul_hull(b), b.checked_minkowski_mul_hull(a));
}
}
}