test: add tests for signals
This commit is contained in:
parent
22d19154af
commit
00a1c32fc1
1 changed files with 153 additions and 1 deletions
|
|
@ -201,7 +201,7 @@ impl<T> BaseSignal for Signal<T> {
|
||||||
|
|
||||||
let last_time = self.time_points.last();
|
let last_time = self.time_points.last();
|
||||||
match last_time {
|
match last_time {
|
||||||
Some(last_t) if last_t > &time => Err(Error::NonMonotonicSignal {
|
Some(last_t) if last_t >= &time => Err(Error::NonMonotonicSignal {
|
||||||
end_time: *last_t,
|
end_time: *last_t,
|
||||||
current_sample: time,
|
current_sample: time,
|
||||||
}),
|
}),
|
||||||
|
|
@ -249,3 +249,155 @@ impl<T> BaseSignal for ConstantSignal<T> {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod arbitrary {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use proptest::{prelude::*, sample::SizeRange};
|
||||||
|
|
||||||
|
/// Generate an arbitrary list of samples and two indices within the list
|
||||||
|
pub fn samples_and_indices<T>(
|
||||||
|
size: impl Into<SizeRange>,
|
||||||
|
) -> impl Strategy<Value = (Vec<(Duration, T)>, usize, usize)>
|
||||||
|
where
|
||||||
|
T: Arbitrary + Copy,
|
||||||
|
{
|
||||||
|
samples(size).prop_flat_map(|vec| {
|
||||||
|
let len = vec.len();
|
||||||
|
if len == 0 {
|
||||||
|
(Just(vec), 0..1, 0..1)
|
||||||
|
} else {
|
||||||
|
(Just(vec), 0..len, 0..len)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate arbitrary samples for a signal where the time stamps are strictly
|
||||||
|
/// monotonically increasing
|
||||||
|
pub fn samples<T>(size: impl Into<SizeRange>) -> impl Strategy<Value = Vec<(Duration, T)>>
|
||||||
|
where
|
||||||
|
T: Arbitrary + Copy,
|
||||||
|
{
|
||||||
|
prop::collection::vec(any::<T>(), size).prop_flat_map(|values| {
|
||||||
|
let len = values.len();
|
||||||
|
prop::collection::vec(any::<u64>(), len).prop_map(move |mut ts| {
|
||||||
|
ts.sort_unstable();
|
||||||
|
ts.dedup();
|
||||||
|
ts.into_iter()
|
||||||
|
.map(Duration::from_secs)
|
||||||
|
.zip(values.clone().into_iter())
|
||||||
|
.collect_vec()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate arbitrary signals of the given type
|
||||||
|
pub fn signal<T>(size: impl Into<SizeRange>) -> impl Strategy<Value = Signal<T>>
|
||||||
|
where
|
||||||
|
T: Arbitrary + Copy,
|
||||||
|
{
|
||||||
|
samples(size).prop_map(Signal::<T>::from_iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate an arbitrary constant signal
|
||||||
|
pub fn constant_signal<T>() -> impl Strategy<Value = ConstantSignal<T>>
|
||||||
|
where
|
||||||
|
T: Arbitrary,
|
||||||
|
{
|
||||||
|
any::<T>().prop_map(ConstantSignal::new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use core::ops::Bound;
|
||||||
|
use paste::paste;
|
||||||
|
use proptest::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! correctly_create_signals_impl {
|
||||||
|
($ty:ty) => {
|
||||||
|
proptest! {
|
||||||
|
|((samples, idx, _) in arbitrary::samples_and_indices::<$ty>(0..100))| {
|
||||||
|
// Creating a signal should be fine
|
||||||
|
let signal: Signal<_> = samples.clone().into_iter().collect();
|
||||||
|
|
||||||
|
if samples.len() > 0 {
|
||||||
|
// We wil get the start and end times.
|
||||||
|
let start_time = samples.first().unwrap().0;
|
||||||
|
let end_time = samples.last().unwrap().0;
|
||||||
|
// Get the value of the sample at a given index
|
||||||
|
let (at, val) = samples[idx];
|
||||||
|
|
||||||
|
assert_eq!(signal.start_time(), Bound::Included(start_time));
|
||||||
|
assert_eq!(signal.end_time(), Bound::Included(end_time));
|
||||||
|
assert_eq!(signal.at(at), Some(&val));
|
||||||
|
} else {
|
||||||
|
assert!(signal.is_empty());
|
||||||
|
assert_eq!(signal.at(Duration::from_secs(1)), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
|((mut samples, a, b) in arbitrary::samples_and_indices::<$ty>(5..100))| {
|
||||||
|
prop_assume!(a != b);
|
||||||
|
// Swap two indices in the samples
|
||||||
|
samples.swap(a, b);
|
||||||
|
// Creating a signal should fail
|
||||||
|
let signal = Signal::try_from_iter(samples.clone());
|
||||||
|
assert!(signal.is_err(), "swapped {:?} and {:?}", samples[a], samples[b]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_signals_from_samples() {
|
||||||
|
correctly_create_signals_impl!(bool);
|
||||||
|
correctly_create_signals_impl!(i8);
|
||||||
|
correctly_create_signals_impl!(i16);
|
||||||
|
correctly_create_signals_impl!(i32);
|
||||||
|
correctly_create_signals_impl!(i64);
|
||||||
|
correctly_create_signals_impl!(u8);
|
||||||
|
correctly_create_signals_impl!(u16);
|
||||||
|
correctly_create_signals_impl!(u32);
|
||||||
|
correctly_create_signals_impl!(u64);
|
||||||
|
correctly_create_signals_impl!(f32);
|
||||||
|
correctly_create_signals_impl!(f64);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! signals_fromiter_panic {
|
||||||
|
($ty:ty) => {
|
||||||
|
paste! {
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn [<fail_create_ $ty _signal>] ((mut samples, a, b) in arbitrary::samples_and_indices::<$ty>(5..100))
|
||||||
|
{
|
||||||
|
prop_assume!(a != b);
|
||||||
|
// Swap two indices in the samples
|
||||||
|
samples.swap(a, b);
|
||||||
|
// Creating a signal should fail
|
||||||
|
let _: Signal<_> = samples.into_iter().collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
signals_fromiter_panic!(bool);
|
||||||
|
signals_fromiter_panic!(i8);
|
||||||
|
signals_fromiter_panic!(i16);
|
||||||
|
signals_fromiter_panic!(i32);
|
||||||
|
signals_fromiter_panic!(i64);
|
||||||
|
signals_fromiter_panic!(u8);
|
||||||
|
signals_fromiter_panic!(u16);
|
||||||
|
signals_fromiter_panic!(u32);
|
||||||
|
signals_fromiter_panic!(u64);
|
||||||
|
signals_fromiter_panic!(f32);
|
||||||
|
signals_fromiter_panic!(f64);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue