use std::fs;
use std::process::Command;
use tempfile::tempdir;
fn lantern() -> Command {
Command::new(env!("CARGO_BIN_EXE_lantern"))
}
fn run(mut cmd: Command) -> (String, String, bool) {
let output = cmd.output().expect("failed to run lantern");
(
String::from_utf8_lossy(&output.stdout).into_owned(),
String::from_utf8_lossy(&output.stderr).into_owned(),
output.status.success(),
)
}
#[test]
fn query_subcommand_produces_summary_output() {
let root = tempdir().unwrap();
let store = root.path().join("store");
fs::create_dir_all(root.path().join("data")).unwrap();
let note = root.path().join("data/note.md");
fs::write(¬e, "needle floating in a wider haystack of text").unwrap();
let (_, _, ok) = run({
let mut c = lantern();
c.args(["init", "--path"]).arg(&store);
c
});
assert!(ok, "init failed");
let (_, _, ok) = run({
let mut c = lantern();
c.arg("ingest").arg(¬e).arg("--store").arg(&store);
c
});
assert!(ok, "ingest failed");
let (stdout, _, ok) = run({
let mut c = lantern();
c.arg("query").arg("needle").arg("--store").arg(&store);
c
});
assert!(ok, "query failed");
assert!(
stdout.contains("query: \"needle\""),
"summary header missing: {stdout}"
);
assert!(stdout.contains("hits: 1"), "hit count missing: {stdout}");
assert!(stdout.contains("note.md"), "source path missing: {stdout}");
}
#[test]
fn query_help_advertises_the_higher_default_limit() {
let (stdout, _, ok) = run({
let mut c = lantern();
c.args(["query", "--help"]);
c
});
assert!(ok, "query --help failed");
assert!(
stdout.contains("[default: 20]"),
"expected a default of 20 in help output: {stdout}"
);
}
#[test]
fn query_accepts_the_same_filters_as_search() {
let root = tempdir().unwrap();
let store = root.path().join("store");
let data = root.path().join("data");
fs::create_dir_all(&data).unwrap();
fs::write(data.join("a.md"), "needle in markdown").unwrap();
fs::write(data.join("b.txt"), "needle in plain text").unwrap();
let (_, _, ok) = run({
let mut c = lantern();
c.args(["init", "--path"]).arg(&store);
c
});
assert!(ok);
let (_, _, ok) = run({
let mut c = lantern();
c.arg("ingest").arg(&data).arg("--store").arg(&store);
c
});
assert!(ok);
let (stdout, _, ok) = run({
let mut c = lantern();
c.arg("query")
.arg("needle")
.arg("--store")
.arg(&store)
.args(["--kind", "text/markdown"]);
c
});
assert!(ok);
assert!(stdout.contains("hits: 1"), "kind filter missing: {stdout}");
assert!(stdout.contains("a.md"));
assert!(!stdout.contains("b.txt"));
}
#[test]
fn query_surfaces_jsonl_metadata_in_summary_output() {
let root = tempdir().unwrap();
let store = root.path().join("store");
let (_, _, ok) = run({
let mut c = lantern();
c.args(["init", "--path"]).arg(&store);
c
});
assert!(ok);
let payload = concat!(
"{\"role\":\"assistant\",\"session_id\":\"sess-7\",",
"\"turn_id\":\"turn-9\",\"tool_name\":\"search\",",
"\"timestamp\":1700000003,\"content\":\"needle in a transcript\"}\n"
);
let transcript = root.path().join("data/session.jsonl");
fs::create_dir_all(transcript.parent().unwrap()).unwrap();
fs::write(&transcript, payload).unwrap();
let (_, _, ok) = run({
let mut c = lantern();
c.arg("ingest").arg(&transcript).arg("--store").arg(&store);
c
});
assert!(ok, "jsonl ingest failed");
let (stdout, _, ok) = run({
let mut c = lantern();
c.arg("query").arg("needle").arg("--store").arg(&store);
c
});
assert!(ok, "query failed");
assert!(
stdout.contains("session=sess-7"),
"session metadata missing: {stdout}"
);
assert!(
stdout.contains("turn=turn-9"),
"turn metadata missing: {stdout}"
);
assert!(
stdout.contains("tool=search"),
"tool metadata missing: {stdout}"
);
}