use super::*;
use tempfile::tempdir;
fn host(program: &str) -> Cli {
Cli::new(program)
}
#[test]
fn shim_script_reexecs_the_clis_own_words_and_forwards_argv() {
let cli = Cli::resolve_with(
crate::cli_outbound::Binary::Bl,
|_| None,
Some(PathBuf::from("/opt/yog/bin/yog")),
);
let script = shim_script(BL, &cli.exec_words());
assert!(script.starts_with("#!/bin/sh\n"), "{script}");
assert!(
script.ends_with("exec '/opt/yog/bin/yog' 'bl' \"$@\"\n"),
"{script}"
);
let script = shim_script(BL, &host("/usr/bin/bl").exec_words());
assert!(script.ends_with("exec '/usr/bin/bl' \"$@\"\n"), "{script}");
}
#[test]
fn shim_script_quotes_a_path_with_spaces_and_quotes() {
let script = shim_script(BL, &host("/we ird/yo'g").exec_words());
assert!(
script.ends_with("exec '/we ird/yo'\\''g' \"$@\"\n"),
"{script}"
);
}
#[test]
fn ensure_shim_creates_the_tree_and_marks_it_executable() {
let dir = tempdir().unwrap();
let tools = dir.path().join("world").join("tools");
let path = ensure_shim(&tools, BL, &host("/usr/bin/bl")).unwrap();
assert_eq!(path, tools.join(BL));
assert_eq!(
fs::read_to_string(&path).unwrap(),
shim_script(BL, &host("/usr/bin/bl").exec_words())
);
let mode = fs::metadata(&path).unwrap().permissions().mode();
assert_eq!(mode & 0o777, SHIM_MODE);
}
#[test]
fn ensure_shim_leaves_an_identical_file_untouched_but_rewrites_drift() {
let dir = tempdir().unwrap();
let tools = dir.path().to_path_buf();
let path = ensure_shim(&tools, BL, &host("/usr/bin/bl")).unwrap();
let first = fs::metadata(&path).unwrap().modified().unwrap();
ensure_shim(&tools, BL, &host("/usr/bin/bl")).unwrap();
assert_eq!(fs::metadata(&path).unwrap().modified().unwrap(), first);
ensure_shim(&tools, BL, &host("/opt/bl")).unwrap();
assert_eq!(
fs::read_to_string(&path).unwrap(),
shim_script(BL, &host("/opt/bl").exec_words())
);
fs::write(&path, "#!/bin/sh\nexit 7\n").unwrap();
ensure_shim(&tools, BL, &host("/opt/bl")).unwrap();
assert_eq!(
fs::read_to_string(&path).unwrap(),
shim_script(BL, &host("/opt/bl").exec_words())
);
}
#[test]
fn ensure_shim_refuses_a_target_that_is_not_an_absolute_path() {
let dir = tempdir().unwrap();
let tools = dir.path().join("tools");
let good = ensure_shim(&tools, BL, &host("/opt/yog/bin/yog")).unwrap();
let before = fs::read_to_string(&good).unwrap();
let err = ensure_shim(&tools, BL, &host("bl")).unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::NotFound);
assert!(err.to_string().contains("absolute path"), "{err}");
assert_eq!(fs::read_to_string(&good).unwrap(), before);
let empty = dir.path().join("empty");
ensure_shim(&empty, BL, &Cli::new("")).unwrap_err();
assert!(!empty.join(BL).exists());
}
#[test]
fn the_seeded_shim_runs_and_passes_argv_through_verbatim() {
let dir = tempdir().unwrap();
let target = dir.path().join("fake yog");
let log = dir.path().join("argv");
fs::write(
&target,
format!(
"#!/bin/sh\nprintf '%s\\n' \"$@\" > '{}'\nexit 3\n",
log.display()
),
)
.unwrap();
fs::set_permissions(&target, fs::Permissions::from_mode(SHIM_MODE)).unwrap();
let tools = dir.path().join("tools");
let shim = ensure_shim(&tools, BL, &host(target.to_string_lossy().as_ref())).unwrap();
let out = crate::git_env::output(crate::git_env::command(&shim).args([
"close",
"bl-1a2b",
"-m",
"two words",
]))
.unwrap();
assert_eq!(out.status.code(), Some(3));
assert_eq!(
fs::read_to_string(&log).unwrap(),
"close\nbl-1a2b\n-m\ntwo words\n"
);
}
#[test]
fn ensure_tools_converges_every_roster_shim() {
let dir = tempdir().unwrap();
let tools = dir.path().join("world").join("tools");
ensure_tools(&tools).unwrap();
for (namespace, binary) in ROSTER {
let path = tools.join(namespace);
assert_eq!(
fs::read_to_string(&path).unwrap(),
shim_script(namespace, &Cli::resolve(binary).exec_words()),
"{namespace}"
);
let mode = fs::metadata(&path).unwrap().permissions().mode();
assert_eq!(mode & 0o777, SHIM_MODE, "{namespace}");
}
let yog_shim = fs::read_to_string(tools.join(YOG)).unwrap();
assert!(
!yog_shim.contains("' yog \"$@\""),
"no verb word in yog's own shim: {yog_shim}"
);
assert!(
yog_shim.contains("\"$@\""),
"argv passes through: {yog_shim}"
);
let stamp = fs::metadata(tools.join(BL)).unwrap().modified().unwrap();
ensure_tools(&tools).unwrap();
assert_eq!(
fs::metadata(tools.join(BL)).unwrap().modified().unwrap(),
stamp
);
}
#[test]
fn prepend_path_puts_the_tools_dir_first_and_is_idempotent() {
let tools = Path::new("/d/yog/world/tools");
assert_eq!(
prepend_path(tools, Some("/usr/bin:/bin".to_owned())),
"/d/yog/world/tools:/usr/bin:/bin"
);
let once = prepend_path(tools, Some("/usr/bin".to_owned()));
assert_eq!(prepend_path(tools, Some(once.clone())), once);
assert_eq!(prepend_path(tools, None), "/d/yog/world/tools");
assert_eq!(
prepend_path(tools, Some(String::new())),
"/d/yog/world/tools"
);
assert_eq!(
prepend_path(tools, Some("/d/yog/world/tools-old:/bin".to_owned())),
"/d/yog/world/tools:/d/yog/world/tools-old:/bin"
);
}
#[test]
fn the_capability_control_shim_is_seeded_where_the_authored_block_names_it() {
let dir = tempdir().unwrap();
let tools = dir.path().join("tools");
let seeded = ensure_control(&tools).unwrap();
assert_eq!(seeded, control_path(&tools));
assert!(seeded.is_absolute(), "the block must not be PATH-resolved");
assert_eq!(
fs::read_to_string(&seeded).unwrap(),
shim_script(
TOOL_CONTROL,
&Cli::resolve(crate::cli_outbound::Binary::ToolControl).exec_words()
)
);
}
#[test]
fn seed_converges_the_world_tools_dir_and_warns_when_it_cannot() {
let root = tempfile::tempdir().unwrap();
let world_root = root.path().join("ok");
let ambient = crate::test_support::world_under(&world_root);
seed(&ambient);
assert!(
crate::world::layout(&ambient).tools.join("bl").exists(),
"the world's `PATH` names this dir unconditionally, so seeding it is the world's own act"
);
let blocked_root = root.path().join("blocked");
let blocked = crate::test_support::world_under(&blocked_root);
let tools = crate::world::layout(&blocked).tools;
std::fs::create_dir_all(tools.parent().unwrap()).unwrap();
std::fs::write(&tools, b"not a directory").unwrap();
seed(&blocked);
assert!(tools.is_file(), "it said so and left the world alone");
}