#![allow(clippy::disallowed_methods)]
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
fn cli() -> Command {
Command::cargo_bin("trueno-rag").unwrap()
}
#[test]
fn test_info_shows_version() {
cli()
.arg("info")
.assert()
.success()
.stdout(predicate::str::contains("Trueno-RAG Pipeline"))
.stdout(predicate::str::contains("Version:"));
}
#[test]
fn test_info_shows_components() {
cli()
.arg("info")
.assert()
.success()
.stdout(predicate::str::contains("Chunkers:"))
.stdout(predicate::str::contains("Embedders:"))
.stdout(predicate::str::contains("TF-IDF"));
}
#[test]
fn test_demo_default_query() {
cli()
.arg("demo")
.assert()
.success()
.stdout(predicate::str::contains("Trueno-RAG Demo"))
.stdout(predicate::str::contains("Indexed"))
.stdout(predicate::str::contains("Results"));
}
#[test]
fn test_demo_custom_query() {
cli()
.args(["demo", "--query", "What is deep learning?"])
.assert()
.success()
.stdout(predicate::str::contains("What is deep learning?"));
}
#[test]
fn test_demo_custom_top_k() {
cli()
.args(["demo", "--top-k", "2"])
.assert()
.success()
.stdout(predicate::str::contains("Results (2)").or(predicate::str::contains("Results (")));
}
#[test]
fn test_demo_shows_citations() {
cli()
.arg("demo")
.assert()
.success()
.stdout(predicate::str::contains("Citations:"));
}
#[test]
fn test_index_single_file() {
let tmp = TempDir::new().unwrap();
let doc_path = tmp.path().join("test.txt");
fs::write(&doc_path, "This is a test document about machine learning.").unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
doc_path.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
])
.assert()
.success()
.stdout(predicate::str::contains("Indexed"));
assert!(index_path.exists(), "Index directory should be created");
}
#[test]
fn test_index_directory() {
let tmp = TempDir::new().unwrap();
let docs_dir = tmp.path().join("docs");
fs::create_dir(&docs_dir).unwrap();
fs::write(docs_dir.join("doc1.txt"), "First document about AI.").unwrap();
fs::write(docs_dir.join("doc2.txt"), "Second document about ML.").unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
docs_dir.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
])
.assert()
.success()
.stdout(predicate::str::contains("2 documents"));
}
#[test]
fn test_index_with_chunk_size() {
let tmp = TempDir::new().unwrap();
let doc_path = tmp.path().join("test.txt");
fs::write(&doc_path, "A ".repeat(500)).unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
doc_path.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
"--chunk-size",
"100",
])
.assert()
.success()
.stdout(predicate::str::contains("chunks"));
}
#[test]
fn test_index_nonexistent_path_fails() {
cli()
.args([
"index",
"--path",
"/nonexistent/path",
"--output",
"/tmp/out",
])
.assert()
.failure()
.stderr(predicate::str::contains("not found").or(predicate::str::contains("No such file")));
}
#[test]
fn test_query_requires_index() {
let tmp = TempDir::new().unwrap();
let index_path = tmp.path().join("nonexistent_index");
cli()
.args([
"query",
"test query",
"--index",
index_path.to_str().unwrap(),
])
.assert()
.failure()
.stderr(predicate::str::contains("index").or(predicate::str::contains("not found")));
}
#[test]
fn test_query_with_index() {
let tmp = TempDir::new().unwrap();
let doc_path = tmp.path().join("test.txt");
fs::write(
&doc_path,
"Machine learning is a field of artificial intelligence.",
)
.unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
doc_path.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
])
.assert()
.success();
cli()
.args([
"query",
"What is machine learning?",
"--index",
index_path.to_str().unwrap(),
])
.assert()
.success()
.stdout(predicate::str::contains("Results"));
}
#[test]
fn test_query_json_output() {
let tmp = TempDir::new().unwrap();
let doc_path = tmp.path().join("test.txt");
fs::write(&doc_path, "Test document content.").unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
doc_path.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
])
.assert()
.success();
cli()
.args([
"query",
"test",
"--index",
index_path.to_str().unwrap(),
"--format",
"json",
])
.assert()
.success()
.stdout(predicate::str::contains("{").and(predicate::str::contains("}")));
}
#[test]
fn test_query_top_k() {
let tmp = TempDir::new().unwrap();
let docs_dir = tmp.path().join("docs");
fs::create_dir(&docs_dir).unwrap();
for i in 0..5 {
fs::write(
docs_dir.join(format!("doc{i}.txt")),
format!("Document {i} content."),
)
.unwrap();
}
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
docs_dir.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
])
.assert()
.success();
cli()
.args([
"query",
"document",
"--index",
index_path.to_str().unwrap(),
"--top-k",
"2",
])
.assert()
.success();
}
#[test]
fn test_transcribe_dry_run_no_media() {
let tmp = TempDir::new().unwrap();
cli()
.args([
"transcribe",
"--path",
tmp.path().to_str().unwrap(),
"--dry-run",
])
.assert()
.success()
.stdout(predicate::str::contains("No media files found"));
}
#[test]
fn test_transcribe_dry_run_with_media() {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("lecture.mp4"), b"").unwrap();
fs::write(tmp.path().join("talk.wav"), b"").unwrap();
cli()
.args([
"transcribe",
"--path",
tmp.path().to_str().unwrap(),
"--dry-run",
])
.assert()
.success()
.stdout(predicate::str::contains("2 media files"))
.stdout(predicate::str::contains("2 need transcription"))
.stdout(predicate::str::contains("lecture.mp4"))
.stdout(predicate::str::contains("talk.wav"));
}
#[test]
fn test_transcribe_skips_existing_sidecars() {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("lecture.mp4"), b"").unwrap();
fs::write(
tmp.path().join("lecture.srt"),
"1\n00:00:01,000 --> 00:00:05,000\nHello.\n",
)
.unwrap();
fs::write(tmp.path().join("talk.wav"), b"").unwrap();
cli()
.args([
"transcribe",
"--path",
tmp.path().to_str().unwrap(),
"--dry-run",
])
.assert()
.success()
.stdout(predicate::str::contains("1 with .srt/.vtt"))
.stdout(predicate::str::contains("1 need transcription"))
.stdout(predicate::str::contains("talk.wav"));
}
#[test]
fn test_transcribe_all_have_sidecars() {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("lecture.mp4"), b"").unwrap();
fs::write(
tmp.path().join("lecture.srt"),
"1\n00:00:01,000 --> 00:00:05,000\nHello.\n",
)
.unwrap();
cli()
.args([
"transcribe",
"--path",
tmp.path().to_str().unwrap(),
"--dry-run",
])
.assert()
.success()
.stdout(predicate::str::contains("Nothing to do"));
}
#[test]
fn test_transcribe_nonexistent_path() {
cli()
.args(["transcribe", "--path", "/nonexistent/path", "--dry-run"])
.assert()
.failure()
.stderr(predicate::str::contains("not found"));
}
#[test]
fn test_transcribe_help() {
cli()
.args(["transcribe", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("Batch transcribe"));
}
#[test]
fn test_transcribe_backend_flag() {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("lecture.wav"), b"").unwrap();
cli()
.args([
"transcribe",
"--path",
tmp.path().to_str().unwrap(),
"--backend",
"gpu",
"--dry-run",
])
.assert()
.success()
.stdout(predicate::str::contains("1 media files"));
}
#[test]
fn test_index_with_manifest() {
let tmp = TempDir::new().unwrap();
let doc_path = tmp.path().join("test.txt");
fs::write(&doc_path, "This is a test document about machine learning.").unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
doc_path.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
"--manifest",
])
.assert()
.success()
.stdout(predicate::str::contains("Manifest saved to"));
let manifest_file = index_path.join("manifest.json");
assert!(manifest_file.exists(), "Manifest file should exist");
let manifest: serde_json::Value =
serde_json::from_str(&fs::read_to_string(&manifest_file).unwrap()).unwrap();
assert_eq!(manifest["file_count"], 1);
assert!(manifest["chunk_count"].as_u64().unwrap() >= 1);
assert!(manifest["files"].is_array());
}
#[test]
#[cfg(feature = "sqlite")]
fn test_index_with_sqlite_flag() {
let tmp = TempDir::new().unwrap();
let docs_dir = tmp.path().join("docs");
fs::create_dir(&docs_dir).unwrap();
fs::write(
docs_dir.join("doc1.txt"),
"First document about Rust programming.",
)
.unwrap();
fs::write(
docs_dir.join("doc2.txt"),
"Second document about Python scripting.",
)
.unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
docs_dir.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
"--sqlite",
])
.assert()
.success()
.stdout(predicate::str::contains("SQLite index saved to"))
.stdout(predicate::str::contains("2 docs"));
assert!(index_path.join("index.json").exists());
assert!(index_path.join("index.sqlite").exists());
}
#[test]
#[cfg(feature = "sqlite")]
fn test_index_sqlite_with_dedup() {
let tmp = TempDir::new().unwrap();
let docs_dir = tmp.path().join("docs");
fs::create_dir(&docs_dir).unwrap();
fs::write(docs_dir.join("a.txt"), "Identical content here.").unwrap();
fs::write(docs_dir.join("b.txt"), "Identical content here.").unwrap(); fs::write(docs_dir.join("c.txt"), "Unique content about SIMD.").unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
docs_dir.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
"--sqlite",
"--dedup",
])
.assert()
.success()
.stdout(predicate::str::contains("SQLite index saved to"));
assert!(index_path.join("index.sqlite").exists());
}
#[test]
fn test_index_parallel_jobs() {
let tmp = TempDir::new().unwrap();
let docs_dir = tmp.path().join("docs");
fs::create_dir(&docs_dir).unwrap();
fs::write(docs_dir.join("doc1.txt"), "First document about AI.").unwrap();
fs::write(docs_dir.join("doc2.txt"), "Second document about ML.").unwrap();
fs::write(docs_dir.join("doc3.txt"), "Third document about NLP.").unwrap();
let index_path = tmp.path().join("index");
cli()
.args([
"index",
"--path",
docs_dir.to_str().unwrap(),
"--output",
index_path.to_str().unwrap(),
"--jobs",
"2",
])
.assert()
.success()
.stdout(predicate::str::contains("Loading with 2 parallel jobs"))
.stdout(predicate::str::contains("3 documents"));
}
#[test]
fn test_help() {
cli()
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Pure-Rust RAG pipeline CLI"));
}
#[test]
fn test_version() {
cli()
.arg("--version")
.assert()
.success()
.stdout(predicate::str::contains("trueno-rag"));
}
#[test]
fn test_subcommand_help() {
cli()
.args(["index", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("Index documents"));
}