use znippy_common::chunkrevolver::{CONFIG, ChunkRevolver};
#[test]
fn test_chunk_revolver_basic_usage() {
let mut config = CONFIG.clone();
config.max_core_in_flight = 4; config.max_chunks = 16; config.file_split_block_size = 1024 * 1024;
let mut revolver = ChunkRevolver::new(&config);
let mut seen = std::collections::HashSet::new();
let mut all_chunks = Vec::new();
for _ in 0..config.max_chunks {
let chunk = revolver.try_get_chunk().expect("Expected available chunk");
let key = (chunk.ring_nr, chunk.index);
assert!(seen.insert(key), "Duplicate chunk detected: {:?}", key);
all_chunks.push((chunk.ring_nr, chunk.index));
}
assert!(
revolver.try_get_chunk().is_none(),
"Should be exhausted after {} chunks",
config.max_chunks
);
for (ring_nr, index) in &all_chunks {
revolver.return_chunk(*ring_nr, *index);
}
let mut second_seen = std::collections::HashSet::new();
for _ in 0..config.max_chunks {
let chunk = revolver
.try_get_chunk()
.expect("Expected chunk after return");
let key = (chunk.ring_nr, chunk.index);
assert!(second_seen.insert(key), "Duplicate on reuse: {:?}", key);
}
}
#[test]
fn test_chunk_revolver_two_passes() {
use znippy_common::chunkrevolver::ChunkRevolver;
use znippy_common::common_config::StrategicConfig;
let mut config = CONFIG.clone();
config.max_chunks = 32;
config.max_core_in_flight = 4;
config.file_split_block_size = 1024 * 1024;
let mut revolver = ChunkRevolver::new(&config);
let mut all_chunks = Vec::new();
while let Some(chunk) = revolver.try_get_chunk() {
all_chunks.push((chunk.ring_nr, chunk.index));
}
let total = all_chunks.len();
assert_eq!(
total, config.max_chunks as usize,
"Första varvet borde hämta alla chunkar"
);
for (ring, index) in &all_chunks {
revolver.return_chunk(*ring, *index);
}
let mut second_pass = Vec::new();
while let Some(chunk) = revolver.try_get_chunk() {
second_pass.push((chunk.ring_nr, chunk.index));
}
assert_eq!(
second_pass.len(),
total,
"Andra varvet borde ge lika många chunkar"
);
let set1: std::collections::HashSet<_> = all_chunks.iter().cloned().collect();
let set2: std::collections::HashSet<_> = second_pass.iter().cloned().collect();
assert_eq!(
set1, set2,
"Chunkarna som återanvänds ska vara identiska mellan varven"
);
}
#[test]
fn test_no_duplicate_without_return() {
use std::collections::HashSet;
use znippy_common::chunkrevolver::ChunkRevolver;
use znippy_common::common_config::StrategicConfig;
let mut config = CONFIG.clone();
config.max_chunks = 64;
config.max_core_in_flight = 4;
config.file_split_block_size = 1024 * 1024;
let mut revolver = ChunkRevolver::new(&config);
let mut seen = HashSet::new();
let mut count = 0;
while let Some(chunk) = revolver.try_get_chunk() {
let key = (chunk.ring_nr, chunk.index);
assert!(
seen.insert(key),
"🔴 Chunk already seen: ring={} index={}",
chunk.ring_nr,
chunk.index
);
count += 1;
}
assert_eq!(
count, config.max_chunks as usize,
"Should get exactly max_chunks before exhaustion"
);
let chunk = revolver.try_get_chunk();
assert!(
chunk.is_none(),
"🔴 Expected None after exhausting all chunks, but got Some"
);
}
#[test]
#[should_panic(expected = "Chunk already seen")]
fn test_duplicate_chunk_without_return_is_detected() {
use std::collections::HashSet;
use znippy_common::chunkrevolver::ChunkRevolver;
use znippy_common::common_config::StrategicConfig;
let mut config = CONFIG.clone();
config.max_chunks = 8;
config.max_core_in_flight = 2;
config.file_split_block_size = 1024 * 1024;
let mut revolver = ChunkRevolver::new(&config);
let mut seen = HashSet::new();
let mut saved_chunk = None;
for i in 0..config.max_chunks {
let chunk = revolver.try_get_chunk().expect("Expected chunk");
let key = (chunk.ring_nr, chunk.index);
assert!(
seen.insert(key),
"🔴 Chunk already seen: ring={} index={}",
chunk.ring_nr,
chunk.index
);
if i == 3 {
saved_chunk = Some(key);
}
}
if let Some(dupe) = saved_chunk {
assert!(
seen.insert(dupe),
"🔴 Chunk already seen: ring={} index={}",
dupe.0,
dupe.1
);
}
}
#[test]
fn test_chunk_does_not_overlap_without_return() {
use std::collections::HashSet;
use znippy_common::chunkrevolver::ChunkRevolver;
use znippy_common::common_config::StrategicConfig;
let mut config = CONFIG.clone();
config.max_chunks = 8;
config.max_core_in_flight = 2;
config.file_split_block_size = 1024 * 1024;
let mut revolver = ChunkRevolver::new(&config);
let mut seen = HashSet::new();
for i in 0..config.max_chunks {
let chunk = revolver
.try_get_chunk()
.expect("Expected unique chunk before exhaustion");
let key = (chunk.ring_nr, chunk.index);
assert!(
seen.insert(key),
"🧨 Overlap detected: chunk reused without return at iteration {}: ring={} index={}",
i,
chunk.ring_nr,
chunk.index
);
}
let chunk = revolver.try_get_chunk();
assert!(
chunk.is_none(),
"🧨 Overlap: expected None after exhaustion, got Some(...)"
);
}
#[test]
fn test_no_duplicate_chunks_without_return() {
use std::collections::HashSet;
use znippy_common::chunkrevolver::ChunkRevolver;
use znippy_common::common_config::CONFIG;
let mut config = CONFIG.clone();
config.max_chunks = 8; config.max_core_in_flight = 2;
config.file_split_block_size = 1024 * 1024;
let mut revolver = ChunkRevolver::new(&config);
let mut seen = HashSet::new();
let mut count = 0;
while let Some(chunk) = revolver.try_get_chunk() {
let key = (chunk.ring_nr, chunk.index);
assert!(
seen.insert(key),
"Duplicate chunk detected: ring {}, index {}",
chunk.ring_nr,
chunk.index
);
count += 1;
}
assert_eq!(
count, config.max_chunks,
"Expected to get exactly {} unique chunks",
config.max_chunks
);
}