feat: add persistent CPU search engine and CLI with lifecycle tests
Core CI / core (ubuntu-latest) (push) Successful in 1m0s
Core CI / core (macos-latest) (push) Canceled after 0s
Core CI / core (windows-latest) (push) Canceled after 0s
Core CI / core (ubuntu-latest) (push) Successful in 1m0s
Core CI / core (macos-latest) (push) Canceled after 0s
Core CI / core (windows-latest) (push) Canceled after 0s
This commit is contained in:
1 parent
aae803771c
commit
f77112db97
19 files changed
+1688
No files matched your search
@@ -0,0 +1,90 @@
|
||||
//! Exercise the executable boundary: exit status, durable indexing, and JSON.
|
||||
use std::{
|
||||
fs,
|
||||
path::PathBuf,
|
||||
process::{Command, Output},
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
struct Fixture(PathBuf);
|
||||
|
||||
impl Fixture {
|
||||
fn new() -> Self {
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
"searchi-cli-test-{}-{}",
|
||||
std::process::id(),
|
||||
NEXT_ID.fetch_add(1, Ordering::Relaxed)
|
||||
));
|
||||
fs::create_dir(&path).unwrap();
|
||||
Self(path)
|
||||
}
|
||||
|
||||
fn run(&self, args: &[&str]) -> Output {
|
||||
Command::new(env!("CARGO_BIN_EXE_searchi"))
|
||||
.current_dir(&self.0)
|
||||
.args(args)
|
||||
.output()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Fixture {
|
||||
fn drop(&mut self) {
|
||||
let _ = fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indexes_persists_and_returns_search_and_stats_json() {
|
||||
let fixture = Fixture::new();
|
||||
fs::create_dir(fixture.0.join("documents")).unwrap();
|
||||
fs::write(
|
||||
fixture.0.join("documents/contract.txt"),
|
||||
"Supplier termination clause requires sixty days notice.",
|
||||
)
|
||||
.unwrap();
|
||||
let indexed = fixture.run(&["index", "--db", "index.db", "--root", "documents"]);
|
||||
assert!(
|
||||
indexed.status.success(),
|
||||
"{}",
|
||||
String::from_utf8_lossy(&indexed.stderr)
|
||||
);
|
||||
|
||||
// Each command is a new process, so retrieval proves the index survived exit.
|
||||
let searched = fixture.run(&["search", "--db", "index.db", "termination", "--json"]);
|
||||
assert!(
|
||||
searched.status.success(),
|
||||
"{}",
|
||||
String::from_utf8_lossy(&searched.stderr)
|
||||
);
|
||||
let results: serde_json::Value = serde_json::from_slice(&searched.stdout).unwrap();
|
||||
let results = results.as_array().unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0]["filename"], "contract.txt");
|
||||
assert!(results[0]["snippet"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("termination"));
|
||||
|
||||
let stats = fixture.run(&["stats", "--db", "index.db", "--json"]);
|
||||
assert!(stats.status.success());
|
||||
let stats: serde_json::Value = serde_json::from_slice(&stats.stdout).unwrap();
|
||||
assert_eq!(stats["files"], 1);
|
||||
assert_eq!(stats["content_files"], 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errors_are_nonzero_and_missing_database_is_not_created() {
|
||||
let fixture = Fixture::new();
|
||||
let missing = fixture.run(&["search", "--db", "missing.db", "invoice", "--json"]);
|
||||
assert!(!missing.status.success());
|
||||
assert!(String::from_utf8_lossy(&missing.stderr).contains("does not exist"));
|
||||
assert!(!fixture.0.join("missing.db").exists());
|
||||
assert!(missing.stdout.is_empty());
|
||||
|
||||
let bad_root = fixture.run(&["index", "--db", "index.db", "--root", "missing-folder"]);
|
||||
assert!(!bad_root.status.success());
|
||||
assert!(String::from_utf8_lossy(&bad_root.stderr).contains("missing-folder"));
|
||||
}
|
||||
Reference in new issue
Block a user