Skip to main content

code_analyze_mcp/
test_detection.rs

1use std::path::Path;
2
3/// Detect if a file path represents a test file based on path-based heuristics.
4///
5/// Checks for:
6/// - Directory patterns: tests/, test/, __tests__/, spec/
7/// - Filename patterns:
8///   - Rust: test_*.rs, *_test.rs
9///   - Python: test_*.py, *_test.py
10///   - Go: *_test.go
11///   - Java: Test*.java, *Test.java
12///   - TypeScript/JavaScript: *.test.ts, *.test.js, *.spec.ts, *.spec.js
13///
14/// Returns true if the path matches any test heuristic, false otherwise.
15pub fn is_test_file(path: &Path) -> bool {
16    // Check directory components for test directories
17    for component in path.components() {
18        if let Some("tests" | "test" | "__tests__" | "spec") = component.as_os_str().to_str() {
19            return true;
20        }
21    }
22
23    // Check filename patterns
24    let file_name = match path.file_name().and_then(|n| n.to_str()) {
25        Some(name) => name,
26        None => return false,
27    };
28
29    // Rust patterns
30    if file_name.starts_with("test_") && file_name.ends_with(".rs") {
31        return true;
32    }
33    if file_name.ends_with("_test.rs") {
34        return true;
35    }
36
37    // Python patterns
38    if file_name.starts_with("test_") && file_name.ends_with(".py") {
39        return true;
40    }
41    if file_name.ends_with("_test.py") {
42        return true;
43    }
44
45    // Go patterns
46    if file_name.ends_with("_test.go") {
47        return true;
48    }
49
50    // Java patterns
51    if file_name.starts_with("Test") && file_name.ends_with(".java") {
52        return true;
53    }
54    if file_name.ends_with("Test.java") {
55        return true;
56    }
57
58    // TypeScript/JavaScript patterns
59    if file_name.ends_with(".test.ts") || file_name.ends_with(".test.js") {
60        return true;
61    }
62    if file_name.ends_with(".spec.ts") || file_name.ends_with(".spec.js") {
63        return true;
64    }
65
66    false
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn filename_pattern_detects_test_file() {
75        assert!(is_test_file(Path::new("test_utils.rs")));
76        assert!(is_test_file(Path::new("utils_test.rs")));
77    }
78
79    #[test]
80    fn filename_pattern_rejects_production_file() {
81        assert!(!is_test_file(Path::new("utils.rs")));
82        assert!(!is_test_file(Path::new("main.rs")));
83    }
84
85    #[test]
86    fn directory_pattern_detects_test_file() {
87        assert!(is_test_file(Path::new("tests/utils.rs")));
88    }
89
90    #[test]
91    fn directory_pattern_detects_nested_test_file() {
92        assert!(is_test_file(Path::new("src/tests/utils.rs")));
93        assert!(!is_test_file(Path::new("src/utils.rs")));
94    }
95}