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                // A % is a match on zero or more chans unless it is escaped
420                '%' if i == 0 || v[i - 1] != '\\' => {
421                    pattern.push_str(".*");
422                }
423                '_' => {
424                    if i == 0 || v[i - 1] != '\\' {
425                        // A _ is a match on a single char unless it is escaped
426                        pattern.push('?');
427                    } else {
428                        // Remove escaping of the underscore
429                        let _ = pattern.pop();
430                        pattern.push(*c);
431                    }
432                }
433                _ => {
434                    pattern.push(*c);
435                }
436            }
437        }
438    });
439    pattern.push('$');
440    Regex::new(&pattern).map_err(|err| {
441        error!("Problem parsing, error = {}", err);
442    })
443}
444
445#[cfg(test)]
446mod tests {
447    use regex::Regex;
448
449    use crate::{
450        events::evaluate::like_to_regex, BaseEventType, DefaultTypeTree, Event, ParsedContentFilter,
451    };
452    use opcua_types::{
453        AttributeId, ByteString, ContentFilter, ContentFilterElement, DateTime, FilterOperator,
454        LocalizedText, NodeClass, NodeId, NumericRange, ObjectTypeId, Operand,
455    };
456
457    fn compare_regex(r1: Regex, r2: Regex) {
458        assert_eq!(r1.as_str(), r2.as_str());
459    }
460
461    #[test]
462    fn like_to_regex_tests() {
463        compare_regex(like_to_regex("").unwrap(), Regex::new("^$").unwrap());
464        compare_regex(like_to_regex("^$").unwrap(), Regex::new(r"^\^\$$").unwrap());
465        compare_regex(like_to_regex("%").unwrap(), Regex::new("^.*$").unwrap());
466        compare_regex(like_to_regex("[%]").unwrap(), Regex::new("^[%]$").unwrap());
467        compare_regex(like_to_regex("[_]").unwrap(), Regex::new("^[_]$").unwrap());
468        compare_regex(
469            like_to_regex(r"[\]]").unwrap(),
470            Regex::new(r"^[\]]$").unwrap(),
471        );
472        compare_regex(
473            like_to_regex("[$().+*?]").unwrap(),
474            Regex::new(r"^[\$\(\)\.\+\*\?]$").unwrap(),
475        );
476        compare_regex(like_to_regex("_").unwrap(), Regex::new("^?$").unwrap());
477        compare_regex(
478            like_to_regex("[a-z]").unwrap(),
479            Regex::new("^[a-z]$").unwrap(),
480        );
481        compare_regex(
482            like_to_regex("[abc]").unwrap(),
483            Regex::new("^[abc]$").unwrap(),
484        );
485        compare_regex(
486            like_to_regex(r"\[\]").unwrap(),
487            Regex::new(r"^\[\]$").unwrap(),
488        );
489        compare_regex(
490            like_to_regex("[^0-9]").unwrap(),
491            Regex::new("^[^0-9]$").unwrap(),
492        );
493
494        // Some samples from OPC UA part 4
495        let re = like_to_regex("Th[ia][ts]%").unwrap();
496        assert!(re.is_match("That is fine"));
497        assert!(re.is_match("This is fine"));
498        assert!(re.is_match("That as one"));
499        assert!(!re.is_match("Then at any")); // Spec says this should pass when it obviously wouldn't
500
501        let re = like_to_regex("%en%").unwrap();
502        assert!(re.is_match("entail"));
503        assert!(re.is_match("green"));
504        assert!(re.is_match("content"));
505
506        let re = like_to_regex("abc[13-68]").unwrap();
507        assert!(re.is_match("abc1"));
508        assert!(!re.is_match("abc2"));
509        assert!(re.is_match("abc3"));
510        assert!(re.is_match("abc4"));
511        assert!(re.is_match("abc5"));
512        assert!(re.is_match("abc6"));
513        assert!(!re.is_match("abc7"));
514        assert!(re.is_match("abc8"));
515
516        let re = like_to_regex("ABC[^13-5]").unwrap();
517        assert!(!re.is_match("ABC1"));
518        assert!(re.is_match("ABC2"));
519        assert!(!re.is_match("ABC3"));
520        assert!(!re.is_match("ABC4"));
521        assert!(!re.is_match("ABC5"));
522    }
523
524    mod opcua {
525        pub(super) use crate as nodes;
526        pub(super) use opcua_types as types;
527    }
528
529    #[derive(Event)]
530    #[opcua(identifier = "i=123", namespace = "my:namespace:uri")]
531    struct TestEvent {
532        base: BaseEventType,
533        own_namespace_index: u16,
534        field: i32,
535    }
536
537    impl TestEvent {
538        pub(super) fn new(
539            type_id: impl Into<NodeId>,
540            event_id: ByteString,
541            message: impl Into<LocalizedText>,
542            time: DateTime,
543            field: i32,
544        ) -> Self {
545            Self {
546                base: BaseEventType::new(type_id, event_id, message, time),
547                field,
548                own_namespace_index: 1,
549            }
550        }
551    }
552
553    fn type_tree() -> DefaultTypeTree {
554        let mut type_tree = DefaultTypeTree::new();
555
556        let event_type_id = NodeId::new(1, 123);
557        type_tree.add_type_node(
558            &event_type_id,
559            &ObjectTypeId::BaseEventType.into(),
560            NodeClass::ObjectType,
561        );
562        type_tree.add_type_property(
563            &NodeId::new(1, "field"),
564            &event_type_id,
565            &[&"Field".into()],
566            NodeClass::Variable,
567        );
568
569        type_tree
570    }
571
572    fn filter(
573        elements: Vec<ContentFilterElement>,
574        type_tree: &DefaultTypeTree,
575    ) -> ParsedContentFilter {
576        let (_, f) = ParsedContentFilter::parse(
577            ContentFilter {
578                elements: Some(elements),
579            },
580            type_tree,
581            false,
582            &[FilterOperator::InView, FilterOperator::RelatedTo],
583        );
584        f.unwrap()
585    }
586
587    fn filter_elem(operands: &[Operand], op: FilterOperator) -> ContentFilterElement {
588        ContentFilterElement {
589            filter_operator: op,
590            filter_operands: Some(operands.iter().map(|o| o.into()).collect()),
591        }
592    }
593
594    fn event(field: i32) -> TestEvent {
595        TestEvent::new(
596            NodeId::new(1, 123),
597            ByteString::null(),
598            "message",
599            DateTime::now(),
600            field,
601        )
602    }
603
604    #[test]
605    fn test_equality_filter() {
606        let type_tree = type_tree();
607        let f = filter(
608            vec![filter_elem(
609                &[Operand::literal(10), Operand::literal(9)],
610                FilterOperator::Equals,
611            )],
612            &type_tree,
613        );
614        let event = event(2);
615        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
616        let f = filter(
617            vec![filter_elem(
618                &[
619                    Operand::literal(2),
620                    Operand::simple_attribute(
621                        ObjectTypeId::BaseEventType,
622                        "Field",
623                        AttributeId::Value,
624                        NumericRange::None,
625                    ),
626                ],
627                FilterOperator::Equals,
628            )],
629            &type_tree,
630        );
631        assert!(f.evaluate(&event as &dyn Event, &type_tree));
632    }
633
634    #[test]
635    fn test_lt_filter() {
636        let type_tree = type_tree();
637        let f = filter(
638            vec![filter_elem(
639                &[Operand::literal(10), Operand::literal(9)],
640                FilterOperator::LessThan,
641            )],
642            &type_tree,
643        );
644        let event = event(2);
645        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
646        let f = filter(
647            vec![filter_elem(
648                &[
649                    Operand::literal(1),
650                    Operand::simple_attribute(
651                        ObjectTypeId::BaseEventType,
652                        "Field",
653                        AttributeId::Value,
654                        NumericRange::None,
655                    ),
656                ],
657                FilterOperator::LessThan,
658            )],
659            &type_tree,
660        );
661        assert!(f.evaluate(&event as &dyn Event, &type_tree));
662        let f = filter(
663            vec![filter_elem(
664                &[
665                    Operand::literal(2),
666                    Operand::simple_attribute(
667                        ObjectTypeId::BaseEventType,
668                        "Field",
669                        AttributeId::Value,
670                        NumericRange::None,
671                    ),
672                ],
673                FilterOperator::LessThan,
674            )],
675            &type_tree,
676        );
677        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
678    }
679
680    #[test]
681    fn test_lte_filter() {
682        let type_tree = type_tree();
683        let f = filter(
684            vec![filter_elem(
685                &[Operand::literal(10), Operand::literal(9)],
686                FilterOperator::LessThanOrEqual,
687            )],
688            &type_tree,
689        );
690        let event = event(2);
691        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
692        let f = filter(
693            vec![filter_elem(
694                &[
695                    Operand::literal(1),
696                    Operand::simple_attribute(
697                        ObjectTypeId::BaseEventType,
698                        "Field",
699                        AttributeId::Value,
700                        NumericRange::None,
701                    ),
702                ],
703                FilterOperator::LessThanOrEqual,
704            )],
705            &type_tree,
706        );
707        assert!(f.evaluate(&event as &dyn Event, &type_tree));
708        let f = filter(
709            vec![filter_elem(
710                &[
711                    Operand::literal(2),
712                    Operand::simple_attribute(
713                        ObjectTypeId::BaseEventType,
714                        "Field",
715                        AttributeId::Value,
716                        NumericRange::None,
717                    ),
718                ],
719                FilterOperator::LessThanOrEqual,
720            )],
721            &type_tree,
722        );
723        assert!(f.evaluate(&event as &dyn Event, &type_tree));
724    }
725
726    #[test]
727    fn test_gt_filter() {
728        let type_tree = type_tree();
729        let f = filter(
730            vec![filter_elem(
731                &[Operand::literal(10), Operand::literal(9)],
732                FilterOperator::GreaterThan,
733            )],
734            &type_tree,
735        );
736        let event = event(2);
737        assert!(f.evaluate(&event as &dyn Event, &type_tree));
738        let f = filter(
739            vec![filter_elem(
740                &[
741                    Operand::literal(3),
742                    Operand::simple_attribute(
743                        ObjectTypeId::BaseEventType,
744                        "Field",
745                        AttributeId::Value,
746                        NumericRange::None,
747                    ),
748                ],
749                FilterOperator::GreaterThan,
750            )],
751            &type_tree,
752        );
753        assert!(f.evaluate(&event as &dyn Event, &type_tree));
754        let f = filter(
755            vec![filter_elem(
756                &[
757                    Operand::literal(2),
758                    Operand::simple_attribute(
759                        ObjectTypeId::BaseEventType,
760                        "Field",
761                        AttributeId::Value,
762                        NumericRange::None,
763                    ),
764                ],
765                FilterOperator::GreaterThan,
766            )],
767            &type_tree,
768        );
769        assert!(!f.evaluate(&event as &dyn Event, &type_tree));
770    }
771
772    #[test]
773    fn test_gte_filter() {
774        let type_tree = type_tree();
775        let f = filter(
776            vec![filter_elem(
777                &[Operand::literal(10), Operand::literal(9)],
778                FilterOperator::GreaterThanOrEqual,
779            )],
780            &type_tree,
781        );
782        let event = event(2);
783        assert!(f.evaluate(&event as &dyn Event, &type_tree));
784        let f = filter(
785            vec![filter_elem(
786                &[
787                    Operand::literal(3),
788                    Operand::simple_attribute(
789                        ObjectTypeId::BaseEventType,
790                        "Field",
791                        AttributeId::Value,
792                        NumericRange::None,
793                    ),
794                ],
795                FilterOperator::GreaterThanOrEqual,
796            )],
797            &type_tree,
798        );
799        assert!(f.evaluate(&event as &dyn Event, &type_tree));
800        let f = filter(
801            vec![filter_elem(
802                &[
803                    Operand::literal(2),
804                    Operand::simple_attribute(
805                        ObjectTypeId::BaseEventType,
806                        "Field",
807                        AttributeId::Value,
808                        NumericRange::None,
809                    ),
810                ],
811                FilterOperator::GreaterThanOrEqual,
812            )],
813            &type_tree,
814        );
815        assert!(f.evaluate(&event as &dyn Event, &type_tree));
816    }
817
818    #[test]
819    fn test_not_filter() {
820        let type_tree = type_tree();
821        let f = filter(
822            vec![filter_elem(&[Operand::literal(false)], FilterOperator::Not)],
823            &type_tree,
824        );
825        let evt = event(2);
826        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
827
828        let f = filter(
829            vec![
830                filter_elem(&[Operand::element(1)], FilterOperator::Not),
831                filter_elem(
832                    &[
833                        Operand::simple_attribute(
834                            ObjectTypeId::BaseEventType,
835                            "Field",
836                            AttributeId::Value,
837                            NumericRange::None,
838                        ),
839                        Operand::literal(3),
840                    ],
841                    FilterOperator::Equals,
842                ),
843            ],
844            &type_tree,
845        );
846        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
847        let evt = event(3);
848        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
849    }
850
851    #[test]
852    fn test_between_filter() {
853        let type_tree = type_tree();
854        let f = filter(
855            vec![filter_elem(
856                &[
857                    Operand::literal(9),
858                    Operand::literal(8),
859                    Operand::literal(10),
860                ],
861                FilterOperator::Between,
862            )],
863            &type_tree,
864        );
865        let evt = event(2);
866        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
867        let f = filter(
868            vec![filter_elem(
869                &[
870                    Operand::simple_attribute(
871                        ObjectTypeId::BaseEventType,
872                        "Field",
873                        AttributeId::Value,
874                        NumericRange::None,
875                    ),
876                    Operand::literal(8),
877                    Operand::literal(10),
878                ],
879                FilterOperator::Between,
880            )],
881            &type_tree,
882        );
883        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
884        let evt = event(9);
885        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
886        let evt = event(10);
887        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
888        let evt = event(8);
889        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
890        let evt = event(11);
891        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
892    }
893
894    #[test]
895    fn test_and_filter() {
896        let type_tree = type_tree();
897        let f = filter(
898            vec![filter_elem(
899                &[Operand::literal(true), Operand::literal(false)],
900                FilterOperator::And,
901            )],
902            &type_tree,
903        );
904        let evt = event(2);
905        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
906        let f = filter(
907            vec![
908                filter_elem(
909                    &[Operand::element(1), Operand::element(2)],
910                    FilterOperator::And,
911                ),
912                filter_elem(
913                    &[
914                        Operand::simple_attribute(
915                            ObjectTypeId::BaseEventType,
916                            "Field",
917                            AttributeId::Value,
918                            NumericRange::None,
919                        ),
920                        Operand::literal(3),
921                    ],
922                    FilterOperator::Equals,
923                ),
924                filter_elem(
925                    &[Operand::literal(3), Operand::literal(3)],
926                    FilterOperator::Equals,
927                ),
928            ],
929            &type_tree,
930        );
931
932        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
933        let evt = event(3);
934        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
935    }
936
937    #[test]
938    fn test_or_filter() {
939        let type_tree = type_tree();
940        let f = filter(
941            vec![filter_elem(
942                &[Operand::literal(true), Operand::literal(false)],
943                FilterOperator::Or,
944            )],
945            &type_tree,
946        );
947        let evt = event(2);
948        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
949        let f = filter(
950            vec![
951                filter_elem(
952                    &[Operand::element(1), Operand::element(2)],
953                    FilterOperator::Or,
954                ),
955                filter_elem(
956                    &[
957                        Operand::simple_attribute(
958                            ObjectTypeId::BaseEventType,
959                            "Field",
960                            AttributeId::Value,
961                            NumericRange::None,
962                        ),
963                        Operand::literal(3),
964                    ],
965                    FilterOperator::Equals,
966                ),
967                filter_elem(
968                    &[Operand::literal(3), Operand::literal(2)],
969                    FilterOperator::Equals,
970                ),
971            ],
972            &type_tree,
973        );
974
975        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
976        let evt = event(3);
977        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
978    }
979
980    #[test]
981    fn test_in_list() {
982        let type_tree = type_tree();
983        let f = filter(
984            vec![filter_elem(
985                &[
986                    Operand::literal(1),
987                    Operand::literal(2),
988                    Operand::literal(3),
989                    Operand::literal(1),
990                ],
991                FilterOperator::InList,
992            )],
993            &type_tree,
994        );
995        let evt = event(2);
996        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
997        let f = filter(
998            vec![filter_elem(
999                &[
1000                    Operand::simple_attribute(
1001                        ObjectTypeId::BaseEventType,
1002                        "Field",
1003                        AttributeId::Value,
1004                        NumericRange::None,
1005                    ),
1006                    Operand::literal(1),
1007                    Operand::literal(2),
1008                    Operand::literal(3),
1009                ],
1010                FilterOperator::InList,
1011            )],
1012            &type_tree,
1013        );
1014        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
1015        let evt = event(4);
1016        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
1017    }
1018
1019    #[test]
1020    fn test_of_type() {
1021        let type_tree = type_tree();
1022        let f = filter(
1023            vec![filter_elem(
1024                &[Operand::literal(NodeId::new(1, 123))],
1025                FilterOperator::OfType,
1026            )],
1027            &type_tree,
1028        );
1029        let evt = event(2);
1030        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
1031
1032        // Test a non-match as well...
1033        let f = filter(
1034            vec![filter_elem(
1035                &[Operand::literal(NodeId::new(1, 456))],
1036                FilterOperator::OfType,
1037            )],
1038            &type_tree,
1039        );
1040        let evt = event(2);
1041        assert!(!f.evaluate(&evt as &dyn Event, &type_tree));
1042
1043        // And with the super-type
1044        let f = filter(
1045            vec![filter_elem(
1046                &[Operand::literal(ObjectTypeId::BaseEventType)],
1047                FilterOperator::OfType,
1048            )],
1049            &type_tree,
1050        );
1051        let evt = event(2);
1052        assert!(f.evaluate(&evt as &dyn Event, &type_tree));
1053    }
1054}