use std::path::PathBuf;
use std::process::Command;
const FIXTURE_SECRETS: &[&str] = &[
"FAKE-TOKEN-DO-NOT-EMIT",
"FAKE-API-SERVER-KEY-DO-NOT-EMIT",
"FAKE-SLACK-BOT-TOKEN-DO-NOT-EMIT",
"FAKE-SLACK-APP-TOKEN-DO-NOT-EMIT",
"FAKE-TELEGRAM-TOKEN-DO-NOT-EMIT",
];
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 command() -> Command {
let fixtures = fixtures();
let mut command = Command::new(bin());
command
.env("HERMES_HOME", fixtures.join("hermes_home"))
.env("OPENCLAW_STATE_DIR", fixtures.join("openclaw_home"));
for var in [
"TELEGRAM_BOT_TOKEN",
"DISCORD_BOT_TOKEN",
"SLACK_BOT_TOKEN",
"SIGNAL_HTTP_URL",
"MATTERMOST_TOKEN",
"MATRIX_ACCESS_TOKEN",
"MATRIX_PASSWORD",
"HASS_TOKEN",
"TWILIO_ACCOUNT_SID",
"GATEWAY_RELAY_URL",
"API_SERVER_KEY",
] {
command.env_remove(var);
}
command
}
fn run(args: &[&str]) -> String {
let output = command()
.args(args)
.output()
.expect("supercode binary runs");
assert!(
output.status.success(),
"`{}` failed: {}",
args.join(" "),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8(output.stdout).unwrap();
for secret in FIXTURE_SECRETS {
assert!(
!stdout.contains(secret),
"`{secret}` leaked into `supercode {}`:\n{stdout}",
args.join(" ")
);
}
stdout
}
fn row<'a>(value: &'a serde_json::Value, harness: &str, name: &str) -> &'a serde_json::Value {
value["channels"]
.as_array()
.expect("channels array")
.iter()
.find(|row| row["harness"] == harness && row["name"] == name)
.unwrap_or_else(|| panic!("no `{harness}` channel `{name}` in {value}"))
}
#[test]
fn channels_list_json_carries_both_harnesses_in_one_row_shape() {
let stdout = run(&["channels", "list", "--json"]);
let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
assert_eq!(value["schema"], "supercode.channels.v1");
let telegram = row(&value, "hermes", "telegram");
assert_eq!(telegram["kind"], "telegram");
assert_eq!(telegram["enabled"], true);
assert_eq!(telegram["configured"], true);
assert_eq!(telegram["sessions"], 2);
let api = row(&value, "hermes", "api_server");
assert_eq!(api["configured"], true);
assert_eq!(api["sessions"], 0);
assert_eq!(row(&value, "hermes", "webhook")["enabled"], false);
let linked = row(&value, "openclaw", "slack/T0FIXTURE");
assert_eq!(linked["kind"], "slack");
assert_eq!(linked["account"], "T0FIXTURE");
assert_eq!(linked["configured"], true);
let unlinked = row(&value, "openclaw", "slack/T1FIXTURE");
assert_eq!(unlinked["enabled"], false);
assert_eq!(unlinked["configured"], false);
assert_eq!(
row(&value, "openclaw", "telegram")["account"],
"hermes-fixture-bot"
);
for row in value["channels"].as_array().unwrap() {
assert_eq!(row["status"], "unknown", "{row}");
}
}
#[test]
fn channels_list_filters_by_harness_and_prints_a_table() {
let stdout = run(&["channels", "list", "--harness", "openclaw"]);
let header = stdout.lines().next().unwrap();
for column in [
"HARNESS", "NAME", "KIND", "ACCOUNT", "ENABLED", "STATUS", "SESSIONS",
] {
assert!(header.contains(column), "missing `{column}` in `{header}`");
}
assert!(stdout.contains("slack/T0FIXTURE"), "{stdout}");
assert!(stdout.contains("T1FIXTURE"), "{stdout}");
assert!(
!stdout.contains("hermes "),
"harness filter leaked: {stdout}"
);
}
#[test]
fn channels_status_reads_one_row() {
let stdout = run(&[
"channels",
"status",
"--harness",
"hermes",
"api_server",
"--json",
]);
let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
assert_eq!(value["schema"], "supercode.channels.v1");
assert_eq!(value["channel"]["name"], "api_server");
assert_eq!(value["channel"]["kind"], "api_server");
assert_eq!(value["channel"]["configured"], true);
assert_eq!(value["channel"]["status"], "unknown");
let human = run(&["channels", "status", "--harness", "hermes", "api_server"]);
assert!(human.contains("configured: yes"), "{human}");
assert!(human.contains("status: unknown"), "{human}");
}
#[test]
fn an_env_only_hermes_platform_is_listed_without_its_value() {
let output = command()
.env("SIGNAL_HTTP_URL", "http://127.0.0.1:65535/env-only-probe")
.args(["channels", "list", "--harness", "hermes", "--json"])
.output()
.unwrap();
assert!(output.status.success());
let stdout = String::from_utf8(output.stdout).unwrap();
let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
let signal = row(&value, "hermes", "signal");
assert_eq!(signal["enabled"], true);
assert_eq!(signal["configured"], true);
assert!(
!stdout.contains("env-only-probe"),
"the env var's VALUE was emitted: {stdout}"
);
}
#[test]
fn unsupported_harness_is_refused() {
for harness in ["claude-code", "codex"] {
let output = command()
.args(["channels", "list", "--harness", harness])
.output()
.unwrap();
assert!(!output.status.success(), "{harness} must be refused");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("has no channel concept"),
"unexpected refusal for {harness}: {stderr}"
);
}
}