use assert_cmd::Command;
use std::fs;
#[test]
fn new_skill_creates_skill_md_with_minimum_frontmatter() {
let tmp = tempfile::tempdir().unwrap();
Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["new", "skill", "code-review"])
.assert()
.success();
let path = tmp.path().join("skills/code-review/SKILL.md");
assert!(path.is_file(), "{path:?} should exist");
let body = fs::read_to_string(&path).unwrap();
assert!(body.starts_with("---\n"), "{body}");
assert!(body.contains("\nschema: 1\n"), "{body}");
assert!(body.contains("\nname: code-review\n"), "{body}");
assert!(body.contains("description:"), "{body}");
}
#[test]
fn new_rule_creates_rule_md() {
let tmp = tempfile::tempdir().unwrap();
Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["new", "rule", "license-awareness"])
.assert()
.success();
let path = tmp.path().join("rules/license-awareness/RULE.md");
assert!(path.is_file());
let body = fs::read_to_string(&path).unwrap();
assert!(body.contains("\nname: license-awareness\n"), "{body}");
}
#[test]
fn new_agent_emits_default_mode_and_model() {
let tmp = tempfile::tempdir().unwrap();
Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["new", "agent", "security-reviewer"])
.assert()
.success();
let body = fs::read_to_string(tmp.path().join("agents/security-reviewer/AGENT.md")).unwrap();
assert!(body.contains("\nmode: subagent\n"), "{body}");
assert!(body.contains("\nmodel: sonnet\n"), "{body}");
}
#[test]
fn new_refuses_existing_item_directory() {
let tmp = tempfile::tempdir().unwrap();
fs::create_dir_all(tmp.path().join("skills/dup")).unwrap();
fs::write(tmp.path().join("skills/dup/SKILL.md"), "old").unwrap();
let assert = Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["new", "skill", "dup"])
.assert()
.failure()
.code(1);
let stderr = String::from_utf8(assert.get_output().stderr.clone()).unwrap();
assert!(stderr.contains("already exists"), "{stderr}");
assert_eq!(
fs::read_to_string(tmp.path().join("skills/dup/SKILL.md")).unwrap(),
"old"
);
}
#[test]
fn new_rejects_invalid_name() {
let tmp = tempfile::tempdir().unwrap();
let assert = Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["new", "skill", "Invalid_Name"])
.assert()
.failure();
let stderr = String::from_utf8(assert.get_output().stderr.clone()).unwrap();
assert!(
stderr.contains("name") || stderr.contains("invalid"),
"{stderr}"
);
}
#[test]
fn new_refuses_to_run_inside_consumer_project() {
let tmp = tempfile::tempdir().unwrap();
fs::write(
tmp.path().join(".upskill-lock.json"),
r#"{"schema":2,"items":[]}"#,
)
.unwrap();
let assert = Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["new", "skill", "anything"])
.assert()
.failure()
.code(2);
let stderr = String::from_utf8(assert.get_output().stderr.clone()).unwrap();
assert!(
stderr.contains("consumer project") || stderr.contains(".upskill-lock.json"),
"{stderr}"
);
}
#[test]
fn new_output_passes_lint_and_fmt() {
let tmp = tempfile::tempdir().unwrap();
for (kind, name) in [
("skill", "starter-skill"),
("rule", "starter-rule"),
("agent", "starter-agent"),
] {
Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["new", kind, name])
.assert()
.success();
}
Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["lint", "--strict"])
.assert()
.success();
let assert = Command::cargo_bin("upskill")
.unwrap()
.current_dir(tmp.path())
.args(["fmt"])
.assert()
.success();
let out = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
assert!(
out.contains("all formatted"),
"scaffold not canonical: {out}"
);
}