use super::CodeIndexer;
use crate::core::chunker::{ChunkType, RawChunk};
use crate::core::corpus::CorpusStore;
use std::sync::Arc;
fn raw(id: &str) -> RawChunk {
RawChunk {
id: id.to_string(),
file: "f.rs".to_string(),
start_line: 1,
end_line: 1,
content: "fn x() {}".to_string(),
function_name: None,
language: Some("rust".to_string()),
chunk_type: ChunkType::Code,
calls: Vec::new(),
inherits_from: Vec::new(),
chunk_depth: 0,
parent_chunk_id: None,
child_chunk_ids: Vec::new(),
nlp_keywords: Vec::new(),
nlp_code_refs: Vec::new(),
virtual_terms: Vec::new(),
}
}
#[tokio::test]
async fn test_enumerate_chunks_after_cursor_in_memory_fallback() {
let idx = CodeIndexer::new("cursor-mem", "/tmp/cursor-mem");
for id in ["a:1:1", "b:1:1", "c:1:1", "d:1:1", "e:1:1"] {
idx.add_chunk(raw(id)).await.unwrap();
}
let mut seen: Vec<String> = Vec::new();
let mut cursor: Option<String> = None;
let mut pages = 0;
loop {
let (total, page, next) = idx.enumerate_chunks_after(cursor.as_deref(), 2).await;
assert_eq!(total, 5, "total chunk count is stable across pages");
for c in &page {
seen.push(c.id.clone());
}
pages += 1;
match next {
Some(c) => cursor = Some(c),
None => break,
}
assert!(pages < 10, "pagination must terminate");
}
assert_eq!(seen, vec!["a:1:1", "b:1:1", "c:1:1", "d:1:1", "e:1:1"]);
let (total_z, z, next_z) = idx.enumerate_chunks_after(None, 0).await;
assert_eq!(total_z, 5);
assert!(z.is_empty());
assert!(next_z.is_none());
}
#[tokio::test]
async fn test_enumerate_chunks_after_cursor_pages_via_redb() {
let dir = tempfile::tempdir().unwrap();
let redb_path = dir.path().join("index.redb");
let mut idx = CodeIndexer::new("cursor-redb", "/tmp/cursor-redb");
idx.set_corpus_store(Arc::new(
CorpusStore::open(&redb_path).expect("open corpus"),
));
idx.index_files_batch(&[
("src/a.rs".into(), "fn a_one() {}\nfn a_two() {}".into()),
("src/b.rs".into(), "fn b_one() {}".into()),
("src/c.rs".into(), "fn c_one() {}".into()),
])
.await
.expect("index batch");
let total_chunks = idx.chunk_count();
assert!(
total_chunks >= 3,
"expected >= 3 chunks, got {total_chunks}"
);
let mut seen: Vec<String> = Vec::new();
let mut cursor: Option<String> = None;
let mut pages = 0;
loop {
let (total, page, next) = idx.enumerate_chunks_after(cursor.as_deref(), 2).await;
assert_eq!(total, total_chunks, "total is the redb chunk_count");
for c in &page {
seen.push(c.id.clone());
}
pages += 1;
match next {
Some(c) => cursor = Some(c),
None => break,
}
assert!(pages < 1000, "pagination must terminate");
}
assert_eq!(
seen.len(),
total_chunks,
"every chunk returned exactly once"
);
let mut sorted = seen.clone();
sorted.sort();
assert_eq!(seen, sorted, "redb cursor pages in ascending id order");
sorted.dedup();
assert_eq!(sorted.len(), seen.len(), "no chunk returned twice");
}