Files
searchi/crates/searchi-core/tests/index_options.rs
T

138 lines
4.9 KiB
Rust

use anyhow::Result;
use searchi_core::{IndexOptions, SearchIndex, SearchOptions};
use std::fs;
#[test]
fn exclusions_database_and_unchanged_metadata() -> Result<()> {
let root = tempfile::tempdir()?;
for directory in [".git", "node_modules", "target", "private"] {
fs::create_dir(root.path().join(directory))?;
fs::write(root.path().join(directory).join("hidden.txt"), "secret")?;
}
fs::write(root.path().join("visible.txt"), "original content")?;
let mut index = SearchIndex::open(root.path().join("index.db"))?;
let options = IndexOptions {
excluded_paths: Vec::new(),
excluded_directory_names: vec![
".git".into(),
"node_modules".into(),
"target".into(),
"private".into(),
],
};
assert_eq!(
index
.index_folder_with_options(root.path(), &options)?
.indexed,
1
);
assert_eq!(index.stats()?.files, 1);
let unchanged = index.index_folder_with_options(root.path(), &options)?;
assert_eq!(unchanged.unchanged, 1);
assert_eq!(unchanged.indexed, 0);
assert!(index.search("secret", 10)?.is_empty());
assert!(index.search("index.db", 10)?.is_empty());
fs::write(
root.path().join("visible.txt"),
"changed and longer content",
)?;
assert_eq!(
index
.index_folder_with_options(root.path(), &options)?
.indexed,
1
);
assert!(index.search("original", 10)?.is_empty());
assert_eq!(index.search("changed", 10)?.len(), 1);
// A new exclusion removes previously indexed entries from this root.
let mut options = IndexOptions::default();
index.index_folder_with_options(root.path(), &options)?;
assert_eq!(index.search("secret", 10)?.len(), 1);
options.excluded_directory_names.push("private".into());
assert_eq!(
index
.index_folder_with_options(root.path(), &options)?
.removed,
1
);
Ok(())
}
#[test]
fn filters_apply_before_limit_and_respect_folder_boundaries() -> Result<()> {
let root = tempfile::tempdir()?;
let docs = root.path().join("docs");
let sibling = root.path().join("docs-more");
fs::create_dir(&docs)?;
fs::create_dir(&sibling)?;
fs::write(docs.join("shared.md"), "shared short")?;
fs::write(docs.join("shared.txt"), "shared considerably longer")?;
fs::write(sibling.join("shared.md"), "shared sibling")?;
let mut index = SearchIndex::open(":memory:")?;
index.index_folder(root.path())?;
let options = SearchOptions {
folder: Some(docs),
extension: Some(".MD".into()),
max_size: Some(15),
..Default::default()
};
let results = index.search_with_options("shared", 1, &options)?;
assert_eq!(results.len(), 1);
assert_eq!(results[0].filename, "shared.md");
assert!(!results[0].path.contains("docs-more"));
let options = SearchOptions {
min_size: Some(20),
..Default::default()
};
assert_eq!(index.search_with_options("shared", 10, &options)?.len(), 1);
let options = SearchOptions {
modified_before_unix_ms: Some(0),
..Default::default()
};
assert!(index
.search_with_options("shared", 10, &options)?
.is_empty());
let options = SearchOptions {
min_size: Some(20),
max_size: Some(10),
..Default::default()
};
assert!(index.search_with_options("shared", 10, &options).is_err());
Ok(())
}
#[test]
fn migrates_v1_database_without_losing_search_records() -> Result<()> {
let root = tempfile::tempdir()?;
let db = root.path().join("legacy.db");
let connection = rusqlite::Connection::open(&db)?;
connection.execute_batch(
"CREATE TABLE files(id INTEGER PRIMARY KEY, path TEXT NOT NULL UNIQUE,
root TEXT NOT NULL, filename TEXT NOT NULL, content TEXT NOT NULL);
PRAGMA user_version=1;",
)?;
drop(connection);
let mut index = SearchIndex::open(&db)?;
fs::write(root.path().join("sample.txt"), "migration evidence")?;
index.index_folder(root.path())?;
assert_eq!(index.search("evidence", 10)?.len(), 1);
Ok(())
}
#[test]
fn readers_open_and_search_during_uncommitted_writer() -> Result<()> {
let root = tempfile::tempdir()?;
let db = root.path().join("index.db");
fs::write(root.path().join("notes.txt"), "committed evidence")?;
let mut index = SearchIndex::open(&db)?;
index.index_folder(root.path())?;
let writer = rusqlite::Connection::open(&db)?;
writer.execute_batch("BEGIN IMMEDIATE; UPDATE files SET content='uncommitted replacement';")?;
// Opening a current schema must not issue DDL or acquire a write lock.
let reader = SearchIndex::open(&db)?;
assert_eq!(reader.search("evidence", 10)?.len(), 1);
assert!(reader.search("replacement", 10)?.is_empty());
writer.execute_batch("ROLLBACK;")?;
Ok(())
}