use super::*;
#[cfg(test)]
mod unit_tests {
use core::u16;
use super::*;
#[test]
fn test_saturating_minkowski_add_basic() {
let a = U16CO::try_new(1, 5).unwrap();
let b = U16CO::try_new(2, 4).unwrap();
let res = a.saturating_minkowski_add(b).unwrap();
assert_eq!(res.start(), 3);
assert_eq!(res.end_excl(), 8);
}
#[test]
fn test_saturating_minkowski_sub_basic() {
let a = U16CO::try_new(5, 10).unwrap();
let b = U16CO::try_new(2, 4).unwrap();
let res = a.saturating_minkowski_sub(b).unwrap();
assert_eq!(res.start(), 2);
assert_eq!(res.end_excl(), 8);
}
#[test]
fn test_saturating_minkowski_mul_basic() {
let a = U16CO::try_new(1, 4).unwrap();
let b = U16CO::try_new(2, 3).unwrap();
let res = a.saturating_minkowski_mul_hull(b).unwrap();
assert_eq!(res.start(), 2);
assert_eq!(res.end_excl(), 7);
}
#[test]
fn test_saturating_minkowski_div_basic() {
let a = U16CO::try_new(4, 10).unwrap();
let b = U16CO::try_new(2, 5).unwrap();
let res = a.saturating_minkowski_div_hull(b).unwrap();
assert_eq!(res.start(), 1);
assert_eq!(res.end_excl(), 5);
}
#[test]
fn test_saturating_minkowski_div_by_zero() {
let a = U16CO::try_new(1, 5).unwrap();
let b = U16CO::try_new(0, 3).unwrap();
assert!(a.saturating_minkowski_div_hull(b).is_none());
}
#[test]
fn test_saturating_add_can_collapse_to_none() {
let a = U16CO::try_new(u16::MAX - 5, u16::MAX).unwrap(); let b = U16CO::try_new(10, 20).unwrap(); assert!(a.saturating_minkowski_add(b).is_none());
}
#[test]
fn test_saturating_mul_can_collapse_to_none() {
let a = U16CO::try_new(u16::MAX - 5, u16::MAX).unwrap();
let b = U16CO::try_new(2, 3).unwrap();
assert!(a.saturating_minkowski_mul_hull(b).is_none());
}
#[test]
fn test_saturating_add_n_basic() {
let a = U16CO::try_new(3, 7).unwrap();
let res = a.saturating_minkowski_add_scalar(4).unwrap();
assert_eq!(res, U16CO::try_new(7, 11).unwrap());
}
#[test]
fn test_saturating_sub_n_basic() {
let a = U16CO::try_new(7, 11).unwrap();
let res = a.saturating_minkowski_sub_scalar(4).unwrap();
assert_eq!(res, U16CO::try_new(3, 7).unwrap());
}
#[test]
fn test_saturating_mul_n_basic() {
let a = U16CO::try_new(2, 5).unwrap();
let res = a.saturating_minkowski_mul_scalar_hull(3).unwrap();
assert_eq!(res, U16CO::try_new(6, 13).unwrap());
}
#[test]
fn test_saturating_div_n_basic() {
let a = U16CO::try_new(6, 13).unwrap();
let res = a.saturating_minkowski_div_scalar_hull(3).unwrap();
assert_eq!(res, U16CO::try_new(2, 5).unwrap());
}
#[test]
fn test_saturating_div_n_by_zero() {
let a = U16CO::try_new(1, 5).unwrap();
assert!(a.saturating_minkowski_div_scalar_hull(0).is_none());
}
#[test]
fn test_saturating_add_n_can_collapse_to_none() {
let a = U16CO::try_new(u16::MAX - 5, u16::MAX).unwrap();
assert!(a.saturating_minkowski_add_scalar(10).is_none());
}
#[test]
fn test_saturating_sub_n_can_collapse_to_none() {
let a = U16CO::try_new(1, 3).unwrap();
assert!(a.saturating_minkowski_sub_scalar(10).is_none());
}
#[test]
fn test_saturating_mul_n_can_collapse_to_none() {
let a = U16CO::try_new(u16::MAX - 5, u16::MAX).unwrap();
assert!(a.saturating_minkowski_mul_scalar_hull(2).is_none());
}
}
#[cfg(test)]
mod prop_tests {
use super::*;
use proptest::prelude::*;
fn interval_strategy() -> impl Strategy<Value = U16CO> {
prop_oneof![
Just(U16CO::try_new(u16::MIN, u16::MIN + 1).unwrap()), Just(U16CO::try_new(u16::MIN, u16::MAX).unwrap()), Just(U16CO::try_new(u16::MAX - 1, u16::MAX).unwrap()), (u16::MIN..=u16::MAX, u16::MIN..=u16::MAX)
.prop_filter_map("valid interval", |(s, e)| U16CO::try_new(s, e))
]
}
fn scalar_strategy() -> impl Strategy<Value = u16> {
prop_oneof![Just(0), Just(1), Just(u16::MAX), any::<u16>()]
}
#[inline]
fn endpoints(x: U16CO) -> [u16; 2] {
[x.start(), x.end_incl()]
}
proptest! {
#[test]
fn prop_saturating_add_semantics(a in interval_strategy(), b in interval_strategy()) {
let got = a.saturating_minkowski_add(b);
let expect_start = a.start().saturating_add(b.start());
let expect_end_excl = a.end_excl().saturating_add(b.end_incl());
let expect_none = expect_start >= expect_end_excl;
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), expect_start);
prop_assert_eq!(c.end_excl(), expect_end_excl);
for &x in &endpoints(a) {
for &y in &endpoints(b) {
let z = x.saturating_add(y);
if z < c.end_excl() {
prop_assert!(c.contains(z));
} else {
prop_assert_eq!(z, u16::MAX);
}
}
}
}
}
#[test]
fn prop_saturating_sub_semantics(a in interval_strategy(), b in interval_strategy()) {
let got = a.saturating_minkowski_sub(b);
let expect_none =
a.start().saturating_sub(b.end_incl()) >=
a.end_excl().saturating_sub(b.start());
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), a.start().saturating_sub(b.end_incl()));
prop_assert_eq!(c.end_incl(), a.end_incl().saturating_sub(b.start()));
for &x in &endpoints(a) {
for &y in &endpoints(b) {
let z = x.saturating_sub(y);
prop_assert!(c.contains(z));
}
}
}
}
#[test]
fn prop_saturating_mul_semantics(a in interval_strategy(), b in interval_strategy()) {
let got = a.saturating_minkowski_mul_hull(b);
let expect_start = a.start().saturating_mul(b.start());
let expect_end_excl = a.end_incl().saturating_mul(b.end_incl()).saturating_add(1);
let expect_none = expect_start >= expect_end_excl;
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), expect_start);
prop_assert_eq!(c.end_excl(), expect_end_excl);
for &x in &endpoints(a) {
for &y in &endpoints(b) {
let z = x.saturating_mul(y);
if z < c.end_excl() {
prop_assert!(c.contains(z));
} else {
prop_assert_eq!(z, u16::MAX);
}
}
}
}
}
#[test]
fn prop_saturating_div_semantics(
a in interval_strategy(),
b in interval_strategy()
) {
let got = a.saturating_minkowski_div_hull(b);
let expect_none =
b.start() == 0 ||
(a.start() / b.end_incl()) >= (a.end_incl() / b.start()).saturating_add(1);
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert!(b.start() != 0);
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) {
if y == 0 {
continue;
}
let z = x / y;
prop_assert!(c.contains(z));
}
}
}
}
#[test]
fn prop_saturating_add_n_semantics(a in interval_strategy(), n in scalar_strategy()) {
let got = a.saturating_minkowski_add_scalar(n);
let expect_start = a.start().saturating_add(n);
let expect_end_excl = a.end_excl().saturating_add(n);
let expect_none = expect_start >= expect_end_excl;
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), expect_start);
prop_assert_eq!(c.end_excl(), expect_end_excl);
for &x in &endpoints(a) {
let z = x.saturating_add(n);
if z < c.end_excl() {
prop_assert!(c.contains(z));
} else {
prop_assert_eq!(z, u16::MAX);
}
}
}
}
#[test]
fn prop_saturating_sub_n_semantics(a in interval_strategy(), n in scalar_strategy()) {
let got = a.saturating_minkowski_sub_scalar(n);
let expect_none =
a.start().saturating_sub(n) >= a.end_excl().saturating_sub(n);
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), a.start().saturating_sub(n));
prop_assert_eq!(c.end_incl(), a.end_incl().saturating_sub(n));
for &x in &endpoints(a) {
let z = x.saturating_sub(n);
prop_assert!(c.contains(z));
}
}
}
#[test]
fn prop_saturating_mul_n_semantics(a in interval_strategy(), n in scalar_strategy()) {
let got = a.saturating_minkowski_mul_scalar_hull(n);
let expect_start = a.start().saturating_mul(n);
let expect_end_excl = a.end_incl().saturating_mul(n).saturating_add(1);
let expect_none = expect_start >= expect_end_excl;
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert_eq!(c.start(), expect_start);
prop_assert_eq!(c.end_excl(), expect_end_excl);
for &x in &endpoints(a) {
let z = x.saturating_mul(n);
if z < c.end_excl() {
prop_assert!(c.contains(z));
} else {
prop_assert_eq!(z, u16::MAX);
}
}
}
}
#[test]
fn prop_saturating_div_n_semantics(a in interval_strategy(), n in scalar_strategy()) {
let got = a.saturating_minkowski_div_scalar_hull(n);
let expect_none =
n == 0 ||
(a.start() / n) >= (a.end_incl() / n).saturating_add(1);
prop_assert_eq!(got.is_none(), expect_none);
if let Some(c) = got {
prop_assert!(n != 0);
prop_assert_eq!(c.start(), a.start() / n);
prop_assert_eq!(c.end_incl(), a.end_incl() / n);
for &x in &endpoints(a) {
let z = x / n;
prop_assert!(c.contains(z));
}
}
}
#[test]
fn prop_add_commutative(a in interval_strategy(), b in interval_strategy()) {
prop_assert_eq!(a.saturating_minkowski_add(b), b.saturating_minkowski_add(a));
}
#[test]
fn prop_mul_commutative(a in interval_strategy(), b in interval_strategy()) {
prop_assert_eq!(a.saturating_minkowski_mul_hull(b), b.saturating_minkowski_mul_hull(a));
}
}
}