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
91 lines
2.8 KiB
Rust
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"));
|
|
}
|