repositories / smith
smith
There are many coding harnesses - but this one is fast
owned by admin
smith-cli/tests/e2e_sessions.rs
Raw//! Read-only inspection through the built binary (`SMH-SPEC-SPEC0001`, Session inspection).
use assert_cmd::Command;
use serde_json::Value;
use std::path::Path;
fn smith(home: &Path, args: &[&str]) -> std::process::Output {
Command::cargo_bin("smith")
.unwrap()
.env("XDG_DATA_HOME", home)
.env_remove("SMITH_PROVIDER")
.env_remove("SMITH_MODEL")
.env_remove("SMITH_BASE_URL")
.env_remove("OPENAI_API_KEY")
.env_remove("ANTHROPIC_API_KEY")
.env_remove("GEMINI_API_KEY")
.args(args)
.timeout(std::time::Duration::from_secs(30))
.output()
.unwrap()
}
#[test]
fn session_list_limit_reports_capacity_not_corruption() {
// Create real sessions through eval; inspection must reject capacity without claiming damage.
let home = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../target/style-exec")
.join(format!("list-limit-e2e-{}", std::process::id()));
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(120);
for _ in 0..1025 {
assert!(
std::time::Instant::now() < deadline,
"session fixture deadline"
);
let created = smith(&home, &["eval", "--mock", "fixture"]);
assert!(
created.status.success(),
"{}",
String::from_utf8_lossy(&created.stderr)
);
}
let listed = smith(&home, &["sessions", "list", "--json"]);
assert!(!listed.status.success());
let diagnostic = String::from_utf8(listed.stderr).unwrap();
assert!(diagnostic.contains("SESSION_LIST_LIMIT"));
assert!(diagnostic.contains("inspect sessions individually"));
assert!(!diagnostic.contains("SESSION_CORRUPT"));
let records = String::from_utf8(listed.stdout).unwrap();
assert_eq!(records.lines().count(), 1024);
assert!(
records
.lines()
.all(|line| serde_json::from_str::<Value>(line).is_ok())
);
std::fs::remove_dir_all(home).unwrap();
}
#[test]
fn sessions_list_get_grep_jsonl_and_no_match() {
let home = std::env::temp_dir().join(format!("smith-sessions-e2e-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&home);
assert!(
smith(&home, &["eval", "--mock", "needle \u{1b}[31m in haystack"])
.status
.success()
);
assert!(
smith(&home, &["eval", "--mock", "other haystack"])
.status
.success()
);
let listed = smith(&home, &["sessions", "list", "--json"]);
assert!(
listed.status.success(),
"{}",
String::from_utf8_lossy(&listed.stderr)
);
let listed = String::from_utf8(listed.stdout).unwrap();
let lines: Vec<Value> = listed
.lines()
.map(|line| serde_json::from_str(line).unwrap())
.collect();
assert_eq!(lines.len(), 2);
let id = lines[0]["session"].as_str().unwrap();
let human_list = smith(&home, &["sessions", "list"]);
assert!(human_list.status.success());
let (mut json_bytes, mut human_bytes) = (String::new(), String::new());
for line in &lines {
let (session, bytes) = (line["session"].as_str().unwrap(), &line["bytes"]);
json_bytes += &format!("{{\"session\":\"{session}\",\"bytes\":{bytes}}}\n");
human_bytes += &format!("{session} {bytes} bytes\n");
}
assert_eq!(listed, json_bytes, "JSON list lines keep their exact bytes");
assert_eq!(
String::from_utf8(human_list.stdout).unwrap(),
human_bytes,
"human list lines keep their exact bytes"
);
let retrieved = smith(&home, &["sessions", "get", id, "--json"]);
assert!(
retrieved.status.success(),
"{}",
String::from_utf8_lossy(&retrieved.stderr)
);
let records: Vec<Value> = String::from_utf8(retrieved.stdout)
.unwrap()
.lines()
.map(|line| serde_json::from_str(line).unwrap())
.collect();
assert_eq!(records.len(), 2);
assert!(
records
.iter()
.all(|record| record["content"]["kind"] == "Message")
);
assert!(
records
.iter()
.all(|record| record["content"]["data"]["blocks"][0]["type"] == "Text")
);
assert!(
records
.iter()
.all(|record| record["content"]["data"]["blocks"][0]["data"].is_string())
);
let human_get = smith(&home, &["sessions", "get", id]);
assert!(human_get.status.success());
assert!(!human_get.stdout.contains(&0x1b));
let matches = smith(&home, &["sessions", "grep", "needle", "--json"]);
assert!(
matches.status.success(),
"{}",
String::from_utf8_lossy(&matches.stderr)
);
let found: Vec<Value> = String::from_utf8(matches.stdout)
.unwrap()
.lines()
.map(|line| serde_json::from_str(line).unwrap())
.collect();
assert_eq!(found.len(), 1);
assert!(found[0]["entry"].is_string());
assert_eq!(
found[0]["content"]["data"]["blocks"][0]["data"],
"needle \u{1b}[31m in haystack"
);
let human_grep = smith(&home, &["sessions", "grep", "needle"]);
assert!(human_grep.status.success());
assert!(
String::from_utf8(human_grep.stdout)
.unwrap()
.contains("needle")
);
let none = smith(&home, &["sessions", "grep", "not-in-any-session"]);
assert_eq!(none.status.code(), Some(1));
assert!(none.stdout.is_empty());
assert!(none.stderr.is_empty());
let _ = std::fs::remove_dir_all(home);
}
#[test]
fn corrupt_session_is_reported_without_repairing_source() {
// SMH-SPEC-SPEC0001: Session inspection never repairs or hides corruption.
let home = std::env::temp_dir().join(format!("smith-corrupt-e2e-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&home);
assert!(smith(&home, &["eval", "--mock", "before"]).status.success());
let dir = home.join("smith/sessions/run");
let path = std::fs::read_dir(&dir)
.unwrap()
.map(|entry| entry.unwrap().path())
.find(|path| path.extension().is_some_and(|ext| ext == "smh"))
.unwrap();
let mut bytes = std::fs::read(&path).unwrap();
let last = bytes.len() - 1;
bytes[last] ^= 0xff;
std::fs::write(&path, &bytes).unwrap();
let id = path.file_stem().unwrap().to_str().unwrap();
let output = smith(&home, &["sessions", "get", id]);
assert_eq!(output.status.code(), Some(2));
assert!(String::from_utf8_lossy(&output.stderr).contains("SESSION_CORRUPT"));
assert_eq!(std::fs::read(path).unwrap(), bytes);
let _ = std::fs::remove_dir_all(home);
}