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