use super::*;
use crate::hooks::Hooks;
use std::fs;
use std::path::Path;
use tempfile::TempDir;
fn xdg_at(root: &Path) -> Xdg {
Xdg::with(root, Some(&root.join("cfg").to_string_lossy()), Some(&root.join("state").to_string_lossy()))
}
fn exe_dir_with(root: &Path, names: &[&str]) -> std::path::PathBuf {
let dir = root.join("bin");
fs::create_dir_all(&dir).unwrap();
for name in names {
fs::write(dir.join(name), "#!/bin/sh\n").unwrap();
}
dir
}
fn bin_link(landing: &Path, name: &str) -> std::path::PathBuf {
landing.join("config/plugins/bin").join(name)
}
#[test]
fn seed_writes_the_embedded_default_then_copies_and_binds_present_plugins() {
let tmp = TempDir::new().unwrap();
let xdg = xdg_at(tmp.path());
let landing = tmp.path().join("landing");
let exe = exe_dir_with(tmp.path(), &["tracker", "bl-delivery"]);
seed_landing(&xdg, &landing, Some(&exe)).unwrap();
assert!(xdg.default_config().join("balls.toml").is_file());
assert!(xdg.default_config().join("plugins.toml").is_file());
assert!(landing.join("config/balls.toml").is_file());
let hooks = Hooks::load(&landing).unwrap();
assert_eq!(hooks.names("close", "post"), ["bl-delivery", "tracker"]);
assert!(bin_link(&landing, "tracker").symlink_metadata().is_ok());
assert!(bin_link(&landing, "bl-delivery").symlink_metadata().is_ok());
assert!(hooks.names("claim", "pre").is_empty());
assert!(hooks.names("unclaim", "pre").is_empty());
assert_eq!(hooks.resolve_read(&crate::registry::Registry::at(&landing), "show").len(), 1);
}
#[test]
fn seed_prunes_a_plugin_whose_binary_is_absent_here() {
let tmp = TempDir::new().unwrap();
let xdg = xdg_at(tmp.path());
let landing = tmp.path().join("landing");
let exe = exe_dir_with(tmp.path(), &["tracker"]);
seed_landing(&xdg, &landing, Some(&exe)).unwrap();
let hooks = Hooks::load(&landing).unwrap();
assert_eq!(hooks.names("close", "post"), ["tracker"]); assert!(hooks.names("close", "pre").is_empty()); assert!(bin_link(&landing, "tracker").symlink_metadata().is_ok());
assert!(bin_link(&landing, "bl-delivery").symlink_metadata().is_err());
}
#[test]
fn seed_with_no_exe_dir_prunes_every_plugin() {
let tmp = TempDir::new().unwrap();
let xdg = xdg_at(tmp.path());
let landing = tmp.path().join("landing");
seed_landing(&xdg, &landing, None).unwrap();
let hooks = Hooks::load(&landing).unwrap();
assert!(hooks.names("prime", "pre").is_empty());
assert!(!landing.join("config/plugins/bin").exists());
assert!(landing.join("config/balls.toml").is_file());
}
#[test]
fn an_xdg_override_wins_over_the_embedded_default() {
let tmp = TempDir::new().unwrap();
let xdg = xdg_at(tmp.path());
let dc = xdg.default_config();
fs::create_dir_all(&dc).unwrap();
fs::write(dc.join("balls.toml"), "tasks_branch = \"team/tasks\"\n").unwrap();
fs::write(dc.join("plugins.toml"), "[hooks]\n\"close.post\" = [\"tracker\"]\n").unwrap();
let landing = tmp.path().join("landing");
let exe = exe_dir_with(tmp.path(), &["tracker", "bl-delivery"]);
seed_landing(&xdg, &landing, Some(&exe)).unwrap();
assert!(fs::read_to_string(landing.join("config/balls.toml")).unwrap().contains("team/tasks"));
let hooks = Hooks::load(&landing).unwrap();
assert_eq!(hooks.names("close", "post"), ["tracker"]); assert!(hooks.names("prime", "pre").is_empty()); }
#[test]
fn an_override_missing_a_file_seeds_only_what_it_has() {
let tmp = TempDir::new().unwrap();
let xdg = xdg_at(tmp.path());
let dc = xdg.default_config();
fs::create_dir_all(&dc).unwrap();
fs::write(dc.join("plugins.toml"), "[hooks]\n\"create.post\" = [\"tracker\"]\n").unwrap();
let landing = tmp.path().join("landing");
let exe = exe_dir_with(tmp.path(), &["tracker"]);
seed_landing(&xdg, &landing, Some(&exe)).unwrap();
assert!(!landing.join("config/balls.toml").exists());
assert_eq!(Hooks::load(&landing).unwrap().names("create", "post"), ["tracker"]);
}
#[test]
fn rebind_reestablishes_present_bindings_without_touching_the_schedule() {
let tmp = TempDir::new().unwrap();
let landing = tmp.path().join("landing");
let config = landing.join("config");
fs::create_dir_all(&config).unwrap();
let schedule = "[hooks]\n\"close.post\" = [\"bl-delivery\", \"tracker\"]\n";
fs::write(config.join("plugins.toml"), schedule).unwrap();
let exe = exe_dir_with(tmp.path(), &["tracker"]);
rebind(&landing, Some(&exe)).unwrap();
assert!(bin_link(&landing, "tracker").symlink_metadata().is_ok());
assert!(bin_link(&landing, "bl-delivery").symlink_metadata().is_err());
assert_eq!(fs::read_to_string(config.join("plugins.toml")).unwrap(), schedule);
}