use super::*;
mod unit_tests {
use super::*;
fn span(lo: i32, hi: i32) -> I32CO {
I32CO::try_new(lo, hi).unwrap()
}
#[test]
fn basic_overlap() {
let a = span(2, 6);
let b = span(4, 8);
assert_eq!(a.intersection(b), Some(span(4, 6)));
}
#[test]
fn disjoint() {
let a = span(1, 3);
let b = span(5, 7);
assert_eq!(a.intersection(b), None);
}
#[test]
fn containment() {
let a = span(2, 10);
let b = span(4, 6);
assert_eq!(a.intersection(b), Some(b));
}
#[test]
fn identical() {
let a = span(3, 7);
assert_eq!(a.intersection(a), Some(a));
}
}
mod prop_tests {
use std::{vec, vec::Vec};
use super::*;
use proptest::prelude::*;
fn span(a: i32, b: i32) -> Option<I32CO> {
let lo = a.min(b);
let hi = a.max(b);
I32CO::try_new(lo, hi)
}
fn edge_values() -> Vec<i32> {
let mut v = vec![i32::MIN, i32::MAX, 0, 1];
if i32::MIN < i32::MAX {
v.push(i32::MIN.saturating_add(1));
v.push(i32::MAX.saturating_sub(1));
}
v.sort_unstable();
v.dedup();
v
}
fn edge_scalar() -> impl Strategy<Value = i32> {
prop::sample::select(edge_values())
}
fn mixed_scalar() -> impl Strategy<Value = i32> {
prop_oneof! {
3 => edge_scalar(),
7 => any::<i32>(),
}
}
fn span_strategy() -> impl Strategy<Value = I32CO> {
(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 intersection_subset(
x in span_strategy(),
y in span_strategy(),
p in mixed_scalar(),
) {
let i = x.intersection(y);
if let Some(i) = i {
if i.contains(p) {
prop_assert!(x.contains(p));
prop_assert!(y.contains(p));
}
}
}
#[test]
fn common_points_preserved(
x in span_strategy(),
y in span_strategy(),
p in mixed_scalar(),
) {
if x.contains(p) && y.contains(p) {
let i = x.intersection(y);
prop_assert!(i.unwrap().contains(p));
}
}
#[test]
fn membership_law(
x in span_strategy(),
y in span_strategy(),
p in mixed_scalar(),
) {
let i = x.intersection(y);
let expected = x.contains(p) && y.contains(p);
prop_assert_eq!(
i.map(|z| z.contains(p)).unwrap_or(false),
expected
);
}
#[test]
fn bounds_correct(
x in span_strategy(),
y in span_strategy(),
) {
let lo = x.start().max(y.start());
let hi = x.end_excl().min(y.end_excl());
let expected = I32CO::try_new(lo, hi);
prop_assert_eq!(x.intersection(y), expected);
}
#[test]
fn empty_iff_no_common_point(
x in span_strategy(),
y in span_strategy(),
) {
let lo = x.start().max(y.start());
let hi = x.end_excl().min(y.end_excl());
let expected = lo < hi;
prop_assert_eq!(
x.intersection(y).is_some(),
expected
);
}
#[test]
fn commutative(
x in span_strategy(),
y in span_strategy(),
) {
prop_assert_eq!(x.intersection(y), y.intersection(x));
}
#[test]
fn idempotent(
x in span_strategy(),
) {
prop_assert_eq!(x.intersection(x), Some(x));
}
}
}