Files
searchi/crates/searchi-cli/tests/commands.rs
T
karl f77112db97
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
feat: add persistent CPU search engine and CLI with lifecycle tests
2026-10-12 15:51:39 +02:00

91 lines
2.8 KiB
Rust

//! 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"));
}