1use std::collections::HashSet;
7
8pub const DEFAULT_VAGUE_PATTERNS: &[&str] =
10 &["improve", "as needed", "etc", "and related", "similar"];
11
12pub fn detect_vague_patterns(text: &str, patterns: &[String]) -> Vec<String> {
55 if text.is_empty() || patterns.is_empty() {
57 return Vec::new();
58 }
59
60 let text_lower = text.to_lowercase();
61 let mut found_patterns = Vec::new();
62 let mut seen = HashSet::new();
63
64 for pattern in patterns {
66 let pattern_lower = pattern.to_lowercase();
67
68 if !seen.contains(&pattern_lower) && text_lower.contains(&pattern_lower) {
70 found_patterns.push(pattern.clone());
71 seen.insert(pattern_lower);
72 }
73 }
74
75 found_patterns
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_detect_single_pattern() {
84 let text = "improve performance";
85 let patterns = vec!["improve".to_string()];
86 let result = detect_vague_patterns(text, &patterns);
87 assert_eq!(result, vec!["improve"]);
88 }
89
90 #[test]
91 fn test_detect_pattern_in_phrase() {
92 let text = "Add feature and related tests";
93 let patterns = vec!["and related".to_string()];
94 let result = detect_vague_patterns(text, &patterns);
95 assert_eq!(result, vec!["and related"]);
96 }
97
98 #[test]
99 fn test_no_match() {
100 let text = "Clean code";
101 let patterns = vec!["improve".to_string()];
102 let result = detect_vague_patterns(text, &patterns);
103 assert_eq!(result, Vec::<String>::new());
104 }
105
106 #[test]
107 fn test_empty_text() {
108 let text = "";
109 let patterns = vec!["improve".to_string()];
110 let result = detect_vague_patterns(text, &patterns);
111 assert_eq!(result, Vec::<String>::new());
112 }
113
114 #[test]
115 fn test_empty_patterns() {
116 let text = "improve performance";
117 let patterns: Vec<String> = vec![];
118 let result = detect_vague_patterns(text, &patterns);
119 assert_eq!(result, Vec::<String>::new());
120 }
121
122 #[test]
123 fn test_case_insensitive() {
124 let text = "IMPROVE Performance";
125 let patterns = vec!["improve".to_string()];
126 let result = detect_vague_patterns(text, &patterns);
127 assert_eq!(result, vec!["improve"]);
128 }
129
130 #[test]
131 fn test_case_insensitive_pattern() {
132 let text = "improve performance";
133 let patterns = vec!["IMPROVE".to_string()];
134 let result = detect_vague_patterns(text, &patterns);
135 assert_eq!(result, vec!["IMPROVE"]);
136 }
137
138 #[test]
139 fn test_multiple_patterns() {
140 let text = "improve performance and related metrics etc";
141 let patterns = vec![
142 "improve".to_string(),
143 "and related".to_string(),
144 "etc".to_string(),
145 ];
146 let result = detect_vague_patterns(text, &patterns);
147 assert_eq!(result, vec!["improve", "and related", "etc"]);
148 }
149
150 #[test]
151 fn test_overlapping_patterns_reported_once() {
152 let text = "improve improve improve";
153 let patterns = vec!["improve".to_string()];
154 let result = detect_vague_patterns(text, &patterns);
155 assert_eq!(result, vec!["improve"]);
157 assert_eq!(result.len(), 1);
158 }
159
160 #[test]
161 fn test_duplicate_patterns_in_list() {
162 let text = "improve performance";
163 let patterns = vec!["improve".to_string(), "improve".to_string()];
164 let result = detect_vague_patterns(text, &patterns);
165 assert_eq!(result, vec!["improve"]);
167 assert_eq!(result.len(), 1);
168 }
169
170 #[test]
171 fn test_partial_word_match() {
172 let text = "we need improvement here";
174 let patterns = vec!["improve".to_string()];
175 let result = detect_vague_patterns(text, &patterns);
176 assert_eq!(result, vec!["improve"]);
177 }
178
179 #[test]
180 fn test_default_patterns() {
181 assert!(DEFAULT_VAGUE_PATTERNS.contains(&"improve"));
183 assert!(DEFAULT_VAGUE_PATTERNS.contains(&"as needed"));
184 assert!(DEFAULT_VAGUE_PATTERNS.contains(&"etc"));
185 assert!(DEFAULT_VAGUE_PATTERNS.contains(&"and related"));
186 assert!(DEFAULT_VAGUE_PATTERNS.contains(&"similar"));
187 }
188
189 #[test]
190 fn test_all_default_patterns() {
191 let text = "improve as needed, etc and related similar things";
192 let patterns: Vec<String> = DEFAULT_VAGUE_PATTERNS
193 .iter()
194 .map(|s| s.to_string())
195 .collect();
196 let result = detect_vague_patterns(text, &patterns);
197 assert_eq!(result.len(), 5);
198 assert!(result.contains(&"improve".to_string()));
199 assert!(result.contains(&"as needed".to_string()));
200 assert!(result.contains(&"etc".to_string()));
201 assert!(result.contains(&"and related".to_string()));
202 assert!(result.contains(&"similar".to_string()));
203 }
204}