use std::path::Path;
#[must_use]
pub fn is_test_file(path: &Path) -> bool {
for component in path.components() {
if let Some("tests" | "test" | "__tests__" | "spec") = component.as_os_str().to_str() {
return true;
}
}
let Some(file_name) = path.file_name().and_then(|n| n.to_str()) else {
return false;
};
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
if file_name.starts_with("test_") && ext.eq_ignore_ascii_case("rs") {
return true;
}
if file_name.ends_with("_test.rs") {
return true;
}
if file_name.starts_with("test_") && ext.eq_ignore_ascii_case("py") {
return true;
}
if file_name.ends_with("_test.py") {
return true;
}
if file_name.ends_with("_test.go") {
return true;
}
if file_name.starts_with("Test") && ext.eq_ignore_ascii_case("java") {
return true;
}
if file_name.ends_with("Test.java") {
return true;
}
if file_name.ends_with(".test.ts") || file_name.ends_with(".test.js") {
return true;
}
if file_name.ends_with(".spec.ts") || file_name.ends_with(".spec.js") {
return true;
}
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn filename_pattern_detects_test_file() {
assert!(is_test_file(Path::new("test_utils.rs")));
assert!(is_test_file(Path::new("utils_test.rs")));
}
#[test]
fn filename_pattern_rejects_production_file() {
assert!(!is_test_file(Path::new("utils.rs")));
assert!(!is_test_file(Path::new("main.rs")));
}
#[test]
fn directory_pattern_detects_test_file() {
assert!(is_test_file(Path::new("tests/utils.rs")));
}
#[test]
fn directory_pattern_detects_nested_test_file() {
assert!(is_test_file(Path::new("src/tests/utils.rs")));
assert!(!is_test_file(Path::new("src/utils.rs")));
}
}