use strobemers_rs::{MinStrobes, RandStrobes};
const SEQS: [&str; 5] = [
"ACGATCTGGTACCTAG",
"ACGTACGTACGTACGTACGTACGT",
"TTGACCTGATCGATCGGGCTTATCAGCTTACGGATCAGCTTAGCATCG",
"AAAAAAAAAAAAAAAAAAAA",
"ACGATCTGGTACCTAGTTGACCTGATCGATCGGGCTTATCAGCTTACGGATCAGCTTAGCATCGAAGGCTTACGCT",
];
const WINDOWS: [(usize, usize); 8] = [
(1, 1),
(1, 4),
(2, 5),
(3, 5),
(4, 4),
(1, 10),
(5, 9),
(7, 7),
];
fn assert_exact<I: Iterator<Item = u64>>(mut it: I, label: &str) {
let total = it.size_hint();
assert_eq!(
total.1,
Some(total.0),
"upper bound must be present and equal to the lower bound ({label})"
);
let mut seen = 0usize;
loop {
let hint = it.size_hint();
assert_eq!(
hint.1,
Some(hint.0),
"upper bound diverged after {seen} items ({label})"
);
assert_eq!(
hint.0 + seen,
total.0,
"remaining + consumed must stay constant after {seen} items ({label})"
);
if it.next().is_none() {
break;
}
seen += 1;
}
assert_eq!(
seen, total.0,
"size_hint promised {} items, iterator produced {seen} ({label})",
total.0
);
}
#[test]
fn size_hint_is_exact() {
let mut checked = 0usize;
for seq in SEQS {
for n in [2u8, 3] {
for l in [2usize, 3, 5, 7] {
for (w_min, w_max) in WINDOWS {
for shrink in [true, false] {
let label = format!(
"len={} n={n} l={l} w=({w_min},{w_max}) shrink={shrink}",
seq.len()
);
if let Ok(mut it) = RandStrobes::new(seq.as_bytes(), n, l, w_min, w_max) {
it.set_window_shrink(shrink);
assert_exact(it, &format!("RandStrobes {label}"));
checked += 1;
}
if let Ok(mut it) = MinStrobes::new(seq.as_bytes(), n, l, w_min, w_max) {
it.set_window_shrink(shrink);
assert_exact(it, &format!("MinStrobes {label}"));
checked += 1;
}
}
}
}
}
}
assert!(
checked > 1000,
"expected broad coverage, only checked {checked}"
);
}
#[test]
fn exact_size_len_matches_output() {
let seq: &[u8] =
b"ACGATCTGGTACCTAGTTGACCTGATCGATCGGGCTTATCAGCTTACGGATCAGCTTAGCATCGAAGGCTTACGCT";
for n in [2u8, 3] {
for (w_min, w_max) in [(1usize, 4usize), (3, 5), (5, 9)] {
let rs = RandStrobes::new(seq, n, 5, w_min, w_max).unwrap();
let len = rs.len();
assert_eq!(len, rs.count(), "RandStrobes n={n} w=({w_min},{w_max})");
let ms = MinStrobes::new(seq, n, 5, w_min, w_max).unwrap();
let len = ms.len();
assert_eq!(len, ms.count(), "MinStrobes n={n} w=({w_min},{w_max})");
}
}
}
#[test]
fn size_hint_zero_when_nothing_fits() {
let seq: &[u8] = b"ACGTACGTACGTACG";
assert_eq!(
RandStrobes::new(seq, 2, 10, 1, 2).unwrap().size_hint(),
(0, Some(0))
);
assert_eq!(
MinStrobes::new(seq, 2, 10, 1, 2).unwrap().size_hint(),
(0, Some(0))
);
let short: &[u8] = b"ACGATCTGGTAC"; let mut rs = RandStrobes::new(short, 3, 3, 2, 5).unwrap();
rs.set_window_shrink(false);
assert_eq!(rs.size_hint(), (0, Some(0)));
assert_eq!(rs.count(), 0);
let mut ms = MinStrobes::new(short, 3, 3, 2, 5).unwrap();
ms.set_window_shrink(false);
assert_eq!(ms.size_hint(), (0, Some(0)));
assert_eq!(ms.count(), 0);
let rs = RandStrobes::new(short, 3, 3, 2, 5).unwrap();
assert_eq!(rs.len(), 3);
assert_eq!(rs.count(), 3);
}