use super::*;
fn windows(from: u64, to: u64, span: u64) -> Vec<(u64, u64)> {
let mut out = Vec::new();
let mut start = from;
while start <= to {
let end = window_end(start, to, span);
out.push((start, end));
start = end + 1;
}
out
}
#[test]
fn window_end_splits_the_range() {
assert_eq!(windows(0, 19, 10), vec![(0, 9), (10, 19)]);
assert_eq!(windows(0, 25, 10), vec![(0, 9), (10, 19), (20, 25)]);
assert_eq!(windows(1_000, 1_000, 10), vec![(1_000, 1_000)]);
assert_eq!(windows(1_000, 1_005, 10), vec![(1_000, 1_005)]);
assert_eq!(windows(100, 119, 10), vec![(100, 109), (110, 119)]);
assert_eq!(window_end(7, 100, 0), 7);
assert_eq!(window_end(5, 9, u64::MAX), 9);
}
#[test]
fn halved_span_halves_the_window_length() {
assert_eq!(halved_span(1, 20), Some(10), "20 blocks -> 10");
assert_eq!(halved_span(0, 20), Some(10), "21 blocks -> 10");
assert_eq!(halved_span(5, 7), Some(1), "3 blocks -> 1");
assert_eq!(halved_span(5, 6), Some(1), "2 blocks -> 1");
assert_eq!(halved_span(9, 9), None, "a one-block window cannot shrink");
assert_eq!(
halved_span(0, u64::MAX),
Some(1 << 63),
"the full u64 range does not overflow"
);
}
fn span(ceiling: u64) -> WindowSpan {
WindowSpan::new(NonZeroU64::new(ceiling).unwrap_or(NonZeroU64::MIN))
}
fn accept(span: &mut WindowSpan, n: u32) -> Option<u64> {
(0..n).filter_map(|_| span.record_success()).last()
}
#[test]
fn window_span_shrinks_to_half_the_rejected_window() {
let mut span = span(10_000);
assert_eq!(
span.shrink(100, 129),
Some(Shrunk {
span: 15,
rejected_probe: false
})
);
assert_eq!(span.current(), 15);
assert_eq!(span.shrink(7, 7), None);
assert_eq!(span.current(), 15);
}
#[test]
fn window_span_never_shrinks_above_the_current_span() {
let mut span = span(100);
assert!(span.shrink(0, 19).is_some(), "20 blocks -> 10");
assert_eq!(span.shrink(0, 99).map(|s| s.span), Some(10));
assert_eq!(span.current(), 10);
}
#[test]
fn window_span_regrows_after_a_streak_up_to_the_ceiling() {
let mut span = span(100);
assert!(span.shrink(0, 99).is_some(), "100 blocks -> 50");
assert_eq!(accept(&mut span, SPAN_REGROW_AFTER_WINDOWS - 1), None);
assert_eq!(accept(&mut span, 1), Some(100));
assert_eq!(accept(&mut span, SPAN_REGROW_AFTER_WINDOWS * 2), None);
assert_eq!(span.current(), 100);
}
#[test]
fn window_span_climbs_back_to_the_ceiling_on_short_windows() {
let mut span = span(10_000);
assert!(span.shrink(0, 29).is_some());
let mut last = None;
for _ in 0..20 {
last = accept(&mut span, SPAN_REGROW_AFTER_WINDOWS).or(last);
}
assert_eq!(last, Some(10_000));
assert_eq!(span.current(), 10_000);
}
#[test]
fn window_span_flags_a_rejected_regrow_probe() {
let mut span = span(200);
let first = span.shrink(0, 199);
assert_eq!(
first.map(|s| (s.span, s.rejected_probe)),
Some((100, false))
);
assert_eq!(accept(&mut span, SPAN_REGROW_AFTER_WINDOWS), Some(200));
let probe = span.shrink(0, 199);
assert_eq!(probe.map(|s| (s.span, s.rejected_probe)), Some((100, true)));
let deeper = span.shrink(0, 99);
assert_eq!(
deeper.map(|s| (s.span, s.rejected_probe)),
Some((50, false))
);
}
#[test]
fn window_span_rejection_resets_the_streak() {
let mut span = span(200);
assert!(span.shrink(0, 199).is_some());
assert_eq!(accept(&mut span, SPAN_REGROW_AFTER_WINDOWS - 1), None);
assert!(span.shrink(0, 99).is_some(), "100 -> 50, streak reset");
assert_eq!(accept(&mut span, SPAN_REGROW_AFTER_WINDOWS - 1), None);
assert_eq!(accept(&mut span, 1), Some(100));
}
#[test]
fn windows_cover_a_large_gap_without_overlap_or_gap() {
let (from, to, span) = (1_000u64, 55_321u64, 10_000u64);
let windows = windows(from, to, span);
let mut expected_next = from;
for (start, end) in &windows {
assert_eq!(*start, expected_next, "windows must be contiguous");
assert!(end >= start, "window end >= start");
assert!(
end - start < span,
"window span {} exceeds cap {span}",
end - start + 1
);
expected_next = end.saturating_add(1);
}
assert_eq!(
windows.last().map(|w| w.1),
Some(to),
"the final window must reach `to`"
);
}