code_analyze_core/
test_detection.rs1use std::path::Path;
10
11#[must_use]
24pub fn is_test_file(path: &Path) -> bool {
25 for component in path.components() {
27 if let Some("tests" | "test" | "__tests__" | "spec") = component.as_os_str().to_str() {
28 return true;
29 }
30 }
31
32 let Some(file_name) = path.file_name().and_then(|n| n.to_str()) else {
34 return false;
35 };
36
37 let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
39 if file_name.starts_with("test_") && ext.eq_ignore_ascii_case("rs") {
40 return true;
41 }
42 if file_name.ends_with("_test.rs") {
43 return true;
44 }
45
46 if file_name.starts_with("test_") && ext.eq_ignore_ascii_case("py") {
48 return true;
49 }
50 if file_name.ends_with("_test.py") {
51 return true;
52 }
53
54 if file_name.ends_with("_test.go") {
56 return true;
57 }
58
59 if file_name.starts_with("Test") && ext.eq_ignore_ascii_case("java") {
61 return true;
62 }
63 if file_name.ends_with("Test.java") {
64 return true;
65 }
66
67 if file_name.ends_with(".test.ts") || file_name.ends_with(".test.js") {
69 return true;
70 }
71 if file_name.ends_with(".spec.ts") || file_name.ends_with(".spec.js") {
72 return true;
73 }
74
75 false
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn filename_pattern_detects_test_file() {
84 assert!(is_test_file(Path::new("test_utils.rs")));
85 assert!(is_test_file(Path::new("utils_test.rs")));
86 }
87
88 #[test]
89 fn filename_pattern_rejects_production_file() {
90 assert!(!is_test_file(Path::new("utils.rs")));
91 assert!(!is_test_file(Path::new("main.rs")));
92 }
93
94 #[test]
95 fn directory_pattern_detects_test_file() {
96 assert!(is_test_file(Path::new("tests/utils.rs")));
97 }
98
99 #[test]
100 fn directory_pattern_detects_nested_test_file() {
101 assert!(is_test_file(Path::new("src/tests/utils.rs")));
102 assert!(!is_test_file(Path::new("src/utils.rs")));
103 }
104}