test: add proptest arbitrary as a feature

This commit is contained in:
Anand Balakrishnan 2023-04-04 09:56:19 -07:00
parent 00b03a509f
commit 7c8c833469
No known key found for this signature in database
4 changed files with 9 additions and 178 deletions

View file

@ -264,7 +264,7 @@ impl ExprBuilder {
}
}
#[cfg(test)]
#[cfg(any(test, feature = "arbitrary"))]
pub mod arbitrary {
//! Helper functions to generate arbitrary expressions using [`proptest`].
use proptest::prelude::*;

View file

@ -268,10 +268,8 @@ impl<T> BaseSignal for ConstantSignal<T> {
}
}
#[cfg(test)]
#[cfg(any(test, feature = "arbitrary"))]
pub mod arbitrary {
use itertools::Itertools;
use proptest::prelude::*;
use proptest::sample::SizeRange;
@ -308,7 +306,7 @@ pub mod arbitrary {
ts.into_iter()
.map(Duration::from_secs)
.zip(values.clone().into_iter())
.collect_vec()
.collect::<Vec<_>>()
})
})
}

View file

@ -173,173 +173,3 @@ where
(start, end)
}
/// More precise intersection of two ranges from point of the first range
#[derive(Debug, PartialEq)]
pub enum Intersection {
/// The self is below the other
Below,
/// The self is below but overlaping
BelowOverlap,
/// The self is within the other
Within,
/// The self is same as the other
Same,
/// The self is over the other, the other is within the self
Over,
/// The self is above but overlaping
AboveOverlap,
/// The self is above the other
Above,
}
impl Intersection {
/// Test if there is any intersection
pub fn is_any(&self) -> bool {
!matches!(self, Intersection::Below | Intersection::Above)
}
/// Test if the range is fully within the other
pub fn is_within(&self) -> bool {
matches!(self, Intersection::Within | Intersection::Same)
}
/// Test if the range is fully over the other
pub fn is_over(&self) -> bool {
matches!(self, Intersection::Over | Intersection::Same)
}
}
pub trait Intersect<T, U>
where
T: PartialOrd,
U: RangeBounds<T>,
{
/// Test two ranges for an intersection
fn check_intersect(&self, other: &U) -> Intersection;
}
impl<T, U, R> Intersect<T, U> for R
where
T: PartialOrd + PartialEq,
U: RangeBounds<T>,
R: RangeBounds<T>,
{
fn check_intersect(&self, other: &U) -> Intersection {
use core::cmp::Ordering::*;
use core::ops::Bound::*;
// We find where the start of self is with respect to that of other
let (left_rel_pos, me_start) = match (self.start_bound(), other.start_bound()) {
(Included(me), Excluded(them)) if me == them => (Less, Some(me)), // [a, _} left of (a, }
//
(Excluded(me), Included(them)) if me == them => (Greater, Some(me)), // (a, _} right of [a, }
// If both are consistently open or close, or they are not equal then we
// just compare them
(Included(me), Excluded(them))
| (Excluded(me), Included(them))
| (Included(me), Included(them))
| (Excluded(me), Excluded(them)) => (me.partial_cmp(them).unwrap(), Some(me)),
// start of self > start of other
(Included(me), Unbounded) | (Excluded(me), Unbounded) => (Greater, Some(me)),
(Unbounded, Unbounded) => (Equal, None), // unbounded start
(Unbounded, _) => (Less, None), // start of self < start of other
};
// We find where the end of self is with respect to that of other
let (right_rel_pos, me_end) = match (self.end_bound(), other.end_bound()) {
(Included(me), Excluded(them)) if me == them => (Greater, Some(me)), // {_, a] right of {_, a)
(Excluded(me), Included(them)) if me == them => (Less, Some(me)), // {_, a) right of {_, a]
// If both are consistently open or close, or they are not equal then we just compare them
(Included(me), Excluded(them))
| (Excluded(me), Included(them))
| (Included(me), Included(them))
| (Excluded(me), Excluded(them)) => (me.partial_cmp(them).unwrap(), Some(me)),
(Included(me), Unbounded) | (Excluded(me), Unbounded) => (Less, Some(me)), // end of self < end of other
(Unbounded, Unbounded) => (Equal, None), // unbounded end
(Unbounded, _) => (Greater, None), // end of self > end of other
};
// We have gotten the relative position of the ends. But we need to check if one
// of the ends are contained within the bounds of the other.
match (left_rel_pos, right_rel_pos) {
(Less, Less) => {
// Check if the end of self is contained within other's domain
// NOTE: Since right is less than, me_end must not be None
assert!(me_end.is_some());
if other.contains(me_end.unwrap()) {
// self is below but overlaps
Intersection::BelowOverlap
} else {
// self is strictly below
Intersection::Below
}
}
(Greater, Greater) => {
// Check if the start of self is contained within other's domain
// NOTE: Since left is greater than, me_start must not be None
assert!(me_start.is_some());
if other.contains(me_start.unwrap()) {
// self is to the right of but overlaps other
Intersection::AboveOverlap
} else {
// self is strictly above
Intersection::Above
}
}
(Less, Greater) | (Equal, Greater) | (Less, Equal) => Intersection::Over, // self contains other
(Equal, Less) | (Greater, Equal) | (Greater, Less) => Intersection::Within, // self within other
(Equal, Equal) => Intersection::Same, // The ranges are equal
}
}
}
#[cfg(test)]
mod tests {
use std::ops::Range;
use proptest::prelude::*;
use super::*;
proptest! {
#[test]
fn range_range_intersection(r1 in any::<Range<i32>>(), r2 in any::<Range<i32>>()) {
use Intersection::*;
let intersect_p = r1.check_intersect(&r2);
match intersect_p {
Below => assert!(r1.end < r2.start, "Expected strict below"),
BelowOverlap => {
assert!(r1.start < r2.start, "Expected below with overlap");
assert!(r2.contains(&r1.end), "Expected below with overlap");
},
Within => {
assert!(r2.contains(&r1.end), "Expected to be contained");
assert!(r2.contains(&r1.start), "Expected to be contained");
}
Same => {
assert!(r1.start == r2.start, "Expected to be same");
assert!(r1.end == r2.end, "Expected to be same");
}
Over => {
assert!(r1.contains(&r2.start), "Expected to cover");
assert!(r1.contains(&r2.end), "Expected to cover");
}
AboveOverlap => {
assert!(r2.contains(&r1.start), "Expected above with overlap");
assert!(r1.end > r2.end, "Expected above with overlap");
}
Above => assert!(r1.start > r2.end, "Expected strict above"),
}
}
}
}