use super::*;
#[serial_test::serial(real_fs)]
#[test]
fn skill_search_dirs_defaults_to_single_newt_dir() {
let cfg = Config::default();
let dirs = cfg.skill_search_dirs_with(None, |_| false);
assert_eq!(dirs.len(), 1);
assert!(dirs[0].ends_with("skills"));
assert_eq!(
dirs[0].parent().and_then(|p| p.file_name()),
Some(".newt".as_ref())
);
}
#[serial_test::serial(real_fs)] #[test]
fn personas_dir_is_a_sibling_of_the_newt_config_dir() {
let dir = Config::personas_dir();
assert!(dir.ends_with("personas"));
assert_eq!(
dir.parent().and_then(|p| p.file_name()),
Some(".newt".as_ref())
);
}
#[test]
fn skill_search_dirs_preserves_configured_order() {
let cfg = Config {
skills: Some(SkillsConfig {
search: vec!["/abs/one".into(), "/abs/two".into()],
bundled_dir: String::new(),
}),
..Config::default()
};
assert_eq!(
cfg.skill_search_dirs_with(None, |_| false),
vec![PathBuf::from("/abs/one"), PathBuf::from("/abs/two")]
);
}
#[test]
fn skill_search_dirs_expands_tilde() {
let cfg = Config {
skills: Some(SkillsConfig {
search: vec!["~/skills-x".into()],
bundled_dir: String::new(),
}),
..Config::default()
};
let dirs = cfg.skill_search_dirs_with(None, |_| false);
assert!(dirs[0].ends_with("skills-x"));
assert!(!dirs[0].starts_with("~"));
}
#[test]
fn skill_search_dirs_appends_bundled_dir_last() {
let cfg = Config {
skills: Some(SkillsConfig {
search: vec!["/abs/user".into()],
bundled_dir: "/abs/bundled".into(),
}),
..Config::default()
};
assert_eq!(
cfg.skill_search_dirs_with(None, |_| false),
vec![PathBuf::from("/abs/user"), PathBuf::from("/abs/bundled")],
"user search dirs must precede the bundled dir so users can override"
);
}
#[test]
fn skill_search_dirs_bundled_after_default_when_search_empty() {
let with_bundled = Config {
skills: Some(SkillsConfig {
search: vec![],
bundled_dir: "/abs/bundled".into(),
}),
..Config::default()
};
let dirs = with_bundled.skill_search_dirs_with(None, |_| false);
assert_eq!(dirs.len(), 2, "default host dir + bundled: {dirs:?}");
assert!(
dirs[0].ends_with("skills"),
"default host dir first: {dirs:?}"
);
assert_eq!(
dirs[1],
PathBuf::from("/abs/bundled"),
"bundled last: {dirs:?}"
);
let no_bundled = Config {
skills: Some(SkillsConfig {
search: vec![],
bundled_dir: String::new(),
}),
..Config::default()
};
assert_eq!(
no_bundled.skill_search_dirs_with(None, |_| false).len(),
1,
"empty bundled_dir contributes no directory"
);
}
#[test]
fn skill_search_dirs_append_the_checkout_bundled_default_when_unset() {
let checkout = PathBuf::from("/home/u/repo/.newt/bundled-skills");
let cfg = Config {
skills: Some(SkillsConfig {
search: vec!["/abs/user".into()],
bundled_dir: String::new(),
}),
..Config::default()
};
assert_eq!(
cfg.skill_search_dirs_with(Some(Path::new("/home/u/repo/newt-core")), |p| p == checkout),
vec![PathBuf::from("/abs/user"), checkout.clone()],
"the checkout default is the LOWEST priority entry"
);
assert_eq!(
cfg.skill_search_dirs_with(Some(Path::new("/elsewhere")), |p| p == checkout),
vec![PathBuf::from("/abs/user")]
);
}
#[test]
fn a_configured_bundled_dir_beats_the_checkout_default() {
let cfg = Config {
skills: Some(SkillsConfig {
search: vec![],
bundled_dir: "/explicit/bundled".into(),
}),
..Config::default()
};
let dirs = cfg.skill_search_dirs_with(Some(Path::new("/home/u/repo")), |_| true);
assert_eq!(dirs.last(), Some(&PathBuf::from("/explicit/bundled")));
assert_eq!(
dirs.len(),
2,
"host default + the explicit bundled dir: {dirs:?}"
);
}
#[test]
fn skill_install_dir_is_the_first_configured_root() {
let cfg = Config {
skills: Some(SkillsConfig {
search: vec!["/abs/first".into(), "/abs/second".into()],
bundled_dir: "/abs/bundled".into(),
}),
..Config::default()
};
assert_eq!(cfg.skill_install_dir(), Some(PathBuf::from("/abs/first")));
assert_eq!(
cfg.skill_search_dirs_with(None, |_| false).first(),
cfg.skill_install_dir().as_ref(),
"the install dir is the search path's highest-priority entry"
);
}
#[serial_test::serial(real_fs)]
#[test]
fn skill_install_dir_honors_newt_config_dir() {
let saved = std::env::var_os(NEWT_CONFIG_DIR_ENV);
std::env::set_var(NEWT_CONFIG_DIR_ENV, "/tmp/redirected-root");
let dir = Config::default().skill_install_dir();
match saved {
Some(v) => std::env::set_var(NEWT_CONFIG_DIR_ENV, v),
None => std::env::remove_var(NEWT_CONFIG_DIR_ENV),
}
assert_eq!(dir, Some(PathBuf::from("/tmp/redirected-root/skills")));
}
#[test]
fn skills_search_round_trips_through_toml() {
let cfg = Config {
skills: Some(SkillsConfig {
search: vec!["~/.newt/skills".into(), "~/.claude/skills".into()],
bundled_dir: String::new(),
}),
..Config::default()
};
let text = toml::to_string_pretty(&cfg).unwrap();
let back: Config = toml::from_str(&text).unwrap();
assert_eq!(
back.skills.unwrap().search,
vec!["~/.newt/skills".to_string(), "~/.claude/skills".to_string()]
);
}