1use anyhow::{Context, Result};
2use regex::Regex;
3
4pub fn compile_filters(patterns: &[String]) -> Result<Vec<Regex>> {
6 patterns
7 .iter()
8 .map(|pattern| {
9 Regex::new(pattern).with_context(|| format!("Invalid regex pattern: '{}'", pattern))
10 })
11 .collect()
12}
13
14pub fn measurements_to_anchored_regex(measurements: &[String]) -> Vec<String> {
17 measurements
18 .iter()
19 .map(|m| format!("^{}$", regex::escape(m)))
20 .collect()
21}
22
23pub fn combine_measurements_and_filters(
26 measurements: &[String],
27 filter_patterns: &[String],
28) -> Vec<String> {
29 let mut combined = measurements_to_anchored_regex(measurements);
30 combined.extend_from_slice(filter_patterns);
31 combined
32}
33
34pub fn matches_any_filter(name: &str, filters: &[Regex]) -> bool {
37 if filters.is_empty() {
38 return true; }
40 filters.iter().any(|re| re.is_match(name))
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn test_compile_valid_filters() {
49 let patterns = vec!["bench.*".to_string(), "test_.*".to_string()];
50 let result = compile_filters(&patterns);
51 assert!(result.is_ok());
52 assert_eq!(result.unwrap().len(), 2);
53 }
54
55 #[test]
56 fn test_compile_invalid_regex() {
57 let patterns = vec!["[invalid".to_string()];
58 let result = compile_filters(&patterns);
59 assert!(result.is_err());
60 }
61
62 #[test]
63 fn test_matches_any_filter_empty() {
64 let filters = vec![];
65 assert!(matches_any_filter("anything", &filters));
66 }
67
68 #[test]
69 fn test_matches_any_filter_single_match() {
70 let patterns = vec!["bench.*".to_string()];
71 let filters = compile_filters(&patterns).unwrap();
72 assert!(matches_any_filter("benchmark_x64", &filters));
73 assert!(!matches_any_filter("test_foo", &filters));
74 }
75
76 #[test]
77 fn test_matches_any_filter_or_logic() {
78 let patterns = vec!["bench.*".to_string(), "test_.*".to_string()];
79 let filters = compile_filters(&patterns).unwrap();
80 assert!(matches_any_filter("benchmark_x64", &filters));
81 assert!(matches_any_filter("test_foo", &filters));
82 assert!(!matches_any_filter("other_thing", &filters));
83 }
84
85 #[test]
86 fn test_anchored_patterns() {
87 let patterns = vec!["^bench.*$".to_string()];
88 let filters = compile_filters(&patterns).unwrap();
89 assert!(matches_any_filter("benchmark_x64", &filters));
90 assert!(!matches_any_filter("my_benchmark_x64", &filters));
91 }
92
93 #[test]
94 fn test_complex_regex() {
95 let patterns = vec![r"bench_.*_v\d+".to_string()];
96 let filters = compile_filters(&patterns).unwrap();
97 assert!(matches_any_filter("bench_foo_v1", &filters));
98 assert!(matches_any_filter("bench_bar_v23", &filters));
99 assert!(!matches_any_filter("bench_baz_vX", &filters));
100 }
101
102 #[test]
103 fn test_measurements_to_anchored_regex() {
104 let measurements = vec![
105 "benchmark_x64".to_string(),
106 "test.with.dots".to_string(),
107 "name[with]brackets".to_string(),
108 ];
109 let anchored = measurements_to_anchored_regex(&measurements);
110
111 assert_eq!(anchored.len(), 3);
112 assert_eq!(anchored[0], "^benchmark_x64$");
113 assert_eq!(anchored[1], r"^test\.with\.dots$");
114 assert_eq!(anchored[2], r"^name\[with\]brackets$");
115 }
116
117 #[test]
118 fn test_measurements_to_anchored_regex_matches_exactly() {
119 let measurements = vec!["benchmark".to_string()];
120 let anchored = measurements_to_anchored_regex(&measurements);
121 let filters = compile_filters(&anchored).unwrap();
122
123 assert!(matches_any_filter("benchmark", &filters));
125
126 assert!(!matches_any_filter("benchmark_x64", &filters));
128 assert!(!matches_any_filter("my_benchmark", &filters));
129 }
130
131 #[test]
132 fn test_combine_measurements_and_filters() {
133 let measurements = vec!["exact_match".to_string()];
134 let filters = vec!["pattern.*".to_string()];
135
136 let combined = combine_measurements_and_filters(&measurements, &filters);
137
138 assert_eq!(combined.len(), 2);
139 assert_eq!(combined[0], "^exact_match$");
140 assert_eq!(combined[1], "pattern.*");
141 }
142
143 #[test]
144 fn test_combine_measurements_and_filters_matching() {
145 let measurements = vec!["benchmark_x64".to_string()];
146 let filters = vec!["test_.*".to_string()];
147
148 let combined = combine_measurements_and_filters(&measurements, &filters);
149 let compiled = compile_filters(&combined).unwrap();
150
151 assert!(matches_any_filter("benchmark_x64", &compiled));
153
154 assert!(matches_any_filter("test_foo", &compiled));
156 assert!(matches_any_filter("test_bar", &compiled));
157
158 assert!(!matches_any_filter("benchmark_arm64", &compiled));
160 assert!(!matches_any_filter("other", &compiled));
161 }
162}