use crate::BoxShrink;
pub fn filter<E, P>(original_shrink: BoxShrink<E>, predicate: P) -> BoxShrink<E>
where
E: Clone + 'static,
P: Fn(&E) -> bool + Clone + 'static,
{
crate::shrinks::from_fn(move |original: E| {
let pred = predicate.clone();
let mut filter_streak = 0;
original_shrink.clone().candidates(original.clone()).filter(
move |candidate| {
let verdict = pred(candidate);
filter_streak = if verdict { 0 } else { filter_streak + 1 };
if filter_streak >= 100 {
panic!(
"Too heavy filtering. Filtered out 100 examples in a \
row. For test performance, please use more efficient \
way to generate examples than heavy reliance on \
filtering."
)
}
verdict
},
)
})
}
#[cfg(test)]
mod test {
use crate::testing::assert_iter_eq;
use crate::*;
#[test]
fn should_be_able_to_filter_using_predicate() {
let shrinker = crate::shrinks::fixed::sequence(&[
11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
])
.filter(|e| e % 2 == 0);
assert_iter_eq(
shrinker.candidates(1337),
vec![10, 8, 6, 4, 2],
"only even candidates should be returned",
)
}
#[test]
#[should_panic = "Too heavy filtering. Filtered out 100 examples in a row. \
For test performance, please use more efficient way to generate \
examples than heavy reliance on filtering."]
fn should_panic_on_too_heavy_filtering() {
let filtererd_shrinker =
crate::shrinks::int_to_zero::<u8>().filter(|&e| e == 234);
filtererd_shrinker.candidates(200).next();
}
#[test]
fn should_not_panic_on_repeaded_filtering() {
let filtererd_shrinker =
crate::shrinks::int_to_zero::<u16>().filter(|&e| e % 2 == 0);
assert!(
filtererd_shrinker.candidates(2000).count() > 1000,
"More candidates that the limit for to heavy filtering is filtered \
out without panicing");
}
}