struct TraceItem<T>(T);
impl<T: crate::Item + std::fmt::Debug> crate::Item for TraceItem<T>
where T::Period: std::fmt::Debug,
{
type Period = T::Period;
fn matches(&self, old: &Self, period: &T::Period) -> bool {
let r = self.0.matches(&old.0, period);
eprintln!("matches({:?} - {:?} >= {:?}) -> {}", self.0, old.0, period, r);
r
}
}
fn assert_keep<Item: crate::Item + std::cmp::Ord + std::fmt::Debug + Clone>(
config: &crate::Config<Item::Period>,
candidates: impl IntoIterator<Item=Item>,
saved: impl IntoIterator<Item=Item>,
)
where Item::Period: std::fmt::Debug
{
let actual = std::cell::RefCell::new(std::collections::BTreeSet::new());
let expected = saved.into_iter().collect::<std::collections::BTreeSet<_>>();
let traced_candidates = candidates.into_iter()
.map(TraceItem)
.inspect(|c| {
let mut actual = actual.borrow_mut();
eprintln!("Alive {:?}", actual);
actual.insert(c.0.clone());
eprintln!("Processing {:?}", c.0);
});
for evicted in crate::prune(config, traced_candidates) {
eprintln!("Evict {:?}", evicted.0);
let mut actual = actual.borrow_mut();
assert!(actual.remove(&evicted.0), "{:?} was evicted twice.", evicted.0);
}
assert_eq!(*actual.borrow(), expected);
}
#[test]
fn daily() {
let c = crate::Config {
buckets: vec![crate::Bucket{period: 3, count: 3}],
};
assert_keep(&c,
1..=12,
[4, 7, 10]);
assert_keep(&c,
2..=12,
[5, 8, 11]);
assert_keep(&c,
[4, 7, 10, 13],
[7, 10, 13]);
assert_keep(&c,
[7, 10, 13, 14],
[7, 10, 13]);
assert_keep(&c,
[4, 7, 10, 13, 14],
[7, 10, 13]);
assert_keep(&c,
[4, 7, 10, 13, 14, 15, 16, 17],
[10, 13, 16]);
assert_keep(&c,
[5, 8, 11, 13, 14],
[8, 11, 14]);
}
#[test]
fn daily_weekly() {
let c = crate::Config {
buckets: vec![
crate::Bucket{period: 3, count: 3},
crate::Bucket{period: 6, count: 4},
],
};
assert_keep(&c,
1..=10,
[1, 4, 7, 10]);
assert_keep(&c,
1..=20,
[1, 7, 13, 16, 19]);
assert_keep(&c,
1..=30,
[7, 13, 19, 22, 25, 28]);
assert_keep(&c,
1..=50,
[31, 37, 43, 46, 49]);
}
#[test]
fn daily_weekly_unaligned() {
let c = crate::Config {
buckets: vec![
crate::Bucket{period: 3, count: 2},
crate::Bucket{period: 7, count: 4},
],
};
assert_keep(&c,
1..=10,
[1, 7, 10]);
assert_keep(&c,
1..=20,
[1, 10, 16, 19]);
assert_keep(&c,
1..=30,
[1, 10, 19, 25, 28]);
assert_keep(&c,
1..=50,
[19, 28, 37, 46, 49]);
}
#[test]
fn multi_aligned() {
let c = crate::Config {
buckets: vec![
crate::Bucket{period: 2, count: 4},
crate::Bucket{period: 4, count: 3},
crate::Bucket{period: 8, count: 2},
crate::Bucket{period: 16, count: 2},
],
};
assert_keep(&c,
1..=20,
[1, 9, 13, 15, 17, 19]);
assert_keep(&c,
1..=30,
[1, 17, 21, 23, 25, 27, 29]);
assert_keep(&c,
1..=50,
[33, 41, 43, 45, 47, 49]);
}
#[test]
fn multi_unaligned() {
let c = crate::Config {
buckets: vec![
crate::Bucket{period: 4, count: 4},
crate::Bucket{period: 5, count: 3},
crate::Bucket{period: 10, count: 4},
crate::Bucket{period: 12, count: 4},
],
};
assert_keep(&c,
1..=20,
[1, 5, 9, 13, 17]);
assert_keep(&c,
1..=30,
[1, 9, 17, 21, 25, 29]);
assert_keep(&c,
1..=50,
[1, 17, 33, 37, 41, 45, 49]);
}
#[test]
fn smaller_bucket_aligned() {
let c = crate::Config {
buckets: vec![
crate::Bucket{period: 2, count: 6},
crate::Bucket{period: 4, count: 2},
],
};
assert_keep(&c,
1..=20,
[7, 9, 11, 13, 15, 17, 19]);
}
#[test]
fn dates() {
let c = crate::Config {
buckets: vec![
crate::Bucket{period: chrono::Duration::days(2), count: 3},
crate::Bucket{period: chrono::Duration::weeks(1), count: 4},
],
};
assert_keep(&c,
(1..=30).map(|d| chrono::NaiveDate::from_ymd(1, 1, d)),
[
chrono::NaiveDate::from_ymd(1, 1, 1),
chrono::NaiveDate::from_ymd(1, 1, 9),
chrono::NaiveDate::from_ymd(1, 1, 17),
chrono::NaiveDate::from_ymd(1, 1, 25),
chrono::NaiveDate::from_ymd(1, 1, 27),
chrono::NaiveDate::from_ymd(1, 1, 29),
]);
}