rsigma_parser/
selector.rs1use crate::ast::SelectorPattern;
11
12pub fn detection_name_matches(pattern: &str, name: &str) -> bool {
35 if pattern == "*" {
36 return true;
37 }
38 if let Some(prefix) = pattern.strip_suffix('*') {
39 return name.starts_with(prefix);
40 }
41 if let Some(suffix) = pattern.strip_prefix('*') {
42 return name.ends_with(suffix);
43 }
44 if let Some((prefix, suffix)) = pattern.split_once('*') {
45 return name.len() >= prefix.len() + suffix.len()
46 && name.starts_with(prefix)
47 && name.ends_with(suffix);
48 }
49 pattern == name
50}
51
52impl SelectorPattern {
53 pub fn matches_detection_name(&self, name: &str) -> bool {
61 match self {
62 SelectorPattern::Them => !name.starts_with('_'),
63 SelectorPattern::Pattern(pat) => {
64 (pat.starts_with('_') || !name.starts_with('_'))
65 && detection_name_matches(pat, name)
66 }
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn star_only_matches_anything() {
77 assert!(detection_name_matches("*", "anything"));
78 assert!(detection_name_matches("*", ""));
79 }
80
81 #[test]
82 fn star_suffix_matches_prefix() {
83 assert!(detection_name_matches("selection_*", "selection_main"));
84 assert!(detection_name_matches("selection_*", "selection_"));
85 assert!(!detection_name_matches("selection_*", "filter_main"));
86 }
87
88 #[test]
89 fn star_prefix_matches_suffix() {
90 assert!(detection_name_matches("*_main", "selection_main"));
91 assert!(!detection_name_matches("*_main", "selection_alt"));
92 }
93
94 #[test]
95 fn star_middle_matches_prefix_and_suffix() {
96 assert!(detection_name_matches("sel*main", "selection_main"));
100 assert!(!detection_name_matches("sel*main", "filter_main"));
101 assert!(!detection_name_matches("sel*main", "selection_alt"));
102 }
103
104 #[test]
105 fn star_middle_prefix_and_suffix_do_not_overlap() {
106 assert!(!detection_name_matches("sel*lection", "selection"));
107 assert!(detection_name_matches("sel*lection", "sellection"));
108 assert!(!detection_name_matches("a_*_main", "a_main"));
109 assert!(detection_name_matches("a_*_main", "a__main"));
110 }
111
112 #[test]
113 fn exact_match_without_star() {
114 assert!(detection_name_matches("selection", "selection"));
115 assert!(!detection_name_matches("selection", "filter"));
116 assert!(!detection_name_matches("selection", "selection_main"));
117 }
118
119 #[test]
120 fn underscore_pattern_is_literal() {
121 assert!(detection_name_matches("_helper", "_helper"));
124 assert!(!detection_name_matches("_helper", "helper"));
125 assert!(detection_name_matches("*", "_helper"));
126 }
127
128 #[test]
129 fn selector_pattern_them_skips_underscore_names() {
130 let them = SelectorPattern::Them;
131 assert!(them.matches_detection_name("selection"));
132 assert!(!them.matches_detection_name("_internal"));
133 }
134
135 #[test]
136 fn selector_pattern_pattern_uses_glob() {
137 let pat = SelectorPattern::Pattern("selection_*".to_string());
138 assert!(pat.matches_detection_name("selection_main"));
139 assert!(!pat.matches_detection_name("filter_main"));
140 }
141
142 #[test]
143 fn selector_pattern_skips_underscore_names_unless_it_starts_with_one() {
144 let star = SelectorPattern::Pattern("*".to_string());
145 assert!(star.matches_detection_name("selection"));
146 assert!(!star.matches_detection_name("_internal"));
147 let suffix = SelectorPattern::Pattern("*_main".to_string());
148 assert!(!suffix.matches_detection_name("_sel_main"));
149
150 let internal = SelectorPattern::Pattern("_internal".to_string());
151 assert!(internal.matches_detection_name("_internal"));
152 let hidden = SelectorPattern::Pattern("_*".to_string());
153 assert!(hidden.matches_detection_name("_internal"));
154 assert!(!hidden.matches_detection_name("selection"));
155 }
156}