use ix::builder::Builder;
use ix::executor::{Executor, QueryOptions};
use ix::planner::Planner;
use ix::reader::Reader;
use std::fs;
use tempfile::tempdir;
#[test]
fn test_edge_case_file_sizes() {
let dir = tempdir().unwrap();
let root = dir.path();
fs::write(root.join("empty.txt"), "").unwrap();
fs::write(root.join("one.txt"), "a").unwrap();
fs::write(root.join("two.txt"), "ab").unwrap();
fs::write(root.join("three.txt"), "abc").unwrap();
fs::write(root.join("four.txt"), "abcd").unwrap();
let mut builder = Builder::new(root).unwrap();
builder.build().unwrap();
let index_path = root.join(".ix/shard.ix");
let reader = Reader::open(&index_path).unwrap();
let executor = Executor::new(&reader);
let plan = Planner::plan("abc", false);
let (matches, _) = executor.execute(&plan, &QueryOptions::default()).unwrap();
assert_eq!(matches.len(), 2);
let names: Vec<_> = matches
.iter()
.map(|m| m.file_path.file_name().unwrap().to_str().unwrap())
.collect();
assert!(names.contains(&"three.txt"));
assert!(names.contains(&"four.txt"));
}
#[test]
fn test_repetitive_data_explosion() {
let dir = tempdir().unwrap();
let root = dir.path();
let content = "abc\n".repeat(1000);
fs::write(root.join("repetitive.txt"), content).unwrap();
let mut builder = Builder::new(root).unwrap();
builder.build().unwrap();
let index_path = root.join(".ix/shard.ix");
let reader = Reader::open(&index_path).unwrap();
let executor = Executor::new(&reader);
let plan = Planner::plan("abc", false);
let (matches, stats) = executor
.execute(
&plan,
&QueryOptions {
max_results: 100,
..Default::default()
},
)
.unwrap();
assert_eq!(matches.len(), 100);
assert_eq!(stats.total_matches, 100);
let (matches_default, _) = executor.execute(&plan, &QueryOptions::default()).unwrap();
assert_eq!(matches_default.len(), 1000);
}
#[test]
fn test_context_merging_logic() {
let dir = tempdir().unwrap();
let root = dir.path();
fs::write(
root.join("context.txt"),
"match\nmatch\nmatch\nother\nother\nmatch",
)
.unwrap();
let mut builder = Builder::new(root).unwrap();
builder.build().unwrap();
let index_path = root.join(".ix/shard.ix");
let reader = Reader::open(&index_path).unwrap();
let executor = Executor::new(&reader);
let plan = Planner::plan("match", false);
let (matches, _) = executor
.execute(
&plan,
&QueryOptions {
context_lines: 1,
..Default::default()
},
)
.unwrap();
assert_eq!(matches.len(), 4);
assert_eq!(matches[0].context_before.len(), 0);
assert_eq!(matches[0].context_after, vec!["match".to_string()]);
assert_eq!(matches[1].context_before, vec!["match".to_string()]);
assert_eq!(matches[1].context_after, vec!["match".to_string()]);
}
#[test]
fn test_type_filtering_robustness() {
let dir = tempdir().unwrap();
let root = dir.path();
fs::write(root.join("file.rs"), "findme").unwrap();
fs::write(root.join("file.py"), "findme").unwrap();
fs::write(root.join("file.txt"), "findme").unwrap();
let mut builder = Builder::new(root).unwrap();
builder.build().unwrap();
let index_path = root.join(".ix/shard.ix");
let reader = Reader::open(&index_path).unwrap();
let executor = Executor::new(&reader);
let plan = Planner::plan("findme", false);
let (matches, _) = executor
.execute(
&plan,
&QueryOptions {
type_filter: vec!["rs".to_string()],
..Default::default()
},
)
.unwrap();
assert_eq!(matches.len(), 1);
assert!(matches[0].file_path.to_str().unwrap().ends_with(".rs"));
let (matches, _) = executor
.execute(
&plan,
&QueryOptions {
type_filter: vec!["rs".to_string(), "py".to_string()],
..Default::default()
},
)
.unwrap();
assert_eq!(matches.len(), 2);
}
#[test]
fn test_large_file_streaming() {
let dir = tempdir().unwrap();
let root = dir.path();
let line = "This is a normal line with a pattern inside it.\n";
let count = (10 * 1024 * 1024) / line.len();
let content = line.repeat(count);
let file_path = root.join("large.txt");
fs::write(&file_path, content).unwrap();
let mut builder = Builder::new(root).unwrap();
builder.build().unwrap();
let index_path = root.join(".ix/shard.ix");
let reader = Reader::open(&index_path).unwrap();
let executor = Executor::new(&reader);
let plan = Planner::plan("pattern", false);
let options = QueryOptions {
max_results: 10,
..Default::default()
};
let (matches, stats) = executor.execute(&plan, &options).unwrap();
assert_eq!(matches.len(), 10);
assert!(stats.files_verified >= 1);
}