use crate::{
I128COSetBuilder,
i128::tests::test_support::{interval_pair, iv},
};
#[test]
fn seal_empty_builder_returns_empty_set() {
let set = I128COSetBuilder::new().seal();
assert!(set.is_empty());
assert_eq!(set.interval_count(), 0);
assert_eq!(set.as_slice(), &[]);
}
#[test]
fn seal_keeps_disjoint_intervals_sorted() {
let b = I128COSetBuilder::new();
b.insert(iv(40, 50));
b.insert(iv(0, 10));
b.insert(iv(20, 30));
let set = b.seal();
assert_eq!(set.as_slice(), &[iv(0, 10), iv(20, 30), iv(40, 50)]);
}
#[test]
fn seal_merges_adjacent_intervals() {
let b = I128COSetBuilder::new();
b.insert(iv(10, 20));
b.insert(iv(0, 5));
b.insert(iv(5, 10));
b.insert(iv(20, 25));
let set = b.seal();
assert_eq!(set.as_slice(), &[iv(0, 25)]);
}
#[test]
fn seal_merges_overlapping_intervals() {
let b = I128COSetBuilder::new();
b.insert(iv(10, 20));
b.insert(iv(15, 30));
b.insert(iv(25, 40));
let set = b.seal();
assert_eq!(set.as_slice(), &[iv(10, 40)]);
}
#[test]
fn seal_merges_mixed_adjacent_and_overlapping_intervals() {
let b = I128COSetBuilder::new();
b.insert(iv(10, 20));
b.insert(iv(0, 5));
b.insert(iv(5, 10));
b.insert(iv(18, 31));
b.insert(iv(30, 40));
let set = b.seal();
assert_eq!(set.as_slice(), &[iv(0, 40)]);
}
#[test]
fn duplicate_intervals_are_deduplicated_by_set_semantics() {
let b = I128COSetBuilder::new();
b.insert(iv(1, 4));
b.insert(iv(1, 4));
b.insert(iv(1, 4));
let set = b.seal();
assert_eq!(set.as_slice(), &[iv(1, 4)]);
}
#[test]
fn seal_handles_domain_endpoints() {
let b = I128COSetBuilder::new();
b.insert(iv(i128::MIN, i128::MIN + 1));
b.insert(iv(2, 3));
b.insert(iv(i128::MAX - 1, i128::MAX));
let set = b.seal();
assert_eq!(
set.as_slice(),
&[iv(i128::MIN, i128::MIN + 1), iv(2, 3), iv(i128::MAX - 1, i128::MAX)]
);
}
#[test]
fn concurrent_writes_are_collected_before_seal() {
let b = I128COSetBuilder::new();
std::thread::scope(|s| {
let b0 = &b;
s.spawn(move || {
b0.insert(iv(0, 4));
b0.insert(iv(20, 25));
});
let b1 = &b;
s.spawn(move || {
b1.insert(iv(4, 8));
b1.insert(iv(25, 30));
});
let b2 = &b;
s.spawn(move || {
b2.insert(iv(8, 10));
b2.insert(iv(30, 31));
});
});
let set = b.seal();
assert_eq!(set.as_slice(), &[iv(0, 10), iv(20, 31)]);
}
#[test]
fn seal_orders_negative_zero_and_positive_intervals() {
let b = I128COSetBuilder::new();
b.insert(iv(10, 20));
b.insert(iv(-20, -10));
b.insert(iv(0, 5));
let set = b.seal();
assert_eq!(set.as_slice(), &[iv(-20, -10), iv(0, 5), iv(10, 20)]);
}
use int_interval::I128CO;
use proptest::prelude::*;
fn reference_normalize(mut xs: Vec<(i128, i128)>) -> Vec<I128CO> {
xs.sort_unstable();
let mut out: Vec<I128CO> = Vec::new();
for (start, end_excl) in xs {
let iv = iv(start, end_excl);
match out.last_mut() {
Some(last) if last.is_contiguous_with(iv) => {
*last = last.convex_hull(iv);
}
_ => out.push(iv),
}
}
out
}
proptest! {
#[test]
fn prop_seal_matches_reference_normalize(
xs in prop::collection::vec(interval_pair(), 0..64)
) {
let b = I128COSetBuilder::new();
for &(start, end_excl) in &xs {
b.insert(iv(start, end_excl));
}
let set = b.seal();
let expected = reference_normalize(xs);
prop_assert_eq!(set.as_slice(), expected.as_slice());
}
#[test]
fn prop_seal_output_is_canonical(
xs in prop::collection::vec(interval_pair(), 0..64)
) {
let b = I128COSetBuilder::new();
for (start, end_excl) in xs {
b.insert(iv(start, end_excl));
}
let set = b.seal();
prop_assert!(
set.as_slice()
.windows(2)
.all(|w| w[0].end_excl() < w[1].start())
);
}
}