Skip to main content

opcua_nodes/events/
evaluate.rs

1use std::cmp::Ordering;
2
3use regex::Regex;
4use tracing::error;
5
6use opcua_types::{
7    AttributeId, EventFieldList, FilterOperator, NodeId, NumericRange, QualifiedName, Variant,
8    VariantScalarTypeId, VariantTypeId,
9};
10
11use crate::TypeTree;
12
13use super::{
14    event::Event,
15    validation::{
16        ParsedContentFilter, ParsedEventFilter, ParsedOperand, ParsedSimpleAttributeOperand,
17    },
18};
19
20impl ParsedEventFilter {
21    /// Evaluate the event filter, returning `None` if the
22    /// filter does not accept the event, and a list of event fields fetched from
23    /// the event if it does.
24    pub fn evaluate(
25        &self,
26        event: &dyn Event,
27        client_handle: u32,
28        type_tree: &dyn TypeTree,
29    ) -> Option<EventFieldList> {
30        if !self.content_filter.evaluate(event, type_tree) {
31            return None;
32        }
33
34        let fields: Vec<_> = self
35            .select_clauses
36            .iter()
37            .map(|c| get_field(event, c))
38            .collect();
39        Some(EventFieldList {
40            client_handle,
41            event_fields: Some(fields),
42        })
43    }
44}
45
46macro_rules! cmp_op {
47    ($slf:ident, $evt:ident, $tt:ident, $op:ident, $pt:pat) => {
48        matches!(
49            ParsedContentFilter::compare_op(
50                $slf.evaluate_operand($evt, $tt, &$op.operands[0]),
51                $slf.evaluate_operand($evt, $tt, &$op.operands[1]),
52            ),
53            $pt
54        )
55        .into()
56    };
57}
58
59macro_rules! as_type {
60    ($v:expr, $t:ident, $def:expr) => {{
61        let v = $v.convert(VariantTypeId::Scalar(VariantScalarTypeId::$t));
62        let Variant::$t(v) = v else {
63            return $def;
64        };
65        v
66    }};
67}
68
69macro_rules! bw_op {
70    ($lhs:expr, $rhs:expr, $op:expr) => {{
71        match $op {
72            BitOperation::And => ($lhs & $rhs).into(),
73            BitOperation::Or => ($lhs | $rhs).into(),
74        }
75    }};
76}
77
78/// Trait for something that can be queried for attribute values.
79///
80/// Implemented by `dyn Event`. Types passed to a content filter must
81/// implement this.
82pub trait AttributeQueryable: Copy {
83    /// Get an attribute value from the item.
84    fn get_attribute(
85        &self,
86        type_definition_id: &NodeId,
87        browse_path: &[QualifiedName],
88        attribute_id: AttributeId,
89        index_range: &NumericRange,
90    ) -> Variant;
91
92    /// Get the type definition of the item.
93    fn get_type(&self) -> NodeId;
94}
95
96impl AttributeQueryable for &dyn Event {
97    fn get_attribute(
98        &self,
99        type_definition_id: &NodeId,
100        browse_path: &[QualifiedName],
101        attribute_id: AttributeId,
102        index_range: &NumericRange,
103    ) -> Variant {
104        self.get_field(type_definition_id, attribute_id, index_range, browse_path)
105    }
106
107    fn get_type(&self) -> NodeId {
108        self.event_type_id().clone()
109    }
110}
111
112enum BitOperation {
113    And,
114    Or,
115}
116
117impl ParsedContentFilter {
118    /// Evaluate the content filter, returning `true` if it
119    /// passes the filter.
120    pub fn evaluate(&self, item: impl AttributeQueryable, type_tree: &dyn TypeTree) -> bool {
121        if self.elements.is_empty() {
122            return true;
123        }
124        matches!(
125            self.evulate_element(item, type_tree, 0),
126            Variant::Boolean(true)
127        )
128    }
129
130    fn evulate_element(
131        &self,
132        item: impl AttributeQueryable,
133        type_tree: &dyn TypeTree,
134        index: usize,
135    ) -> Variant {
136        let Some(op) = self.elements.get(index) else {
137            return Variant::Empty;
138        };
139
140        match op.operator {
141            FilterOperator::Equals => cmp_op!(self, item, type_tree, op, Some(Ordering::Equal)),
142            FilterOperator::IsNull => {
143                (self.evaluate_operand(item, type_tree, &op.operands[0]) == Variant::Empty).into()
144            }
145            FilterOperator::GreaterThan => {
146                cmp_op!(self, item, type_tree, op, Some(Ordering::Greater))
147            }
148            FilterOperator::LessThan => cmp_op!(self, item, type_tree, op, Some(Ordering::Less)),
149            FilterOperator::GreaterThanOrEqual => {
150                cmp_op!(
151                    self,
152                    item,
153                    type_tree,
154                    op,
155                    Some(Ordering::Equal | Ordering::Greater)
156                )
157            }
158            FilterOperator::LessThanOrEqual => {
159                cmp_op!(
160                    self,
161                    item,
162                    type_tree,
163                    op,
164                    Some(Ordering::Equal | Ordering::Less)
165                )
166            }
167            FilterOperator::Like => Self::like(
168                self.evaluate_operand(item, type_tree, &op.operands[0]),
169                self.evaluate_operand(item, type_tree, &op.operands[1]),
170            )
171            .into(),
172            FilterOperator::Not => {
173                Self::not(self.evaluate_operand(item, type_tree, &op.operands[0]))
174            }
175            FilterOperator::Between => Self::between(
176                self.evaluate_operand(item, type_tree, &op.operands[0]),
177                self.evaluate_operand(item, type_tree, &op.operands[1]),
178                self.evaluate_operand(item, type_tree, &op.operands[2]),
179            )
180            .into(),
181            FilterOperator::InList => Self::in_list(
182                self.evaluate_operand(item, type_tree, &op.operands[0]),
183                op.operands
184                    .iter()
185                    .skip(1)
186                    .map(|o| self.evaluate_operand(item, type_tree, o)),
187            )
188            .into(),
189            FilterOperator::And => Self::and(
190                self.evaluate_operand(item, type_tree, &op.operands[0]),
191                self.evaluate_operand(item, type_tree, &op.operands[1]),
192            ),
193            FilterOperator::Or => Self::or(
194                self.evaluate_operand(item, type_tree, &op.operands[0]),
195                self.evaluate_operand(item, type_tree, &op.operands[1]),
196            ),
197            FilterOperator::Cast => Self::cast(
198                self.evaluate_operand(item, type_tree, &op.operands[0]),
199                self.evaluate_operand(item, type_tree, &op.operands[1]),
200            ),
201            FilterOperator::BitwiseAnd => Self::bitwise_op(
202                self.evaluate_operand(item, type_tree, &op.operands[0]),
203                self.evaluate_operand(item, type_tree, &op.operands[1]),
204                BitOperation::And,
205            ),
206            FilterOperator::BitwiseOr => Self::bitwise_op(
207                self.evaluate_operand(item, type_tree, &op.operands[0]),
208                self.evaluate_operand(item, type_tree, &op.operands[1]),
209                BitOperation::Or,
210            ),
211            FilterOperator::OfType => Self::of_type(
212                self.evaluate_operand(item, type_tree, &op.operands[0]),
213                item,
214                type_tree,
215            )
216            .into(),
217            // TODO: Support RelatedTo. InView is not really possible until we build
218            // proper view support.
219            _ => Variant::Empty,
220        }
221    }
222
223    fn evaluate_operand(
224        &self,
225        item: impl AttributeQueryable,
226        type_tree: &dyn TypeTree,
227        op: &ParsedOperand,
228    ) -> Variant {
229        match op {
230            ParsedOperand::ElementOperand(o) => {
231                self.evulate_element(item, type_tree, o.index as usize)
232            }
233            ParsedOperand::LiteralOperand(o) => o.value.clone(),
234            ParsedOperand::AttributeOperand(_) => unreachable!(),
235            ParsedOperand::SimpleAttributeOperand(o) => item.get_attribute(
236                &o.type_definition_id,
237                &o.browse_path,
238                o.attribute_id,
239                &o.index_range,
240            ),
241        }
242    }
243
244    fn in_list(lhs: Variant, rhs: impl Iterator<Item = Variant>) -> bool {
245        for it in rhs {
246            if matches!(Self::compare_op(lhs.clone(), it), Some(Ordering::Equal)) {
247                return true;
248            }
249        }
250        false
251    }
252
253    fn between(it: Variant, gte: Variant, lte: Variant) -> bool {
254        matches!(
255            Self::compare_op(it.clone(), gte),
256            Some(Ordering::Greater | Ordering::Equal)
257        ) && matches!(
258            Self::compare_op(it, lte),
259            Some(Ordering::Less | Ordering::Equal)
260        )
261    }
262
263    fn not(rhs: Variant) -> Variant {
264        let rhs = as_type!(rhs, Boolean, Variant::Empty);
265        (!rhs).into()
266    }
267
268    fn and(lhs: Variant, rhs: Variant) -> Variant {
269        let lhs = as_type!(lhs, Boolean, Variant::Empty);
270        let rhs = as_type!(rhs, Boolean, Variant::Empty);
271
272        (lhs && rhs).into()
273    }
274
275    fn or(lhs: Variant, rhs: Variant) -> Variant {
276        let lhs = as_type!(lhs, Boolean, Variant::Empty);
277        let rhs = as_type!(rhs, Boolean, Variant::Empty);
278
279        (lhs || rhs).into()
280    }
281
282    fn like(lhs: Variant, rhs: Variant) -> bool {
283        let lhs = as_type!(lhs, String, false);
284        let rhs = as_type!(rhs, String, false);
285        let Ok(re) = like_to_regex(rhs.as_ref()) else {
286            return false;
287        };
288        re.is_match(lhs.as_ref())
289    }
290
291    fn cast(lhs: Variant, rhs: Variant) -> Variant {
292        let type_id = match rhs {
293            Variant::NodeId(n) => {
294                let Ok(t) = VariantTypeId::try_from(&*n) else {
295                    return Variant::Empty;
296                };
297                t
298            }
299            Variant::ExpandedNodeId(n) => {
300                let Ok(t) = VariantTypeId::try_from(&n.node_id) else {
301                    return Variant::Empty;
302                };
303                t
304            }
305            _ => return Variant::Empty,
306        };
307        lhs.cast(type_id)
308    }
309
310    fn convert(lhs: Variant, rhs: Variant) -> (Variant, Variant) {
311        let lhs_type = lhs.type_id();
312        match lhs_type.precedence().cmp(&rhs.type_id().precedence()) {
313            std::cmp::Ordering::Less => {
314                let c = rhs.convert(lhs_type);
315                (lhs, c)
316            }
317            std::cmp::Ordering::Equal => (lhs, rhs),
318            std::cmp::Ordering::Greater => (lhs.convert(rhs.type_id()), rhs),
319        }
320    }
321
322    fn bitwise_op(lhs: Variant, rhs: Variant, op: BitOperation) -> Variant {
323        let (lhs, rhs) = Self::convert(lhs, rhs);
324
325        match (lhs, rhs) {
326            (Variant::SByte(lhs), Variant::SByte(rhs)) => bw_op!(lhs, rhs, op),
327            (Variant::Byte(lhs), Variant::Byte(rhs)) => bw_op!(lhs, rhs, op),
328            (Variant::Int16(lhs), Variant::Int16(rhs)) => bw_op!(lhs, rhs, op),
329            (Variant::Int32(lhs), Variant::Int32(rhs)) => bw_op!(lhs, rhs, op),
330            (Variant::Int64(lhs), Variant::Int64(rhs)) => bw_op!(lhs, rhs, op),
331            (Variant::UInt16(lhs), Variant::UInt16(rhs)) => bw_op!(lhs, rhs, op),
332            (Variant::UInt32(lhs), Variant::UInt32(rhs)) => bw_op!(lhs, rhs, op),
333            (Variant::UInt64(lhs), Variant::UInt64(rhs)) => bw_op!(lhs, rhs, op),
334            _ => Variant::Empty,
335        }
336    }
337
338    fn compare_op(lhs: Variant, rhs: Variant) -> Option<Ordering> {
339        let (lhs, rhs) = Self::convert(lhs, rhs);
340        match (lhs, rhs) {
341            (Variant::SByte(lhs), Variant::SByte(rhs)) => Some(lhs.cmp(&rhs)),
342            (Variant::Byte(lhs), Variant::Byte(rhs)) => Some(lhs.cmp(&rhs)),
343            (Variant::Int16(lhs), Variant::Int16(rhs)) => Some(lhs.cmp(&rhs)),
344            (Variant::Int32(lhs), Variant::Int32(rhs)) => Some(lhs.cmp(&rhs)),
345            (Variant::Int64(lhs), Variant::Int64(rhs)) => Some(lhs.cmp(&rhs)),
346            (Variant::UInt16(lhs), Variant::UInt16(rhs)) => Some(lhs.cmp(&rhs)),
347            (Variant::UInt32(lhs), Variant::UInt32(rhs)) => Some(lhs.cmp(&rhs)),
348            (Variant::UInt64(lhs), Variant::UInt64(rhs)) => Some(lhs.cmp(&rhs)),
349            (Variant::Double(lhs), Variant::Double(rhs)) => Some(lhs.total_cmp(&rhs)),
350            (Variant::Float(lhs), Variant::Float(rhs)) => Some(lhs.total_cmp(&rhs)),
351            (Variant::Boolean(lhs), Variant::Boolean(rhs)) => Some(lhs.cmp(&rhs)),
352            _ => None,
353        }
354    }
355
356    fn of_type(lhs: Variant, item: impl AttributeQueryable, type_tree: &dyn TypeTree) -> bool {
357        let type_id = as_type!(lhs, NodeId, false);
358
359        let item_type = item.get_type();
360        type_tree.is_subtype_of(&item_type, &type_id)
361    }
362}
363
364fn get_field(event: &dyn Event, attr: &ParsedSimpleAttributeOperand) -> Variant {
365    event.get_field(
366        &attr.type_definition_id,
367        attr.attribute_id,
368        &attr.index_range,
369        &attr.browse_path,
370    )
371}
372
373/// Converts the OPC UA SQL-esque Like format into a regular expression.
374fn like_to_regex(v: &str) -> Result<Regex, ()> {
375    // Give a reasonable buffer
376    let mut pattern = String::with_capacity(v.len() * 2);
377
378    let mut in_list = false;
379
380    // Turn the chars into a vec to make it easier to index them
381    let v = v.chars().collect::<Vec<char>>();
382
383    pattern.push('^');
384    v.iter().enumerate().for_each(|(i, c)| {
385        if in_list {
386            if *c == ']' && (i == 0 || v[i - 1] != '\\') {
387                // Close the list
388                in_list = false;
389                pattern.push(*c);
390            } else {
391                // Chars in list are escaped if required
392                match c {
393                    '$' | '(' | ')' | '.' | '+' | '*' | '?' => {
394                        // Other regex chars except for ^ are escaped
395                        pattern.push('\\');
396                        pattern.push(*c);
397                    }
398                    _ => {
399                        // Everything between two [] will be treated as-is
400                        pattern.push(*c);
401                    }
402                }
403            }
404        } else {
405            match c {
406                '$' | '^' | '(' | ')' | '.' | '+' | '*' | '?' => {
407                    // Other regex chars are escaped
408                    pattern.push('\\');
409                    pattern.push(*c);
410                }
411                '[' => {
412                    // Opens a list of chars to match
413                    if i == 0 || v[i - 1] != '\\' {
414                        // Open the list
415                        in_list = true;
416                    }
417                    pattern.push(*c);
418                }
419                '%' => {
420                    if i == 0 || v[i - 1] != '\\' {
421                        // A % is a match on zero or more chans unless it is escaped
422                        pattern.push_str(".*");
423                    } else {
424                        pattern.push(*c);
425                    }
426                }
427                '_' => {
428                    if i == 0 || v[i - 1] != '\\' {
429                        // A _ is a match on a single char unless it is escaped
430                        pattern.push('?');
431                    } else {
432                        // Remove escaping of the underscore
433                        let _ = pattern.pop();
434                        pattern.push(*c);
435                    }
436                }
437                _ => {
438                    pattern.push(*c);
439                }
440            }
441        }
442    });
443    pattern.push('$');
444    Regex::new(&pattern).map_err(|err| {
445        error!("Problem parsing, error = {}", err);
446    })
447}
448
449#[cfg(test)]
450mod tests {
451    use regex::Regex;
452
453    use crate::{
454        events::evaluate::like_to_regex, BaseEventType, DefaultTypeTree, Event, ParsedContentFilter,
455    };
456    use opcua_types::{
457        AttributeId, ByteString, ContentFilter, ContentFilterElement, DateTime, FilterOperator,
458        LocalizedText, NodeClass, NodeId, NumericRange, ObjectTypeId, Operand,
459    };
460
461    fn compare_regex(r1: Regex, r2: Regex) {
462        assert_eq!(r1.as_str(), r2.as_str());
463    }
464
465    #[test]
466    fn like_to_regex_tests() {
467        compare_regex(like_to_regex("").unwrap(), Regex::new("^$").unwrap());
468        compare_regex(like_to_regex("^$").unwrap(), Regex::new(r"^\^\$$").unwrap());
469        compare_regex(like_to_regex("%").unwrap(), Regex::new("^.*$").unwrap());
470        compare_regex(like_to_regex("[%]").unwrap(), Regex::new("^[%]$").unwrap());
471        compare_regex(like_to_regex("[_]").unwrap(), Regex::new("^[_]$").unwrap());
472        compare_regex(
473            like_to_regex(r"[\]]").unwrap(),
474            Regex::new(r"^[\]]$").unwrap(),
475        );
476        compare_regex(
477            like_to_regex("[$().+*?]").unwrap(),
478            Regex::new(r"^[\$\(\)\.\+\*\?]$").unwrap(),
479        );
480        compare_regex(like_to_regex("_").unwrap(), Regex::new("^?$").unwrap());
481        compare_regex(
482            like_to_regex("[a-z]").unwrap(),
483            Regex::new("^[a-z]$").unwrap(),
484        );
485        compare_regex(
486            like_to_regex("[abc]").unwrap(),
487            Regex::new("^[abc]$").unwrap(),
488        );
489        compare_regex(
490            like_to_regex(r"\[\]").unwrap(),
491            Regex::new(r"^\[\]$").unwrap(),
492        );
493        compare_regex(
494            like_to_regex("[^0-9]").unwrap(),
495            Regex::new("^[^0-9]$").unwrap(),
496        );
497
498        // Some samples from OPC UA part 4
499        let re = like_to_regex("Th[ia][ts]%").unwrap();
500        assert!(re.is_match("That is fine"));
501        assert!(re.is_match("This is fine"));
502        assert!(re.is_match("That as one"));
503        assert!(!re.is_match("Then at any")); // Spec says this should pass when it obviously wouldn't
504
505        let re = like_to_regex("%en%").unwrap();
506        assert!(re.is_match("entail"));
507        assert!(re.is_match("green"));
508        assert!(re.is_match("content"));
509
510        let re = like_to_regex("abc[13-68]").unwrap();
511        assert!(re.is_match("abc1"));
512        assert!(!re.is_match("abc2"));
513        assert!(re.is_match("abc3"));
514        assert!(re.is_match("abc4"));
515        assert!(re.is_match("abc5"));
516        assert!(re.is_match("abc6"));
517        assert!(!re.is_match("abc7"));
518        assert!(re.is_match("abc8"));
519
520        let re = like_to_regex("ABC[^13-5]").unwrap();
521        assert!(!re.is_match("ABC1"));
522        assert!(re.is_match("ABC2"));
523        assert!(!re.is_match("ABC3"));
524        assert!(!re.is_match("ABC4"));
525        assert!(!re.is_match("ABC5"));
526    }
527
528    mod opcua {
529        pub(super) use crate as nodes;
530        pub(super) use opcua_types as types;
531    }
532
533    #[derive(Event)]
534    #[opcua(identifier = "i=123", namespace = "my:namespace:uri")]
535    struct TestEvent {
536        base: BaseEventType,
537        own_namespace_index: u16,
538        field: i32,
539    }
540
541    impl TestEvent {
542        pub(super) fn new(
543            type_id: impl Into<NodeId>,
544            event_id: ByteString,
545            message: impl Into<LocalizedText>,
546            time: DateTime,
547            field: i32,
548        ) -> Self {
549            Self {
550                base: BaseEventType::new(type_id, event_id, message, time),
551                field,
552                own_namespace_index: 1,
553            }
554        }
555    }
556
557    fn type_tree() -> DefaultTypeTree {
558        let mut type_tree = DefaultTypeTree::new();
559
560        let event_type_id = NodeId::new(1, 123);
561        type_tree.add_type_node(
562            &event_type_id,
563            &ObjectTypeId::BaseEventType.into(),
564            NodeClass::ObjectType,
565        );
566        type_tree.add_type_property(
567            &NodeId::new(1, "field"),
568            &event_type_id,
569            &[&"Field".into()],
570            NodeClass::Variable,
571        );
572
573        type_tree
574    }
575
576    fn filter(
577        elements: Vec<ContentFilterElement>,
578        type_tree: &DefaultTypeTree,
579    ) -> ParsedContentFilter {
580        let (_, f) = ParsedContentFilter::parse(
581            ContentFilter {
582                elements: Some(elements),
583            },
584            type_tree,
585            false,
586            &[FilterOperator::InView, FilterOperator::RelatedTo],
587        );
588        f.unwrap()
589    }
590
591    fn filter_elem(operands: &[Operand], op: FilterOperator) -> ContentFilterElement {
592        ContentFilterElement {
593            filter_operator: op,
594            filter_operands: Some(operands.iter().map(|o| o.into()).collect()),
595        }
596    }
597
598    fn event(field: i32) -> TestEvent {
599        TestEvent::new(
600            NodeId::new(1, 123),
601            ByteString::null(),
602            "message",
603            DateTime::now(),
604            field,
605        )
606    }
607
608    #[test]
609    fn test_equality_filter() {
610        let type_tree = type_tree();
611        let f = filter(
612            vec![filter_elem(
613                &[Operand::literal(10), Operand::literal(9)],
614                FilterOperator::Equals,
615            )],
616            &type_tree,
617        );
618        let event = event(2);
619        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
620        let f = filter(
621            vec![filter_elem(
622                &[
623                    Operand::literal(2),
624                    Operand::simple_attribute(
625                        ObjectTypeId::BaseEventType,
626                        "Field",
627                        AttributeId::Value,
628                        NumericRange::None,
629                    ),
630                ],
631                FilterOperator::Equals,
632            )],
633            &type_tree,
634        );
635        assert!(f.evaluate(&event as &dyn Event, &type_tree));
636    }
637
638    #[test]
639    fn test_lt_filter() {
640        let type_tree = type_tree();
641        let f = filter(
642            vec![filter_elem(
643                &[Operand::literal(10), Operand::literal(9)],
644                FilterOperator::LessThan,
645            )],
646            &type_tree,
647        );
648        let event = event(2);
649        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
650        let f = filter(
651            vec![filter_elem(
652                &[
653                    Operand::literal(1),
654                    Operand::simple_attribute(
655                        ObjectTypeId::BaseEventType,
656                        "Field",
657                        AttributeId::Value,
658                        NumericRange::None,
659                    ),
660                ],
661                FilterOperator::LessThan,
662            )],
663            &type_tree,
664        );
665        assert!(f.evaluate(&event as &dyn Event, &type_tree));
666        let f = filter(
667            vec![filter_elem(
668                &[
669                    Operand::literal(2),
670                    Operand::simple_attribute(
671                        ObjectTypeId::BaseEventType,
672                        "Field",
673                        AttributeId::Value,
674                        NumericRange::None,
675                    ),
676                ],
677                FilterOperator::LessThan,
678            )],
679            &type_tree,
680        );
681        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
682    }
683
684    #[test]
685    fn test_lte_filter() {
686        let type_tree = type_tree();
687        let f = filter(
688            vec![filter_elem(
689                &[Operand::literal(10), Operand::literal(9)],
690                FilterOperator::LessThanOrEqual,
691            )],
692            &type_tree,
693        );
694        let event = event(2);
695        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
696        let f = filter(
697            vec![filter_elem(
698                &[
699                    Operand::literal(1),
700                    Operand::simple_attribute(
701                        ObjectTypeId::BaseEventType,
702                        "Field",
703                        AttributeId::Value,
704                        NumericRange::None,
705                    ),
706                ],
707                FilterOperator::LessThanOrEqual,
708            )],
709            &type_tree,
710        );
711        assert!(f.evaluate(&event as &dyn Event, &type_tree));
712        let f = filter(
713            vec![filter_elem(
714                &[
715                    Operand::literal(2),
716                    Operand::simple_attribute(
717                        ObjectTypeId::BaseEventType,
718                        "Field",
719                        AttributeId::Value,
720                        NumericRange::None,
721                    ),
722                ],
723                FilterOperator::LessThanOrEqual,
724            )],
725            &type_tree,
726        );
727        assert!(f.evaluate(&event as &dyn Event, &type_tree));
728    }
729
730    #[test]
731    fn test_gt_filter() {
732        let type_tree = type_tree();
733        let f = filter(
734            vec![filter_elem(
735                &[Operand::literal(10), Operand::literal(9)],
736                FilterOperator::GreaterThan,
737            )],
738            &type_tree,
739        );
740        let event = event(2);
741        assert!(f.evaluate(&event as &dyn Event, &type_tree));
742        let f = filter(
743            vec![filter_elem(
744                &[
745                    Operand::literal(3),
746                    Operand::simple_attribute(
747                        ObjectTypeId::BaseEventType,
748                        "Field",
749                        AttributeId::Value,
750                        NumericRange::None,
751                    ),
752                ],
753                FilterOperator::GreaterThan,
754            )],
755            &type_tree,
756        );
757        assert!(f.evaluate(&event as &dyn Event, &type_tree));
758        let f = filter(
759            vec![filter_elem(
760                &[
761                    Operand::literal(2),
762                    Operand::simple_attribute(
763                        ObjectTypeId::BaseEventType,
764                        "Field",
765                        AttributeId::Value,
766                        NumericRange::None,
767                    ),
768                ],
769                FilterOperator::GreaterThan,
770            )],
771            &type_tree,
772        );
773        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
774    }
775
776    #[test]
777    fn test_gte_filter() {
778        let type_tree = type_tree();
779        let f = filter(
780            vec![filter_elem(
781                &[Operand::literal(10), Operand::literal(9)],
782                FilterOperator::GreaterThanOrEqual,
783            )],
784            &type_tree,
785        );
786        let event = event(2);
787        assert!(f.evaluate(&event as &dyn Event, &type_tree));
788        let f = filter(
789            vec![filter_elem(
790                &[
791                    Operand::literal(3),
792                    Operand::simple_attribute(
793                        ObjectTypeId::BaseEventType,
794                        "Field",
795                        AttributeId::Value,
796                        NumericRange::None,
797                    ),
798                ],
799                FilterOperator::GreaterThanOrEqual,
800            )],
801            &type_tree,
802        );
803        assert!(f.evaluate(&event as &dyn Event, &type_tree));
804        let f = filter(
805            vec![filter_elem(
806                &[
807                    Operand::literal(2),
808                    Operand::simple_attribute(
809                        ObjectTypeId::BaseEventType,
810                        "Field",
811                        AttributeId::Value,
812                        NumericRange::None,
813                    ),
814                ],
815                FilterOperator::GreaterThanOrEqual,
816            )],
817            &type_tree,
818        );
819        assert!(f.evaluate(&event as &dyn Event, &type_tree));
820    }
821
822    #[test]
823    fn test_not_filter() {
824        let type_tree = type_tree();
825        let f = filter(
826            vec![filter_elem(&[Operand::literal(false)], FilterOperator::Not)],
827            &type_tree,
828        );
829        let evt = event(2);
830        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
831
832        let f = filter(
833            vec![
834                filter_elem(&[Operand::element(1)], FilterOperator::Not),
835                filter_elem(
836                    &[
837                        Operand::simple_attribute(
838                            ObjectTypeId::BaseEventType,
839                            "Field",
840                            AttributeId::Value,
841                            NumericRange::None,
842                        ),
843                        Operand::literal(3),
844                    ],
845                    FilterOperator::Equals,
846                ),
847            ],
848            &type_tree,
849        );
850        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
851        let evt = event(3);
852        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
853    }
854
855    #[test]
856    fn test_between_filter() {
857        let type_tree = type_tree();
858        let f = filter(
859            vec![filter_elem(
860                &[
861                    Operand::literal(9),
862                    Operand::literal(8),
863                    Operand::literal(10),
864                ],
865                FilterOperator::Between,
866            )],
867            &type_tree,
868        );
869        let evt = event(2);
870        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
871        let f = filter(
872            vec![filter_elem(
873                &[
874                    Operand::simple_attribute(
875                        ObjectTypeId::BaseEventType,
876                        "Field",
877                        AttributeId::Value,
878                        NumericRange::None,
879                    ),
880                    Operand::literal(8),
881                    Operand::literal(10),
882                ],
883                FilterOperator::Between,
884            )],
885            &type_tree,
886        );
887        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
888        let evt = event(9);
889        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
890        let evt = event(10);
891        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
892        let evt = event(8);
893        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
894        let evt = event(11);
895        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
896    }
897
898    #[test]
899    fn test_and_filter() {
900        let type_tree = type_tree();
901        let f = filter(
902            vec![filter_elem(
903                &[Operand::literal(true), Operand::literal(false)],
904                FilterOperator::And,
905            )],
906            &type_tree,
907        );
908        let evt = event(2);
909        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
910        let f = filter(
911            vec![
912                filter_elem(
913                    &[Operand::element(1), Operand::element(2)],
914                    FilterOperator::And,
915                ),
916                filter_elem(
917                    &[
918                        Operand::simple_attribute(
919                            ObjectTypeId::BaseEventType,
920                            "Field",
921                            AttributeId::Value,
922                            NumericRange::None,
923                        ),
924                        Operand::literal(3),
925                    ],
926                    FilterOperator::Equals,
927                ),
928                filter_elem(
929                    &[Operand::literal(3), Operand::literal(3)],
930                    FilterOperator::Equals,
931                ),
932            ],
933            &type_tree,
934        );
935
936        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
937        let evt = event(3);
938        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
939    }
940
941    #[test]
942    fn test_or_filter() {
943        let type_tree = type_tree();
944        let f = filter(
945            vec![filter_elem(
946                &[Operand::literal(true), Operand::literal(false)],
947                FilterOperator::Or,
948            )],
949            &type_tree,
950        );
951        let evt = event(2);
952        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
953        let f = filter(
954            vec![
955                filter_elem(
956                    &[Operand::element(1), Operand::element(2)],
957                    FilterOperator::Or,
958                ),
959                filter_elem(
960                    &[
961                        Operand::simple_attribute(
962                            ObjectTypeId::BaseEventType,
963                            "Field",
964                            AttributeId::Value,
965                            NumericRange::None,
966                        ),
967                        Operand::literal(3),
968                    ],
969                    FilterOperator::Equals,
970                ),
971                filter_elem(
972                    &[Operand::literal(3), Operand::literal(2)],
973                    FilterOperator::Equals,
974                ),
975            ],
976            &type_tree,
977        );
978
979        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
980        let evt = event(3);
981        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
982    }
983
984    #[test]
985    fn test_in_list() {
986        let type_tree = type_tree();
987        let f = filter(
988            vec![filter_elem(
989                &[
990                    Operand::literal(1),
991                    Operand::literal(2),
992                    Operand::literal(3),
993                    Operand::literal(1),
994                ],
995                FilterOperator::InList,
996            )],
997            &type_tree,
998        );
999        let evt = event(2);
1000        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
1001        let f = filter(
1002            vec![filter_elem(
1003                &[
1004                    Operand::simple_attribute(
1005                        ObjectTypeId::BaseEventType,
1006                        "Field",
1007                        AttributeId::Value,
1008                        NumericRange::None,
1009                    ),
1010                    Operand::literal(1),
1011                    Operand::literal(2),
1012                    Operand::literal(3),
1013                ],
1014                FilterOperator::InList,
1015            )],
1016            &type_tree,
1017        );
1018        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
1019        let evt = event(4);
1020        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
1021    }
1022
1023    #[test]
1024    fn test_of_type() {
1025        let type_tree = type_tree();
1026        let f = filter(
1027            vec![filter_elem(
1028                &[Operand::literal(NodeId::new(1, 123))],
1029                FilterOperator::OfType,
1030            )],
1031            &type_tree,
1032        );
1033        let evt = event(2);
1034        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
1035
1036        // Test a non-match as well...
1037        let f = filter(
1038            vec![filter_elem(
1039                &[Operand::literal(NodeId::new(1, 456))],
1040                FilterOperator::OfType,
1041            )],
1042            &type_tree,
1043        );
1044        let evt = event(2);
1045        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
1046
1047        // And with the super-type
1048        let f = filter(
1049            vec![filter_elem(
1050                &[Operand::literal(ObjectTypeId::BaseEventType)],
1051                FilterOperator::OfType,
1052            )],
1053            &type_tree,
1054        );
1055        let evt = event(2);
1056        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
1057    }
1058}