use std::path::{Path, PathBuf};
use std::process::Command;
fn bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_supercode"))
}
fn fixtures() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../harness/tests/fixtures")
.canonicalize()
.unwrap()
}
fn run(args: &[&str]) -> String {
let fixtures = fixtures();
let output = Command::new(bin())
.env("HERMES_HOME", fixtures.join("hermes_home"))
.env("OPENCLAW_STATE_DIR", fixtures.join("openclaw_home"))
.args(args)
.output()
.expect("supercode binary runs");
assert!(
output.status.success(),
"`{}` failed: {}",
args.join(" "),
String::from_utf8_lossy(&output.stderr)
);
String::from_utf8(output.stdout).unwrap()
}
fn row<'a>(value: &'a serde_json::Value, harness: &str, name: &str) -> &'a serde_json::Value {
value["profiles"]
.as_array()
.expect("profiles array")
.iter()
.find(|row| row["harness"] == harness && row["name"] == name)
.unwrap_or_else(|| panic!("no `{harness}` profile `{name}` in {value}"))
}
#[test]
fn profiles_list_json_carries_every_source_in_one_row_shape() {
let stdout = run(&["profiles", "list", "--json"]);
let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
assert_eq!(value["schema"], "supercode.profiles.v1");
let preset = row(&value, "supercode", "supercode-default");
assert_eq!(preset["kind"], "preset");
assert_eq!(preset["default"], true);
assert_eq!(preset["home"], serde_json::Value::Null);
let default = row(&value, "hermes", "default");
assert_eq!(default["kind"], "hermes_profile");
assert_eq!(default["default"], true);
assert_eq!(default["sessions"], 11);
let coder = row(&value, "hermes", "coder");
assert_eq!(coder["routes"], 1);
assert_eq!(coder["sessions"], 1);
assert_eq!(coder["model"], "anthropic/claude-opus-4-8");
assert!(Path::new(coder["home"].as_str().unwrap()).is_dir());
let main = row(&value, "openclaw", "main");
assert_eq!(main["kind"], "openclaw_agent");
assert_eq!(main["default"], true);
assert_eq!(main["sessions"], 4);
let design = row(&value, "openclaw", "design");
assert_eq!(design["routes"], 1);
assert_eq!(design["sessions"], 0);
}
#[test]
fn profiles_list_filters_by_harness_and_prints_a_table() {
let stdout = run(&["profiles", "list", "--harness", "openclaw"]);
let header = stdout.lines().next().unwrap();
for column in ["HARNESS", "NAME", "KIND", "DEFAULT", "ROUTES", "SESSIONS"] {
assert!(header.contains(column), "missing `{column}` in `{header}`");
}
let cells = |name: &str| {
stdout.lines().any(|line| {
line.starts_with("openclaw") && line.split_whitespace().nth(1) == Some(name)
})
};
assert!(cells("design"), "{stdout}");
assert!(cells("main"), "{stdout}");
assert!(
!stdout.contains("hermes"),
"harness filter leaked: {stdout}"
);
}
#[test]
fn profiles_show_reads_one_row() {
let stdout = run(&["profiles", "show", "--harness", "hermes", "coder", "--json"]);
let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
assert_eq!(value["schema"], "supercode.profiles.v1");
assert_eq!(value["profile"]["name"], "coder");
assert_eq!(value["profile"]["kind"], "hermes_profile");
assert_eq!(value["profile"]["routes"], 1);
}
#[test]
fn unsupported_harness_is_refused() {
let output = Command::new(bin())
.args(["profiles", "list", "--harness", "claude-code"])
.output()
.unwrap();
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("has no profile concept"),
"unexpected refusal: {stderr}"
);
}