use super::{by_leaf, leaf, name_of, resolve};
use std::path::{Path, PathBuf};
fn set(paths: &[&str]) -> Vec<PathBuf> {
paths.iter().map(PathBuf::from).collect()
}
#[test]
fn a_workspace_is_named_by_its_leaf() {
assert_eq!(leaf(Path::new("/d/yog/workspaces/home")), "home");
assert_eq!(
leaf(Path::new("/d/litany/workspaces/20260727T093000Z-f0reign")),
"20260727T093000Z-f0reign"
);
}
#[test]
fn a_rootless_path_names_nothing() {
assert_eq!(leaf(Path::new("")), "");
}
#[test]
fn by_leaf_is_the_inverse() {
let s = set(&[
"/d/yog/workspaces/home",
"/d/litany/workspaces/auto-1",
"/d/litany/replays/replay-1",
]);
assert_eq!(by_leaf(&s, "home"), Ok(s[0].clone()));
assert_eq!(by_leaf(&s, "auto-1"), Ok(s[1].clone()));
assert_eq!(by_leaf(&s, "replay-1"), Ok(s[2].clone()));
}
#[test]
fn an_unknown_leaf_refuses_and_names_the_set() {
let s = set(&["/d/yog/workspaces/home"]);
assert_eq!(
by_leaf(&s, "nope"),
Err("unknown workspace \"nope\" — known: home".to_owned())
);
assert_eq!(
by_leaf(&[], "home"),
Err("unknown workspace \"home\" — none is enumerated here".into())
);
}
#[test]
fn an_ambiguous_leaf_refuses() {
let s = set(&["/d/yog/workspaces/home", "/d/litany/replays/home"]);
assert_eq!(
by_leaf(&s, "home"),
Err("ambiguous workspace \"home\"".to_owned())
);
}
#[test]
fn a_project_names_by_its_basename() {
let s = set(&["/home/u/dev/yog", "/home/u/dev/litany"]);
assert_eq!(name_of(&s, &s[0]), "yog");
assert_eq!(name_of(&s, &s[1]), "litany");
}
#[test]
fn a_shared_basename_grows_one_component() {
let s = set(&["/a/x/proj", "/b/x/proj", "/a/y/proj"]);
let names: Vec<String> = s.iter().map(|p| name_of(&s, p)).collect();
assert_eq!(names, vec!["a/x/proj", "b/x/proj", "y/proj"]);
}
#[test]
fn an_unseparable_relative_names_itself() {
let s = set(&["yog", "/x/yog"]);
assert_eq!(name_of(&s, &s[0]), "yog");
assert_eq!(name_of(&s, &s[1]), "x/yog");
}
#[test]
fn a_path_outside_the_set_names_itself() {
let s = set(&["/d/clones/yog"]);
assert_eq!(name_of(&s, Path::new("/elsewhere/ops")), "/elsewhere/ops");
assert!(resolve(&s, "/elsewhere/ops").is_err());
}
#[test]
fn resolve_is_the_inverse() {
let s = set(&["/a/x/proj", "/b/x/proj"]);
assert_eq!(resolve(&s, "a/x/proj"), Ok(s[0].clone()));
assert_eq!(
resolve(&s, "proj"),
Err("unknown project \"proj\" — known: a/x/proj, b/x/proj".to_owned()),
"the refusal names the derived words `--project` takes, not the paths"
);
}
#[test]
fn a_crowded_world_names_a_bounded_prefix_and_a_count() {
let paths: Vec<String> = (0..20).map(|n| format!("/d/p{n:02}")).collect();
let s = set(&paths.iter().map(String::as_str).collect::<Vec<_>>());
let why = resolve(&s, "nope").expect_err("refused");
assert!(
why.starts_with("unknown project \"nope\" — known: p00, p01,"),
"{why}"
);
assert!(why.ends_with(", and 8 more"), "{why}");
}