mod support;
use std::io::Write;
use std::process::{Command, Stdio};
use support::{assert_tree_equal, fixtures_root, TempDir};
const PRODUCER_BIN: &str = env!("CARGO_BIN_EXE_skillflag");
const INSTALLER_BIN: &str = env!("CARGO_BIN_EXE_skill-install");
#[test]
fn skills_root_env_serves_fixtures_and_excludes_bundled_skill() {
let output = Command::new(PRODUCER_BIN)
.args(["--skill", "list"])
.env("SKILLFLAG_SKILLS_ROOT", fixtures_root())
.output()
.unwrap();
assert!(output.status.success());
assert_eq!(
String::from_utf8(output.stdout).unwrap(),
"alpha\tAlpha test skill\nbeta\tBeta test skill\n"
);
}
#[test]
fn skills_root_env_accepts_multiple_paths() {
let extra = TempDir::new();
support::write_skill_dir(extra.path(), "zzz", "zzz");
let joined = std::env::join_paths([fixtures_root().as_path(), extra.path()]).unwrap();
let output = Command::new(PRODUCER_BIN)
.args(["--skill", "list"])
.env("SKILLFLAG_SKILLS_ROOT", joined)
.output()
.unwrap();
assert!(output.status.success());
assert_eq!(
String::from_utf8(output.stdout).unwrap(),
"alpha\tAlpha test skill\nbeta\tBeta test skill\nzzz\tzzz skill\n"
);
}
#[test]
fn without_skills_root_env_only_the_bundled_skill_is_listed() {
let output = Command::new(PRODUCER_BIN)
.args(["--skill", "list"])
.env_remove("SKILLFLAG_SKILLS_ROOT")
.output()
.unwrap();
assert!(output.status.success());
let stdout = String::from_utf8(output.stdout).unwrap();
assert!(stdout.starts_with("skillflag\t"), "stdout: {stdout}");
assert_eq!(stdout.lines().count(), 1);
}
#[test]
fn direct_action_form_works() {
let output = Command::new(PRODUCER_BIN)
.args(["list", "--json"])
.env("SKILLFLAG_SKILLS_ROOT", fixtures_root())
.output()
.unwrap();
assert!(output.status.success());
let stdout = String::from_utf8(output.stdout).unwrap();
assert!(stdout.starts_with("{\"skillflag_version\":\"0.1\",\"skills\":[{\"id\":\"alpha\""));
assert!(!stdout.ends_with('\n'));
}
#[test]
fn export_pipes_into_installer_round_trip() {
let cwd = TempDir::new();
let producer = Command::new(PRODUCER_BIN)
.args(["--skill", "export", "alpha"])
.env("SKILLFLAG_SKILLS_ROOT", fixtures_root())
.output()
.unwrap();
assert!(producer.status.success());
let tar = producer.stdout;
assert_eq!(tar.len() % 512, 0);
let mut installer = Command::new(INSTALLER_BIN)
.args(["--agent", "codex", "--scope", "repo"])
.current_dir(cwd.path())
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
installer.stdin.take().unwrap().write_all(&tar).unwrap();
let result = installer.wait_with_output().unwrap();
let stderr = String::from_utf8(result.stderr).unwrap();
assert!(result.status.success(), "stderr: {stderr}");
assert!(stderr.starts_with("Installed alpha to "));
let dest = cwd.path().join(".codex").join("skills").join("alpha");
assert_tree_equal(&fixtures_root().join("alpha"), &dest);
}
#[test]
fn producer_install_subcommand_routes_to_installer() {
let cwd = TempDir::new();
let source = fixtures_root().join("alpha");
let output = Command::new(PRODUCER_BIN)
.args([
"install",
source.to_str().unwrap(),
"--agent",
"codex",
"--scope",
"cwd",
])
.current_dir(cwd.path())
.stdin(Stdio::null())
.output()
.unwrap();
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(output.status.success(), "stderr: {stderr}");
let dest = cwd.path().join(".codex").join("skills").join("alpha");
assert_tree_equal(&source, &dest);
}
#[test]
fn unknown_id_exit_code_from_binary() {
let output = Command::new(PRODUCER_BIN)
.args(["--skill", "export", "nope"])
.env("SKILLFLAG_SKILLS_ROOT", fixtures_root())
.output()
.unwrap();
assert_eq!(output.status.code(), Some(1));
assert_eq!(
String::from_utf8(output.stderr).unwrap(),
"Skill not found: nope\n"
);
assert!(output.stdout.is_empty());
}