use assert_cmd::Command;
use predicates::prelude::*;
fn harness_cmd() -> Command {
Command::cargo_bin("harness").unwrap()
}
#[test]
fn help_flag_shows_usage() {
harness_cmd()
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Run Claude Code, OpenCode, Codex, or Cursor"));
}
#[test]
fn version_flag() {
harness_cmd()
.arg("--version")
.assert()
.success()
.stdout(predicate::str::contains(env!("CARGO_PKG_VERSION")));
}
#[test]
fn list_command_runs() {
harness_cmd().arg("list").assert().success();
}
#[test]
fn list_command_json() {
harness_cmd()
.args(["list", "--json"])
.assert()
.success()
.stdout(predicate::str::contains("["));
}
#[test]
fn check_unknown_agent_fails() {
harness_cmd()
.args(["check", "nonexistent"])
.assert()
.failure()
.stderr(predicate::str::contains("unknown agent"));
}
#[test]
fn check_accepts_all_agent_names() {
for name in &["claude", "opencode", "codex", "cursor"] {
let result = harness_cmd().args(["check", name]).assert();
let output = result.get_output().clone();
let combined =
String::from_utf8_lossy(&output.stdout).to_string() + &String::from_utf8_lossy(&output.stderr);
assert!(
combined.contains("Claude")
|| combined.contains("OpenCode")
|| combined.contains("Codex")
|| combined.contains("Cursor"),
"Expected agent name in output for {name}, got: {combined}"
);
}
}
#[test]
fn run_rejects_unknown_agent() {
harness_cmd()
.args(["run", "--agent", "foobar", "--prompt", "hello"])
.assert()
.failure()
.stderr(predicate::str::contains("unknown agent"));
}
#[test]
fn run_rejects_unknown_permission_mode() {
harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--permissions", "foobar",
])
.assert()
.failure()
.stderr(predicate::str::contains("unknown permission mode"));
}
#[test]
fn run_rejects_unknown_output_format() {
harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--output", "xml",
])
.assert()
.failure()
.stderr(predicate::str::contains("unknown output format"));
}
#[test]
fn run_accepts_all_permission_modes() {
for mode in &["full-access", "full", "yolo", "default", "read-only", "readonly", "plan"] {
let result = harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--permissions", mode,
])
.assert();
let output = result.get_output().clone();
let combined =
String::from_utf8_lossy(&output.stdout).to_string() + &String::from_utf8_lossy(&output.stderr);
assert!(
!combined.contains("unknown permission mode"),
"Permission mode `{mode}` was rejected: {combined}"
);
}
}
#[test]
fn run_accepts_all_output_formats() {
for fmt in &["text", "json", "stream-json", "markdown"] {
let result = harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--output", fmt,
])
.assert();
let output = result.get_output().clone();
let combined =
String::from_utf8_lossy(&output.stdout).to_string() + &String::from_utf8_lossy(&output.stderr);
assert!(
!combined.contains("unknown output format"),
"Output format `{fmt}` was rejected: {combined}"
);
}
}
#[test]
fn run_invalid_cwd_fails() {
harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--cwd", "/nonexistent/path/abc123",
])
.assert()
.failure();
}
#[test]
fn no_subcommand_shows_help() {
harness_cmd()
.assert()
.failure()
.stderr(predicate::str::contains("Usage"));
}
#[test]
fn dry_run_prints_command_info() {
let result = harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--dry-run",
])
.assert();
let output = result.get_output().clone();
let combined =
String::from_utf8_lossy(&output.stdout).to_string() + &String::from_utf8_lossy(&output.stderr);
assert!(
combined.contains("Binary:") || combined.contains("not found") || combined.contains("error"),
"dry-run produced unexpected output: {combined}"
);
}
#[test]
fn run_accepts_verbose_flag() {
let result = harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--verbose",
"--dry-run",
])
.assert();
let output = result.get_output().clone();
let combined =
String::from_utf8_lossy(&output.stdout).to_string() + &String::from_utf8_lossy(&output.stderr);
assert!(
!combined.contains("unexpected argument"),
"verbose flag was rejected: {combined}"
);
}
#[test]
fn check_diagnose_shows_info() {
let result = harness_cmd()
.args(["check", "claude", "--diagnose"])
.assert();
let output = result.get_output().clone();
let combined =
String::from_utf8_lossy(&output.stdout).to_string() + &String::from_utf8_lossy(&output.stderr);
assert!(
combined.contains("Diagnostics:") || combined.contains("candidates"),
"diagnose should show diagnostic info: {combined}"
);
}
#[test]
fn check_diagnose_json() {
let result = harness_cmd()
.args(["check", "claude", "--diagnose", "--json"])
.assert();
let output = result.get_output().clone();
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("diagnostics"),
"JSON diagnose should have diagnostics key: {stdout}"
);
}
#[test]
fn models_subcommand_help() {
harness_cmd()
.args(["models", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("model registry"));
}
#[test]
fn models_list_runs() {
harness_cmd()
.args(["models", "list"])
.assert()
.success();
}
#[test]
fn models_path_runs() {
harness_cmd()
.args(["models", "path"])
.assert()
.success()
.stdout(predicate::str::contains("models.toml"));
}
#[test]
fn run_accepts_output_file_flag() {
let tmp = tempfile::NamedTempFile::new().unwrap();
let result = harness_cmd()
.args([
"run",
"--agent", "claude",
"--prompt", "hello",
"--output-file",
tmp.path().to_str().unwrap(),
"--dry-run",
])
.assert();
let output = result.get_output().clone();
let combined =
String::from_utf8_lossy(&output.stdout).to_string() + &String::from_utf8_lossy(&output.stderr);
assert!(
combined.contains("Binary:") || combined.contains("not found") || combined.contains("error"),
"output-file flag produced unexpected output: {combined}"
);
}