use super::*;
mod unit_tests {
use super::*;
const MIN: isize = isize::MIN;
const MAX: isize = isize::MAX;
const NEG_ONE: isize = -1;
const ZERO: isize = 0;
const ONE: isize = 1;
mod len {
use super::*;
#[test]
fn len_of_singleton_is_one() {
let iv = IsizeCO::try_new(ZERO, ONE).unwrap();
assert_eq!(iv.len(), 1);
let iv = IsizeCO::try_new(MIN, MIN + ONE).unwrap();
assert_eq!(iv.len(), 1);
let iv = IsizeCO::try_new(MAX - ONE, MAX).unwrap();
assert_eq!(iv.len(), 1);
}
#[test]
fn len_matches_basic_examples() {
let cases = [
(MIN, MIN + ONE, 1),
(MIN, MIN + 8, 8),
(-5, ZERO, 5),
(ZERO, ONE, 1),
(ZERO, 10, 10),
(5, 9, 4),
(MAX - ONE, MAX, 1),
(MIN, MAX, usize::MAX),
];
for (start, end_excl, expect) in cases {
let iv = IsizeCO::try_new(start, end_excl).unwrap();
assert_eq!(iv.len(), expect, "case [{start}, {end_excl})");
}
}
#[test]
fn len_matches_iteration_count() {
let cases = [
(MIN, MIN + ONE),
(MIN, MIN + 8),
(-100, -90),
(-5, ZERO),
(NEG_ONE, ONE),
(ZERO, ONE),
(ZERO, 10),
(10, 20),
(MAX - ONE, MAX),
];
for (start, end_excl) in cases {
let iv = IsizeCO::try_new(start, end_excl).unwrap();
assert_eq!(
iv.len(),
iv.iter().count() as usize,
"case [{start}, {end_excl})"
);
}
}
#[test]
fn len_equals_end_minus_start_in_order_space() {
const SIGN_MASK: usize = 1usize << (isize::BITS - 1);
let cases = [
(MIN, MIN + ONE),
(MIN, NEG_ONE),
(MIN, ZERO),
(MIN, MAX),
(NEG_ONE, ZERO),
(NEG_ONE, ONE),
(ZERO, ONE),
(ZERO, MAX),
(MAX - ONE, MAX),
];
for (start, end_excl) in cases {
let iv = IsizeCO::try_new(start, end_excl).unwrap();
let expect = ((end_excl as usize) ^ SIGN_MASK) - ((start as usize) ^ SIGN_MASK);
assert_eq!(iv.len(), expect, "case [{start}, {end_excl})");
}
}
#[test]
fn len_is_monotonic_under_interval_extension() {
let small = IsizeCO::try_new(-5, 5).unwrap();
let large = IsizeCO::try_new(-10, 10).unwrap();
assert!(small.len() < large.len());
let small = IsizeCO::try_new(MIN, -120).unwrap();
let large = IsizeCO::try_new(MIN, -100).unwrap();
assert!(small.len() < large.len());
let small = IsizeCO::try_new(100, 110).unwrap();
let large = IsizeCO::try_new(100, MAX).unwrap();
assert!(small.len() < large.len());
}
#[test]
fn len_of_maximal_isize_interval_is_255() {
let iv = IsizeCO::try_new(MIN, MAX).unwrap();
assert_eq!(iv.len(), usize::MAX);
}
}
mod midpoint_api {
use super::*;
#[test]
fn midpoint_basic() {
let iv = IsizeCO::try_new(0, 5).unwrap();
assert_eq!(iv.midpoint(), 2);
let iv = IsizeCO::try_new(-5, 5).unwrap();
assert_eq!(iv.midpoint(), 0);
let iv = IsizeCO::try_new(MIN, MAX).unwrap();
assert_eq!(iv.midpoint(), MIN + ((iv.len() / 2) as isize));
}
#[test]
fn checked_from_midpoint_len_basic() {
let mid = 0;
let len = 5;
let iv = IsizeCO::checked_from_midpoint_len(mid, len).unwrap();
assert_eq!(iv.len(), len);
assert_eq!(iv.midpoint(), mid);
let mid = 10;
let len = 4;
let iv = IsizeCO::checked_from_midpoint_len(mid, len).unwrap();
assert_eq!(iv.len(), len);
assert_eq!(iv.midpoint(), mid);
assert!(IsizeCO::checked_from_midpoint_len(mid, 0).is_none());
assert!(IsizeCO::checked_from_midpoint_len(MIN, 10).is_none());
assert!(IsizeCO::checked_from_midpoint_len(MAX, 10).is_none());
}
#[test]
fn saturating_from_midpoint_len_basic() {
let mid = 0;
let len = 5;
let iv = IsizeCO::saturating_from_midpoint_len(mid, len).unwrap();
assert_eq!(iv.len(), len);
assert_eq!(iv.midpoint(), mid);
assert!(IsizeCO::saturating_from_midpoint_len(mid, 0).is_none());
let iv = IsizeCO::saturating_from_midpoint_len(MIN, 10).unwrap();
assert!(iv.start() >= MIN);
let iv = IsizeCO::saturating_from_midpoint_len(MAX, 10).unwrap();
assert!(iv.end_excl() <= MAX);
}
}
}
mod prop_tests {
use proptest::prelude::*;
use super::*;
mod len {
use super::*;
proptest! {
#[test]
fn prop_len_is_positive_for_valid_intervals(start in any::<isize>(), end in any::<isize>()) {
if let Some(iv) = IsizeCO::try_new(start, end) {
prop_assert!(iv.len() >= 1);
}
}
#[test]
fn prop_len_matches_order_space_difference(start in any::<isize>(), end in any::<isize>()) {
if let Some(iv) = IsizeCO::try_new(start, end) {
const SIGN_MASK: usize = 1usize << (isize::BITS - 1);
let expect = ((end as usize) ^ SIGN_MASK) - ((start as usize) ^ SIGN_MASK);
prop_assert_eq!(iv.len(), expect);
}
}
}
}
mod midpoint_api {
use super::*;
fn mixed_scalar() -> impl Strategy<Value = isize> {
prop_oneof![3 => prop::sample::select(&[isize::MIN, isize::MAX, 0, -1, 1]), 7 => any::<isize>()]
}
proptest! {
#[test]
fn prop_midpoint_in_bounds(start in any::<isize>(), end in any::<isize>()) {
if let Some(iv) = IsizeCO::try_new(start, end) {
let mp = iv.midpoint();
prop_assert!(mp >= iv.start());
prop_assert!(mp <= iv.end_incl());
}
}
#[test]
fn prop_checked_from_midpoint_len_inverse(mid in mixed_scalar(), len in 1usize..=255) {
if let Some(iv) = IsizeCO::checked_from_midpoint_len(mid, len) {
prop_assert_eq!(iv.len(), len);
prop_assert_eq!(iv.midpoint(), mid);
}
}
#[test]
fn prop_saturating_from_midpoint_len_safety(mid in mixed_scalar(), len in 1usize..=255) {
if let Some(iv) = IsizeCO::saturating_from_midpoint_len(mid, len) {
prop_assert!(iv.start() < iv.end_excl());
prop_assert_eq!(iv.midpoint(), iv.start() + (iv.len()/2) as isize);
}
}
}
}
}