use std::path::Path;
use assert_cmd::Command;
use predicates::prelude::*;
fn rigger(data: &Path) -> Command {
let mut cmd = Command::cargo_bin("rigger").unwrap();
cmd.env("RIGGER_DATA_DIR", data);
cmd.env("RIGGER_SKILLS_DIR", data.join("skills"));
cmd
}
fn project(data: &Path) -> std::path::PathBuf {
let root = data.join("sample");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(
root.join("Cargo.toml"),
"[package]\nname = \"sample-cli\"\ndescription = \"A sample product\"\n",
)
.unwrap();
rigger(data).args(["init"]).assert().success();
rigger(data).args(["project", "add"]).arg(&root).assert().success();
let hub = data.join("hub");
std::fs::create_dir_all(&hub).unwrap();
std::fs::write(hub.join("План.md"), "# План\n\n## v0.1.0 · First\n\n- [ ] one\n").unwrap();
std::fs::write(hub.join("Rituals.md"), "Deploy to the box after the tag.\n").unwrap();
rigger(data).args(["import", "sample", "--hub"]).arg(&hub).assert().success();
hub
}
fn output(data: &Path, args: &[&str]) -> String {
let out = rigger(data).args(args).assert().success();
String::from_utf8(out.get_output().stdout.clone()).unwrap()
}
#[test]
fn the_skill_is_printed_from_the_built_in_template_with_the_record_filled_in() {
let data = tempfile::tempdir().unwrap();
let hub = project(data.path());
let out = output(data.path(), &["skill", "sample"]);
assert!(out.starts_with("---\nname: sample\n"), "{out}");
assert!(out.contains("A sample product"), "the manifest's description: {out}");
assert!(out.contains("rigger context sample"), "{out}");
assert!(out.contains("rigger session end sample"), "{out}");
let hub = dunce::canonicalize(&hub).unwrap();
assert!(out.contains(&format!("Hub: {}", hub.display())), "{out}");
assert!(out.contains("<!-- generated by rigger skill"), "{out}");
assert!(!data.path().join("skills").exists());
}
#[test]
fn a_template_in_the_data_directory_is_what_every_skill_follows() {
let data = tempfile::tempdir().unwrap();
project(data.path());
std::fs::write(data.path().join("skill.md"), "# {{name}}\n\n{{file:Rituals.md}}\n").unwrap();
let out = output(data.path(), &["skill", "sample"]);
assert!(out.contains("# sample\n\nDeploy to the box after the tag.\n"), "{out}");
assert!(!out.contains("rigger context"), "the built-in template is not used when one is written: {out}");
}
#[test]
fn install_writes_rewrites_and_leaves_an_unchanged_file_alone() {
let data = tempfile::tempdir().unwrap();
project(data.path());
let path = data.path().join("skills").join("sample").join("SKILL.md");
let out = output(data.path(), &["skill", "sample", "--install"]);
assert!(out.starts_with("Wrote"), "{out}");
assert!(out.contains("the built-in template"), "{out}");
assert!(path.is_file());
let again = output(data.path(), &["skill", "sample", "--install"]);
assert!(again.contains("already what the template says"), "{again}");
std::fs::write(data.path().join("skill.md"), "# {{name}} again\n").unwrap();
let rewritten = output(data.path(), &["skill", "sample", "--install"]);
assert!(rewritten.starts_with("Rewrote"), "{rewritten}");
assert!(std::fs::read_to_string(&path).unwrap().contains("# sample again"));
}
#[test]
fn a_skill_written_by_hand_is_not_replaced_unless_asked() {
let data = tempfile::tempdir().unwrap();
project(data.path());
let dir = data.path().join("skills").join("sample");
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("SKILL.md"), "# sample\n\nSixteen kilobytes of ritual.\n").unwrap();
rigger(data.path())
.args(["skill", "sample", "--install"])
.assert()
.failure()
.stderr(predicate::str::contains("written by hand").and(predicate::str::contains("--replace")));
assert!(std::fs::read_to_string(dir.join("SKILL.md")).unwrap().contains("Sixteen kilobytes"));
output(data.path(), &["skill", "sample", "--install", "--replace"]);
assert!(std::fs::read_to_string(dir.join("SKILL.md")).unwrap().contains("rigger context sample"));
}
#[test]
fn a_placeholder_rigger_does_not_know_is_refused_by_name() {
let data = tempfile::tempdir().unwrap();
project(data.path());
std::fs::write(data.path().join("skill.md"), "{{name}} {{tier}}\n").unwrap();
rigger(data.path())
.args(["skill", "sample"])
.assert()
.failure()
.stderr(predicate::str::contains("{{tier}}").and(predicate::str::contains("file:<name>")));
}
#[test]
fn dir_and_template_are_taken_from_the_command_line() {
let data = tempfile::tempdir().unwrap();
project(data.path());
let template = data.path().join("mine.md");
std::fs::write(&template, "mine: {{name}}\n").unwrap();
let dir = data.path().join("elsewhere");
let out = output(
data.path(),
&["skill", "sample", "--dir", dir.to_str().unwrap(), "--template", template.to_str().unwrap()],
);
assert!(out.contains("mine.md"), "{out}");
let written = std::fs::read_to_string(dir.join("sample").join("SKILL.md")).unwrap();
assert!(written.ends_with("mine: sample\n"), "{written}");
}
#[test]
fn the_built_in_template_can_be_printed_to_start_from() {
let data = tempfile::tempdir().unwrap();
let out = output(data.path(), &["skill", "--print-template"]);
assert!(out.starts_with("---\nname: {{name}}\n"), "{out}");
}