use std::path::PathBuf;
use std::process::{Command, Output};
fn bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_supercode"))
}
fn scratch(tag: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"supercode-orch9-{tag}-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn run(args: &[&str]) -> Output {
let home = scratch("home");
let output = Command::new(bin())
.env("SUPERCODE_HOME", home.join("sessions"))
.env("HOME", &home)
.env("NO_COLOR", "1")
.env_remove("OPENROUTER_API_KEY")
.args(args)
.stdin(std::process::Stdio::null())
.output()
.expect("supercode binary runs");
let _ = std::fs::remove_dir_all(&home);
output
}
fn stdout(args: &[&str]) -> String {
let output = run(args);
assert!(
output.status.success(),
"`supercode {}` failed: {}",
args.join(" "),
String::from_utf8_lossy(&output.stderr)
);
String::from_utf8(output.stdout).unwrap()
}
#[test]
fn approvals_list_json_is_the_rpc_row_array() {
let rows: Vec<serde_json::Value> =
serde_json::from_str(&stdout(&["approvals", "list", "--json"]))
.expect("approvals list --json is a JSON array");
assert!(rows.is_empty(), "{rows:#?}");
let filtered: Vec<serde_json::Value> = serde_json::from_str(&stdout(&[
"approvals",
"list",
"--harness",
"hermes",
"--session",
"some-session",
"--json",
]))
.expect("a filtered listing is a JSON array");
assert!(filtered.is_empty(), "{filtered:#?}");
}
#[test]
fn approvals_list_table_names_where_a_live_request_lives() {
let table = stdout(&["approvals", "list"]);
assert!(table.contains("no approval request is waiting"), "{table}");
assert!(table.contains("harness.v1.approvals.list"), "{table}");
}
#[test]
fn approvals_list_refuses_a_harness_that_cannot_carry_a_request() {
for harness in ["claude-code", "notaharness"] {
let output = run(&["approvals", "list", "--harness", harness]);
assert!(!output.status.success(), "{harness} should be refused");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains(harness), "{stderr}");
assert!(stderr.contains("unsupported action"), "{stderr}");
assert!(stderr.contains("hermes"), "{stderr}");
}
}
#[test]
fn approvals_resolve_takes_only_the_three_uniform_decisions() {
let output = run(&["approvals", "resolve", "runtime-1/7", "maybe"]);
assert!(!output.status.success(), "an invented decision is refused");
let stderr = String::from_utf8_lossy(&output.stderr);
for decision in ["allow-once", "allow-always", "deny"] {
assert!(stderr.contains(decision), "{stderr}");
}
}
#[test]
fn approvals_resolve_refuses_a_row_this_process_is_not_holding() {
for decision in ["allow-once", "allow-always", "deny"] {
let output = run(&["approvals", "resolve", "runtime-1/7", decision]);
assert!(
!output.status.success(),
"resolving a row nobody holds must fail"
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("runtime-1/7"), "{stderr}");
assert!(stderr.contains("only inside the process"), "{stderr}");
}
}
#[test]
fn approvals_resolve_names_the_door_for_a_queued_subagent_row() {
let output = run(&[
"approvals",
"resolve",
"supercode/subagent/child-1/100/0",
"deny",
]);
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("queued subagent record"), "{stderr}");
assert!(stderr.contains("supercode runtime"), "{stderr}");
}
#[test]
fn approvals_help_advertises_both_verbs() {
let help = stdout(&["approvals", "--help"]);
assert!(help.contains("list"), "{help}");
assert!(help.contains("resolve"), "{help}");
}