use super::*;
#[test]
fn strip_prefix_recognizes_bare_token() {
let root = Path::new("/home/u/.claude/projects");
assert_eq!(
strip_projects_root_prefix(Path::new("-Users-foo-bar"), root).as_deref(),
Some("-Users-foo-bar")
);
}
#[test]
fn strip_prefix_recognizes_under_root() {
let root = Path::new("/home/u/.claude/projects");
assert_eq!(
strip_projects_root_prefix(Path::new("/home/u/.claude/projects/-Users-foo-bar"), root)
.as_deref(),
Some("-Users-foo-bar")
);
}
#[test]
fn strip_prefix_rejects_real_path() {
let root = Path::new("/home/u/.claude/projects");
assert!(strip_projects_root_prefix(Path::new("/Users/testuser/Projects/foo"), root).is_none());
assert!(
strip_projects_root_prefix(Path::new("/home/u/.claude/projects/-Users-foo/sub"), root)
.is_none()
);
}
#[test]
fn lexical_normalize_resolves_dotdot() {
assert_eq!(
lexical_normalize(Path::new("/a/b/../c")),
PathBuf::from("/a/c")
);
assert_eq!(
lexical_normalize(Path::new("/a/./b")),
PathBuf::from("/a/b")
);
}
#[test]
fn projects_root_ends_with_claude_projects() {
let root = projects_root().expect("projects_root");
assert!(root.ends_with("projects"));
assert!(root.to_string_lossy().contains(".claude"));
}
#[test]
fn resolve_claude_home_precedence_flag_then_env_then_home() {
let home = Path::new("/home/u");
assert_eq!(
resolve_claude_home(
Some(Path::new("/flag/dir")),
Some(OsStr::new("/env/dir")),
home
),
PathBuf::from("/flag/dir")
);
assert_eq!(
resolve_claude_home(None, Some(OsStr::new("/env/dir")), home),
PathBuf::from("/env/dir")
);
assert_eq!(
resolve_claude_home(None, Some(OsStr::new("")), home),
PathBuf::from("/home/u/.claude")
);
assert_eq!(
resolve_claude_home(None, None, home),
PathBuf::from("/home/u/.claude")
);
}
#[test]
fn absolutize_existing_path_canonicalizes() {
let tmp = std::env::temp_dir();
let abs = absolutize(&tmp).expect("absolutize existing");
assert!(abs.is_absolute());
}
#[test]
fn absolutize_nonexistent_absolute_path_normalizes_lexically() {
#[cfg(windows)]
let (input, want) = (r"C:\no\such\csift\a\..\b", r"C:\no\such\csift\b");
#[cfg(not(windows))]
let (input, want) = ("/no/such/csift/a/../b", "/no/such/csift/b");
let abs = absolutize(Path::new(input)).expect("absolutize");
assert_eq!(abs, PathBuf::from(want));
}
#[test]
fn absolutize_nonexistent_relative_path_joins_cwd() {
let rel = Path::new("csift-nonexistent-xyzzy-rel");
let abs = absolutize(rel).expect("absolutize relative");
assert!(abs.is_absolute());
assert!(abs.ends_with("csift-nonexistent-xyzzy-rel"));
}
#[test]
fn lexical_normalize_handles_curdir_and_parentdir_and_plain() {
assert_eq!(
lexical_normalize(Path::new("/a/./b/../c")),
PathBuf::from("/a/c")
);
assert_eq!(lexical_normalize(Path::new("a/b")), PathBuf::from("a/b"));
}
#[test]
fn strip_prefix_under_root_with_token() {
let root = Path::new("/home/u/.claude/projects");
assert_eq!(
strip_projects_root_prefix(Path::new("/home/u/.claude/projects/-Enc-Token"), root)
.as_deref(),
Some("-Enc-Token")
);
assert!(
strip_projects_root_prefix(Path::new("/home/u/.claude/projects/plain"), root).is_none()
);
}
#[test]
fn strip_prefix_under_root_empty_remainder_is_none() {
let root = Path::new("/home/u/.claude/projects");
assert!(strip_projects_root_prefix(root, root).is_none());
}
#[test]
fn resolve_target_real_path_that_does_not_resolve_errors() {
let err = resolve_target(Path::new(
"/Users/csift-definitely-no-such-project-9999/zzz",
))
.unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("no Claude Code project dir"),
"expected step-4 bail, got: {msg}"
);
}
#[test]
fn resolve_target_encoded_token_not_a_dir_errors() {
let err = resolve_target(Path::new("-csift-no-such-encoded-token-zzzz")).unwrap_err();
assert!(
err.to_string().contains("no Claude Code project dir named"),
"expected token bail, got: {err}"
);
}