use super::*;
mod unit_tests {
use super::*;
const MIN: i16 = i16::MIN;
const MAX: i16 = i16::MAX;
const NEG_ONE: i16 = -1;
const ZERO: i16 = 0;
const ONE: i16 = 1;
mod len {
use super::*;
#[test]
fn len_of_singleton_is_one() {
let iv = I16CO::try_new(ZERO, ONE).unwrap();
assert_eq!(iv.len(), 1);
let iv = I16CO::try_new(MIN, MIN + ONE).unwrap();
assert_eq!(iv.len(), 1);
let iv = I16CO::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, u16::MAX),
];
for (start, end_excl, expect) in cases {
let iv = I16CO::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 = I16CO::try_new(start, end_excl).unwrap();
assert_eq!(
iv.len(),
iv.iter().count() as u16,
"case [{start}, {end_excl})"
);
}
}
#[test]
fn len_equals_end_minus_start_in_order_space() {
const SIGN_MASK: u16 = 1u16 << (i16::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 = I16CO::try_new(start, end_excl).unwrap();
let expect = ((end_excl as u16) ^ SIGN_MASK) - ((start as u16) ^ SIGN_MASK);
assert_eq!(iv.len(), expect, "case [{start}, {end_excl})");
}
}
#[test]
fn len_is_monotonic_under_interval_extension() {
let small = I16CO::try_new(-5, 5).unwrap();
let large = I16CO::try_new(-10, 10).unwrap();
assert!(small.len() < large.len());
let small = I16CO::try_new(MIN, -120).unwrap();
let large = I16CO::try_new(MIN, -100).unwrap();
assert!(small.len() < large.len());
let small = I16CO::try_new(100, 110).unwrap();
let large = I16CO::try_new(100, MAX).unwrap();
assert!(small.len() < large.len());
}
#[test]
fn len_of_maximal_i16_interval_is_255() {
let iv = I16CO::try_new(MIN, MAX).unwrap();
assert_eq!(iv.len(), u16::MAX);
}
}
mod midpoint_api {
use super::*;
#[test]
fn midpoint_basic() {
let iv = I16CO::try_new(0, 5).unwrap();
assert_eq!(iv.midpoint(), 2);
let iv = I16CO::try_new(-5, 5).unwrap();
assert_eq!(iv.midpoint(), 0);
let iv = I16CO::try_new(MIN, MAX).unwrap();
assert_eq!(iv.midpoint(), MIN + ((iv.len() / 2) as i16));
}
#[test]
fn checked_from_midpoint_len_basic() {
let mid = 0;
let len = 5;
let iv = I16CO::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 = I16CO::checked_from_midpoint_len(mid, len).unwrap();
assert_eq!(iv.len(), len);
assert_eq!(iv.midpoint(), mid);
assert!(I16CO::checked_from_midpoint_len(mid, 0).is_none());
assert!(I16CO::checked_from_midpoint_len(MIN, 10).is_none());
assert!(I16CO::checked_from_midpoint_len(MAX, 10).is_none());
}
#[test]
fn saturating_from_midpoint_len_basic() {
let mid = 0;
let len = 5;
let iv = I16CO::saturating_from_midpoint_len(mid, len).unwrap();
assert_eq!(iv.len(), len);
assert_eq!(iv.midpoint(), mid);
assert!(I16CO::saturating_from_midpoint_len(mid, 0).is_none());
let iv = I16CO::saturating_from_midpoint_len(MIN, 10).unwrap();
assert!(iv.start() >= MIN);
let iv = I16CO::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::<i16>(), end in any::<i16>()) {
if let Some(iv) = I16CO::try_new(start, end) {
prop_assert!(iv.len() >= 1);
}
}
#[test]
fn prop_len_matches_order_space_difference(start in any::<i16>(), end in any::<i16>()) {
if let Some(iv) = I16CO::try_new(start, end) {
const SIGN_MASK: u16 = 1u16 << (i16::BITS - 1);
let expect = ((end as u16) ^ SIGN_MASK) - ((start as u16) ^ SIGN_MASK);
prop_assert_eq!(iv.len(), expect);
}
}
}
}
mod midpoint_api {
use super::*;
fn mixed_scalar() -> impl Strategy<Value = i16> {
prop_oneof![3 => prop::sample::select(&[i16::MIN, i16::MAX, 0, -1, 1]), 7 => any::<i16>()]
}
proptest! {
#[test]
fn prop_midpoint_in_bounds(start in any::<i16>(), end in any::<i16>()) {
if let Some(iv) = I16CO::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 1u16..=255) {
if let Some(iv) = I16CO::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 1u16..=255) {
if let Some(iv) = I16CO::saturating_from_midpoint_len(mid, len) {
prop_assert!(iv.start() < iv.end_excl());
prop_assert_eq!(iv.midpoint(), iv.start() + (iv.len()/2) as i16);
}
}
}
}
}