use std::sync::Mutex;
use clap::Command;
use serde_json::Value;
use tempfile::TempDir;
static CWD_LOCK: Mutex<()> = Mutex::new(());
fn build_cli() -> Command {
Command::new("toolz-cli")
.version("0.0.1")
.subcommand(Command::new("greet").about("Say hi"))
.subcommand(Command::new("status").about("Show status"))
.subcommand(brontes::command(None))
}
fn dispatch(argv: &[&str]) -> brontes::Result<()> {
let cli = build_cli();
let mut full: Vec<&str> = vec!["toolz-cli"];
full.extend_from_slice(argv);
let matches = cli.clone().get_matches_from(full);
let Some(("mcp", sub)) = matches.subcommand() else {
panic!("expected mcp match, got {:?}", matches.subcommand_name());
};
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("runtime");
rt.block_on(brontes::handle(sub, &cli, None))
}
#[test]
fn tools_writes_expected_tool_list_to_cwd() {
let _guard = CWD_LOCK.lock().expect("cwd lock");
let dir = TempDir::new().expect("tempdir");
let prev_cwd = std::env::current_dir().expect("cwd");
std::env::set_current_dir(dir.path()).expect("chdir");
let result = dispatch(&["mcp", "tools"]);
std::env::set_current_dir(prev_cwd).expect("restore cwd");
result.expect("mcp tools succeeds");
let out_path = dir.path().join("mcp-tools.json");
assert!(
out_path.exists(),
"mcp tools must write {} to cwd",
out_path.display()
);
let raw = std::fs::read(&out_path).expect("read mcp-tools.json");
assert!(
raw.ends_with(b"\n"),
"atomic-write helper must append a trailing newline"
);
let tools: Value = serde_json::from_slice(&raw).expect("parse mcp-tools.json");
let names: Vec<&str> = tools
.as_array()
.expect("top-level is array")
.iter()
.map(|t| t["name"].as_str().expect("tool name is string"))
.collect();
assert!(
names.contains(&"toolz-cli_greet"),
"expected toolz-cli_greet in {names:?}"
);
assert!(
names.contains(&"toolz-cli_status"),
"expected toolz-cli_status in {names:?}"
);
assert!(
!names.iter().any(|n| n.contains("mcp_tools")),
"the mcp subtree must not appear as a tool in {names:?}"
);
}
#[test]
fn tools_overwrites_existing_file() {
let _guard = CWD_LOCK.lock().expect("cwd lock");
let dir = TempDir::new().expect("tempdir");
let prev_cwd = std::env::current_dir().expect("cwd");
std::env::set_current_dir(dir.path()).expect("chdir");
let out_path = dir.path().join("mcp-tools.json");
std::fs::write(&out_path, b"stale junk that does not parse as JSON").expect("seed");
let result = dispatch(&["mcp", "tools"]);
std::env::set_current_dir(prev_cwd).expect("restore cwd");
result.expect("mcp tools succeeds on overwrite");
let raw = std::fs::read(&out_path).expect("read mcp-tools.json");
let tools: Value = serde_json::from_slice(&raw).expect("overwrite must produce valid JSON");
assert!(
tools.is_array(),
"overwritten file must parse as a tool-list array"
);
}
#[test]
fn tools_log_level_flag_is_accepted_for_each_recognized_value() {
let _guard = CWD_LOCK.lock().expect("cwd lock");
let dir = TempDir::new().expect("tempdir");
let prev_cwd = std::env::current_dir().expect("cwd");
std::env::set_current_dir(dir.path()).expect("chdir");
for raw in &["trace", "debug", "info", "warn", "warning", "error"] {
let result = dispatch(&["mcp", "tools", "--log-level", raw]);
if let Err(e) = &result {
std::env::set_current_dir(&prev_cwd).expect("restore cwd");
panic!("mcp tools failed with --log-level={raw}: {e}");
}
let out_path = dir.path().join("mcp-tools.json");
assert!(out_path.exists(), "log-level={raw}: file must be written");
let raw_bytes = std::fs::read(&out_path).expect("read");
let _tools: Value = serde_json::from_slice(&raw_bytes)
.unwrap_or_else(|e| panic!("log-level={raw}: invalid JSON: {e}"));
}
std::env::set_current_dir(prev_cwd).expect("restore cwd");
}
#[test]
fn tools_unknown_log_level_does_not_block_export() {
let _guard = CWD_LOCK.lock().expect("cwd lock");
let dir = TempDir::new().expect("tempdir");
let prev_cwd = std::env::current_dir().expect("cwd");
std::env::set_current_dir(dir.path()).expect("chdir");
let result = dispatch(&["mcp", "tools", "--log-level", "nonsense"]);
std::env::set_current_dir(prev_cwd).expect("restore cwd");
result.expect("unknown log-level must not error");
let raw = std::fs::read(dir.path().join("mcp-tools.json")).expect("read");
let _tools: Value = serde_json::from_slice(&raw).expect("valid JSON");
}