use std::path::Path;
pub fn is_no_reverse(source_path: &Path, patterns: &[String]) -> bool {
if patterns.is_empty() {
return false;
}
let Some(filename) = source_path.file_name().and_then(|f| f.to_str()) else {
return false;
};
patterns.iter().any(|p| {
glob::Pattern::new(p)
.map(|g| g.matches(filename))
.unwrap_or(false)
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn empty_patterns_never_match() {
let p = PathBuf::from("/dotfiles/app/config.toml.tmpl");
assert!(!is_no_reverse(&p, &[]));
}
#[test]
fn exact_filename_match() {
let p = PathBuf::from("/dotfiles/app/complex-config.toml.tmpl");
assert!(is_no_reverse(&p, &["complex-config.toml.tmpl".to_string()]));
assert!(!is_no_reverse(&p, &["other-config.toml.tmpl".to_string()]));
}
#[test]
fn glob_matches_by_suffix() {
let p = PathBuf::from("/dotfiles/app/foo.gen.tmpl");
assert!(is_no_reverse(&p, &["*.gen.tmpl".to_string()]));
}
#[test]
fn glob_matches_one_of_many() {
let p = PathBuf::from("/dotfiles/app/foo.gen.tmpl");
let patterns = vec![
"first.tmpl".to_string(),
"*.gen.tmpl".to_string(),
"third.tmpl".to_string(),
];
assert!(is_no_reverse(&p, &patterns));
}
#[test]
fn no_match_returns_false() {
let p = PathBuf::from("/dotfiles/app/regular.tmpl");
assert!(!is_no_reverse(&p, &["*.gen.tmpl".to_string()]));
}
#[test]
fn invalid_glob_pattern_is_ignored() {
let p = PathBuf::from("/dotfiles/app/cfg.tmpl");
assert!(!is_no_reverse(&p, &["[unclosed".to_string()]));
}
#[test]
fn matches_against_filename_not_full_path() {
let p = PathBuf::from("/dotfiles/strange-name/cfg.tmpl");
assert!(is_no_reverse(&p, &["cfg.tmpl".to_string()]));
assert!(!is_no_reverse(&p, &["strange-name".to_string()]));
}
}