use std::path::Path;
pub trait PathMatched {
fn path_patterns(&self) -> Option<&[String]>;
fn matches_path(&self, path: &Path) -> bool;
fn is_global(&self) -> bool {
self.path_patterns().is_none()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestPathMatched {
patterns: Option<Vec<String>>,
}
impl PathMatched for TestPathMatched {
fn path_patterns(&self) -> Option<&[String]> {
self.patterns.as_deref()
}
fn matches_path(&self, path: &Path) -> bool {
match &self.patterns {
None => true, Some(patterns) if patterns.is_empty() => false,
Some(patterns) => {
let path_str = path.to_string_lossy();
patterns.iter().any(|p| {
glob::Pattern::new(p)
.map(|pat| pat.matches(&path_str))
.unwrap_or(false)
})
}
}
}
}
#[test]
fn test_global_matches_all() {
let global = TestPathMatched { patterns: None };
assert!(global.is_global());
assert!(global.matches_path(Path::new("any/file.rs")));
assert!(global.matches_path(Path::new("other/path.ts")));
}
#[test]
fn test_pattern_matching() {
let rust_only = TestPathMatched {
patterns: Some(vec!["**/*.rs".to_string()]),
};
assert!(!rust_only.is_global());
assert!(rust_only.matches_path(Path::new("src/lib.rs")));
assert!(rust_only.matches_path(Path::new("tests/integration.rs")));
assert!(!rust_only.matches_path(Path::new("src/lib.ts")));
}
#[test]
fn test_multiple_patterns() {
let web = TestPathMatched {
patterns: Some(vec!["**/*.ts".to_string(), "**/*.tsx".to_string()]),
};
assert!(web.matches_path(Path::new("src/app.ts")));
assert!(web.matches_path(Path::new("components/Button.tsx")));
assert!(!web.matches_path(Path::new("src/lib.rs")));
}
#[test]
fn test_empty_patterns_matches_nothing() {
let empty = TestPathMatched {
patterns: Some(vec![]),
};
assert!(!empty.is_global());
assert!(!empty.matches_path(Path::new("any/file.rs")));
}
}