56 lines
1.7 KiB
Rust
56 lines
1.7 KiB
Rust
use std::collections::BTreeSet;
|
|
use std::ops::Bound::{self, *};
|
|
|
|
use quickcheck::{quickcheck, TestResult};
|
|
|
|
/// Covers every `std::ops::Range*` plus variants with exclusive start.
|
|
type RangeAny<T> = (Bound<T>, Bound<T>);
|
|
|
|
/// Mimic `RangeBounds::contains`, stabilized in Rust 1.35.
|
|
trait RangeBounds<T> {
|
|
fn contains(&self, _: &T) -> bool;
|
|
}
|
|
|
|
impl<T: PartialOrd> RangeBounds<T> for RangeAny<T> {
|
|
fn contains(&self, item: &T) -> bool {
|
|
(match &self.0 {
|
|
Included(start) => start <= item,
|
|
Excluded(start) => start < item,
|
|
Unbounded => true,
|
|
}) && (match &self.1 {
|
|
Included(end) => item <= end,
|
|
Excluded(end) => item < end,
|
|
Unbounded => true,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Checks conditions where `BTreeSet::range` panics:
|
|
/// - Panics if range start > end.
|
|
/// - Panics if range start == end and both bounds are Excluded.
|
|
fn panics<T: PartialOrd>(range: RangeAny<T>) -> bool {
|
|
match (&range.0, &range.1) {
|
|
(Excluded(start), Excluded(end)) => start >= end,
|
|
(Included(start), Excluded(end))
|
|
| (Excluded(start), Included(end))
|
|
| (Included(start), Included(end)) => start > end,
|
|
(Unbounded, _) | (_, Unbounded) => false,
|
|
}
|
|
}
|
|
|
|
/// Checks that `BTreeSet::range` returns all items contained in the given `range`.
|
|
fn check_range(set: BTreeSet<i32>, range: RangeAny<i32>) -> TestResult {
|
|
if panics(range) {
|
|
TestResult::discard()
|
|
} else {
|
|
let xs: BTreeSet<_> = set.range(range).cloned().collect();
|
|
TestResult::from_bool(
|
|
set.iter().all(|x| range.contains(x) == xs.contains(x)),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
quickcheck(check_range as fn(_, _) -> TestResult);
|
|
}
|