evaluator_rs/evaluator/
evaluator.rs

1use std::collections::HashMap;
2use thiserror::Error;
3
4use crate::ast::{
5    expr::Expr,
6    op::{AdditiveOp, LogicalOp, MultiplicativeOp, Op, RelationalOp},
7    value::Value,
8};
9
10#[derive(Error, Debug, PartialEq)]
11pub enum EvaluatorError {
12    #[error("invalid parameter {0}")]
13    InvalidParameter(String),
14    #[error("invalid operation {0} {1} {2}")]
15    InvalidOperation(Value, Op, Value),
16}
17
18/// evaluate expresstion with parameters
19///
20/// Examples:
21///
22/// ```
23/// use evaluator_rs::*;
24/// use std::collections::HashMap;
25///
26/// let expr = parse_expr_from_str("{a} + 2 + 3").unwrap();
27/// let parameters = HashMap::from([("a", Value::from(1))]);
28/// let rs = evaluate(&expr, &parameters).unwrap();
29/// assert_eq!(rs, Value::from(6));
30/// ```
31pub fn evaluate(expr: &Expr, parameters: &HashMap<&str, Value>) -> Result<Value, EvaluatorError> {
32    match expr {
33        Expr::Identifier(name) => match parameters.get(name.as_str()) {
34            Some(v) => Ok(v.clone()),
35            None => Err(EvaluatorError::InvalidParameter(name.to_string())),
36        },
37        Expr::Op(ref lhs, op, ref rhs) => evaluate_op(lhs, op, rhs, parameters),
38        Expr::Value(v) => Ok(v.clone()),
39    }
40}
41
42fn evaluate_op(
43    lhs: &Expr,
44    op: &Op,
45    rhs: &Expr,
46    parameters: &HashMap<&str, Value>,
47) -> Result<Value, EvaluatorError> {
48    let lr = evaluate(lhs, parameters)?;
49    let rr = evaluate(rhs, parameters)?;
50
51    match op {
52        Op::Logical(o) => evaluate_logical_expr(&lr, o, &rr),
53        Op::Relational(o) => evaluate_relational_expr(&lr, o, &rr),
54        Op::Additive(o) => evaluate_additive_expr(&lr, o, &rr),
55        Op::Multiplicative(o) => evaluate_multiplicative_expr(&lr, o, &rr),
56    }
57}
58
59fn evaluate_logical_expr(
60    lhs: &Value,
61    op: &LogicalOp,
62    rhs: &Value,
63) -> Result<Value, EvaluatorError> {
64    match op {
65        LogicalOp::Or => match (lhs, rhs) {
66            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l || *r)),
67            _ => Err(EvaluatorError::InvalidOperation(
68                lhs.clone(),
69                Op::Logical(*op),
70                rhs.clone(),
71            )),
72        },
73        LogicalOp::And => match (lhs, rhs) {
74            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l && *r)),
75            _ => Err(EvaluatorError::InvalidOperation(
76                lhs.clone(),
77                Op::Logical(*op),
78                rhs.clone(),
79            )),
80        },
81    }
82}
83
84fn evaluate_relational_expr(
85    lhs: &Value,
86    op: &RelationalOp,
87    rhs: &Value,
88) -> Result<Value, EvaluatorError> {
89    match op {
90        RelationalOp::Gt => match (lhs, rhs) {
91            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l > *r)),
92            (Value::Number(l), Value::Number(r)) => Ok(Value::Bool(*l > *r)),
93            (Value::String(l), Value::String(r)) => Ok(Value::Bool(*l > *r)),
94            _ => Err(EvaluatorError::InvalidOperation(
95                lhs.clone(),
96                Op::Relational(*op),
97                rhs.clone(),
98            )),
99        },
100        RelationalOp::Gte => match (lhs, rhs) {
101            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l >= *r)),
102            (Value::Number(l), Value::Number(r)) => Ok(Value::Bool(*l >= *r)),
103            (Value::String(l), Value::String(r)) => Ok(Value::Bool(*l >= *r)),
104            _ => Err(EvaluatorError::InvalidOperation(
105                lhs.clone(),
106                Op::Relational(*op),
107                rhs.clone(),
108            )),
109        },
110        RelationalOp::Lt => match (lhs, rhs) {
111            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l < *r)),
112            (Value::Number(l), Value::Number(r)) => Ok(Value::Bool(*l < *r)),
113            (Value::String(l), Value::String(r)) => Ok(Value::Bool(*l < *r)),
114            _ => Err(EvaluatorError::InvalidOperation(
115                lhs.clone(),
116                Op::Relational(*op),
117                rhs.clone(),
118            )),
119        },
120        RelationalOp::Lte => match (lhs, rhs) {
121            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l <= *r)),
122            (Value::Number(l), Value::Number(r)) => Ok(Value::Bool(*l <= *r)),
123            (Value::String(l), Value::String(r)) => Ok(Value::Bool(*l <= *r)),
124            _ => Err(EvaluatorError::InvalidOperation(
125                lhs.clone(),
126                Op::Relational(*op),
127                rhs.clone(),
128            )),
129        },
130        RelationalOp::Eq => match (lhs, rhs) {
131            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l == *r)),
132            (Value::Number(l), Value::Number(r)) => Ok(Value::Bool(*l == *r)),
133            (Value::String(l), Value::String(r)) => Ok(Value::Bool(*l == *r)),
134            (Value::Array(l), Value::Array(r)) => Ok(Value::Bool(*l == *r)),
135            _ => Err(EvaluatorError::InvalidOperation(
136                lhs.clone(),
137                Op::Relational(*op),
138                rhs.clone(),
139            )),
140        },
141        RelationalOp::Neq => match (lhs, rhs) {
142            (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l != *r)),
143            (Value::Number(l), Value::Number(r)) => Ok(Value::Bool(*l != *r)),
144            (Value::String(l), Value::String(r)) => Ok(Value::Bool(*l != *r)),
145            (Value::Array(l), Value::Array(r)) => Ok(Value::Bool(*l != *r)),
146            _ => Err(EvaluatorError::InvalidOperation(
147                lhs.clone(),
148                Op::Relational(*op),
149                rhs.clone(),
150            )),
151        },
152        RelationalOp::In => match (lhs, rhs) {
153            (Value::Number(_), Value::Array(r)) => Ok(Value::Bool(r.contains(lhs))),
154            (Value::String(_), Value::Array(r)) => Ok(Value::Bool(r.contains(lhs))),
155            (Value::Bool(_), Value::Array(r)) => Ok(Value::Bool(r.contains(lhs))),
156            _ => Err(EvaluatorError::InvalidOperation(
157                lhs.clone(),
158                Op::Relational(*op),
159                rhs.clone(),
160            )),
161        },
162    }
163}
164
165fn evaluate_additive_expr(
166    lhs: &Value,
167    op: &AdditiveOp,
168    rhs: &Value,
169) -> Result<Value, EvaluatorError> {
170    match op {
171        AdditiveOp::Add => match (lhs, rhs) {
172            (Value::Number(l), Value::Number(r)) => Ok(Value::Number(*l + *r)),
173            _ => Err(EvaluatorError::InvalidOperation(
174                lhs.clone(),
175                Op::Additive(*op),
176                rhs.clone(),
177            )),
178        },
179        AdditiveOp::Sub => match (lhs, rhs) {
180            (Value::Number(l), Value::Number(r)) => Ok(Value::Number(*l - *r)),
181            _ => Err(EvaluatorError::InvalidOperation(
182                lhs.clone(),
183                Op::Additive(*op),
184                rhs.clone(),
185            )),
186        },
187    }
188}
189
190fn evaluate_multiplicative_expr(
191    lhs: &Value,
192    op: &MultiplicativeOp,
193    rhs: &Value,
194) -> Result<Value, EvaluatorError> {
195    match op {
196        MultiplicativeOp::Mul => match (lhs, rhs) {
197            (Value::Number(l), Value::Number(r)) => Ok(Value::Number(*l * *r)),
198            _ => Err(EvaluatorError::InvalidOperation(
199                lhs.clone(),
200                Op::Multiplicative(*op),
201                rhs.clone(),
202            )),
203        },
204        MultiplicativeOp::Div => match (lhs, rhs) {
205            (Value::Number(l), Value::Number(r)) => Ok(Value::Number(*l / *r)),
206            _ => Err(EvaluatorError::InvalidOperation(
207                lhs.clone(),
208                Op::Multiplicative(*op),
209                rhs.clone(),
210            )),
211        },
212        MultiplicativeOp::Mod => match (lhs, rhs) {
213            (Value::Number(l), Value::Number(r)) => Ok(Value::Number(*l % *r)),
214            _ => Err(EvaluatorError::InvalidOperation(
215                lhs.clone(),
216                Op::Multiplicative(*op),
217                rhs.clone(),
218            )),
219        },
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226    use crate::parser::parser;
227    use crate::Value;
228    use std::collections::HashMap;
229
230    #[allow(dead_code)]
231    struct TestCase<'a> {
232        expr: &'a str,
233        want: Result<Value, EvaluatorError>,
234    }
235
236    #[allow(dead_code)]
237    struct TestCaseWithParameters<'a> {
238        expr: &'a str,
239        parameters: HashMap<&'a str, Value>,
240        want: Result<Value, EvaluatorError>,
241    }
242
243    #[test]
244    fn test_logical_expr() {
245        let empty_parameters: HashMap<&str, Value> = HashMap::new();
246        let test_cases: Vec<TestCase> = vec![
247            TestCase {
248                expr: "true && true",
249                want: Ok(Value::from(true)),
250            },
251            TestCase {
252                expr: "true && false",
253                want: Ok(Value::from(false)),
254            },
255            TestCase {
256                expr: "false && false",
257                want: Ok(Value::from(false)),
258            },
259            TestCase {
260                expr: "true || false",
261                want: Ok(Value::from(true)),
262            },
263            TestCase {
264                expr: "false || false",
265                want: Ok(Value::from(false)),
266            },
267            TestCase {
268                expr: "true || true",
269                want: Ok(Value::from(true)),
270            },
271            TestCase {
272                expr: "1 || true",
273                want: Err(EvaluatorError::InvalidOperation(
274                    Value::from(1),
275                    Op::Logical(LogicalOp::Or),
276                    Value::from(true),
277                )),
278            },
279            TestCase {
280                expr: "1 && true",
281                want: Err(EvaluatorError::InvalidOperation(
282                    Value::from(1),
283                    Op::Logical(LogicalOp::And),
284                    Value::from(true),
285                )),
286            },
287        ];
288        test_cases.iter().for_each(|case| {
289            let expr = parser::parse_expr_from_str(case.expr).unwrap();
290            let output = super::evaluate(&expr, &empty_parameters);
291            assert_eq!(case.want, output, "expr: {}", case.expr);
292        });
293    }
294
295    #[test]
296    fn test_additive_expr() {
297        let empty_parameters: HashMap<&str, Value> = HashMap::new();
298
299        let test_cases: Vec<TestCase> = vec![
300            TestCase {
301                expr: "10 + 10",
302                want: Ok(Value::from(20.0)),
303            },
304            TestCase {
305                expr: "10 - 10",
306                want: Ok(Value::from(0.0)),
307            },
308            TestCase {
309                expr: "1.5 + 1.5",
310                want: Ok(Value::from(3.0)),
311            },
312            TestCase {
313                expr: "1.5 + 1",
314                want: Ok(Value::from(2.5)),
315            },
316            TestCase {
317                expr: "1 + 1.5",
318                want: Ok(Value::from(2.5)),
319            },
320            TestCase {
321                expr: "3.5 - 1",
322                want: Ok(Value::from(2.5)),
323            },
324            TestCase {
325                expr: "3 - 1.5",
326                want: Ok(Value::from(1.5)),
327            },
328            TestCase {
329                expr: "3.5 - 1.5",
330                want: Ok(Value::from(2.0)),
331            },
332            TestCase {
333                expr: "1 + false",
334                want: Err(EvaluatorError::InvalidOperation(
335                    Value::from(1),
336                    Op::Additive(AdditiveOp::Add),
337                    Value::from(false),
338                )),
339            },
340            TestCase {
341                expr: "1 - false",
342                want: Err(EvaluatorError::InvalidOperation(
343                    Value::from(1),
344                    Op::Additive(AdditiveOp::Sub),
345                    Value::from(false),
346                )),
347            },
348        ];
349        test_cases.iter().for_each(|case| {
350            let expr = parser::parse_expr_from_str(case.expr).unwrap();
351            let output = super::evaluate(&expr, &empty_parameters);
352            assert_eq!(case.want, output, "expr: {}", case.expr);
353        });
354    }
355
356    #[test]
357    fn test_multiplicative_expr() {
358        let empty_parameters: HashMap<&str, Value> = HashMap::new();
359
360        let test_cases: Vec<TestCase> = vec![
361            TestCase {
362                expr: "10 * 10",
363                want: Ok(Value::from(100.0)),
364            },
365            TestCase {
366                expr: "10 / 10",
367                want: Ok(Value::from(1.0)),
368            },
369            TestCase {
370                expr: "1.1 * 2.0",
371                want: Ok(Value::from(2.2)),
372            },
373            TestCase {
374                expr: "1.1 * 2",
375                want: Ok(Value::from(2.2)),
376            },
377            TestCase {
378                expr: "2 * 1.1",
379                want: Ok(Value::from(2.2)),
380            },
381            TestCase {
382                expr: "10 % 3",
383                want: Ok(Value::from(1)),
384            },
385            TestCase {
386                expr: "10 % 2.5",
387                want: Ok(Value::from(0)),
388            },
389            TestCase {
390                expr: "1 * true",
391                want: Err(EvaluatorError::InvalidOperation(
392                    Value::from(1),
393                    Op::Multiplicative(MultiplicativeOp::Mul),
394                    Value::from(true),
395                )),
396            },
397            TestCase {
398                expr: "1 / true",
399                want: Err(EvaluatorError::InvalidOperation(
400                    Value::from(1),
401                    Op::Multiplicative(MultiplicativeOp::Div),
402                    Value::from(true),
403                )),
404            },
405            TestCase {
406                expr: "1 % false",
407                want: Err(EvaluatorError::InvalidOperation(
408                    Value::from(1),
409                    Op::Multiplicative(MultiplicativeOp::Mod),
410                    Value::from(false),
411                )),
412            },
413        ];
414        test_cases.iter().for_each(|case| {
415            let expr = parser::parse_expr_from_str(case.expr).unwrap();
416            let output = super::evaluate(&expr, &empty_parameters);
417            assert_eq!(case.want, output, "expr: {}", case.expr);
418        });
419    }
420
421    #[test]
422    fn test_equality_expr() {
423        let empty_parameters: HashMap<&str, Value> = HashMap::new();
424
425        let test_cases: Vec<TestCase> = vec![
426            TestCase {
427                expr: "10 == 10",
428                want: Ok(Value::from(true)),
429            },
430            TestCase {
431                expr: "10 == 1",
432                want: Ok(Value::from(false)),
433            },
434            TestCase {
435                expr: "10 != 10",
436                want: Ok(Value::from(false)),
437            },
438            TestCase {
439                expr: "1 != 10",
440                want: Ok(Value::from(true)),
441            },
442            TestCase {
443                expr: "10.2 != 12.2",
444                want: Ok(Value::from(true)),
445            },
446            TestCase {
447                expr: "10.1 == 10.1",
448                want: Ok(Value::from(true)),
449            },
450            TestCase {
451                expr: "10 != 12.2",
452                want: Ok(Value::from(true)),
453            },
454            TestCase {
455                expr: "10 == 10.0",
456                want: Ok(Value::from(true)),
457            },
458            TestCase {
459                expr: "12.2 != 10",
460                want: Ok(Value::from(true)),
461            },
462            TestCase {
463                expr: "10.0 == 10",
464                want: Ok(Value::from(true)),
465            },
466            TestCase {
467                expr: "true == true",
468                want: Ok(Value::from(true)),
469            },
470            TestCase {
471                expr: "true != true",
472                want: Ok(Value::from(false)),
473            },
474            TestCase {
475                expr: "true == false",
476                want: Ok(Value::from(false)),
477            },
478            TestCase {
479                expr: "'hello' == 'hello'",
480                want: Ok(Value::from(true)),
481            },
482            TestCase {
483                expr: "'hello' == 'world'",
484                want: Ok(Value::from(false)),
485            },
486            TestCase {
487                expr: "'hello' != 'world'",
488                want: Ok(Value::from(true)),
489            },
490            TestCase {
491                expr: "1 == true",
492                want: Err(EvaluatorError::InvalidOperation(
493                    Value::from(1),
494                    Op::Relational(RelationalOp::Eq),
495                    Value::from(true),
496                )),
497            },
498            TestCase {
499                expr: "1 != true",
500                want: Err(EvaluatorError::InvalidOperation(
501                    Value::from(1),
502                    Op::Relational(RelationalOp::Neq),
503                    Value::from(true),
504                )),
505            },
506            TestCase {
507                expr: "1 in true",
508                want: Err(EvaluatorError::InvalidOperation(
509                    Value::from(1),
510                    Op::Relational(RelationalOp::In),
511                    Value::from(true),
512                )),
513            },
514        ];
515        test_cases.iter().for_each(|case| {
516            let expr = parser::parse_expr_from_str(case.expr).unwrap();
517            let output = super::evaluate(&expr, &empty_parameters);
518            assert_eq!(case.want, output, "expr: {}", case.expr);
519        });
520    }
521
522    #[test]
523    fn test_relational_expr() {
524        let empty_parameters: HashMap<&str, Value> = HashMap::new();
525
526        let test_cases: Vec<TestCase> = vec![
527            TestCase {
528                expr: "2 > 1",
529                want: Ok(Value::from(true)),
530            },
531            TestCase {
532                expr: "2 >= 1",
533                want: Ok(Value::from(true)),
534            },
535            TestCase {
536                expr: "2 >= 2",
537                want: Ok(Value::from(true)),
538            },
539            TestCase {
540                expr: "1 < 2",
541                want: Ok(Value::from(true)),
542            },
543            TestCase {
544                expr: "1 <= 1",
545                want: Ok(Value::from(true)),
546            },
547            TestCase {
548                expr: "1 <= 2",
549                want: Ok(Value::from(true)),
550            },
551            TestCase {
552                expr: "2.0 > 1",
553                want: Ok(Value::from(true)),
554            },
555            TestCase {
556                expr: "2.2 >= 1",
557                want: Ok(Value::from(true)),
558            },
559            TestCase {
560                expr: "2.0 >= 2",
561                want: Ok(Value::from(true)),
562            },
563            TestCase {
564                expr: "1.5 < 2",
565                want: Ok(Value::from(true)),
566            },
567            TestCase {
568                expr: "2.2 <= 3",
569                want: Ok(Value::from(true)),
570            },
571            TestCase {
572                expr: "2.0 <= 2",
573                want: Ok(Value::from(true)),
574            },
575            TestCase {
576                expr: "true >= true",
577                want: Ok(Value::from(true)),
578            },
579            TestCase {
580                expr: "true >= false",
581                want: Ok(Value::from(true)),
582            },
583            TestCase {
584                expr: "true > true",
585                want: Ok(Value::from(false)),
586            },
587            TestCase {
588                expr: "true > false",
589                want: Ok(Value::from(true)),
590            },
591            TestCase {
592                expr: "false < false",
593                want: Ok(Value::from(false)),
594            },
595            TestCase {
596                expr: "false <= false",
597                want: Ok(Value::from(true)),
598            },
599            TestCase {
600                expr: "false < true",
601                want: Ok(Value::from(true)),
602            },
603            TestCase {
604                expr: "false <= true",
605                want: Ok(Value::from(true)),
606            },
607            TestCase {
608                expr: "[1, 2] == [1, 2]",
609                want: Ok(Value::from(true)),
610            },
611            TestCase {
612                expr: "[1, 2, 3] == [1, 2]",
613                want: Ok(Value::from(false)),
614            },
615            TestCase {
616                expr: "[1, 2, 3] != [1, 2]",
617                want: Ok(Value::from(true)),
618            },
619            TestCase {
620                expr: "'2' > '1'",
621                want: Ok(Value::from(true)),
622            },
623            TestCase {
624                expr: "'2' >= '1'",
625                want: Ok(Value::from(true)),
626            },
627            TestCase {
628                expr: "'2' > '3'",
629                want: Ok(Value::from(false)),
630            },
631            TestCase {
632                expr: "'2' >= '3'",
633                want: Ok(Value::from(false)),
634            },
635            TestCase {
636                expr: "'2' < '3'",
637                want: Ok(Value::from(true)),
638            },
639            TestCase {
640                expr: "'2' < '1'",
641                want: Ok(Value::from(false)),
642            },
643            TestCase {
644                expr: "'2' <= '3'",
645                want: Ok(Value::from(true)),
646            },
647            TestCase {
648                expr: "'2' <= '1'",
649                want: Ok(Value::from(false)),
650            },
651            TestCase {
652                expr: "1 > true",
653                want: Err(EvaluatorError::InvalidOperation(
654                    Value::from(1),
655                    Op::Relational(RelationalOp::Gt),
656                    Value::from(true),
657                )),
658            },
659            TestCase {
660                expr: "1 >= true",
661                want: Err(EvaluatorError::InvalidOperation(
662                    Value::from(1),
663                    Op::Relational(RelationalOp::Gte),
664                    Value::from(true),
665                )),
666            },
667            TestCase {
668                expr: "1 < true",
669                want: Err(EvaluatorError::InvalidOperation(
670                    Value::from(1),
671                    Op::Relational(RelationalOp::Lt),
672                    Value::from(true),
673                )),
674            },
675            TestCase {
676                expr: "1 <= true",
677                want: Err(EvaluatorError::InvalidOperation(
678                    Value::from(1),
679                    Op::Relational(RelationalOp::Lte),
680                    Value::from(true),
681                )),
682            },
683        ];
684        test_cases.iter().for_each(|case| {
685            let expr = parser::parse_expr_from_str(case.expr).unwrap();
686            let output = super::evaluate(&expr, &empty_parameters);
687            assert_eq!(case.want, output, "expr: {}", case.expr);
688        });
689    }
690
691    #[test]
692    fn test_in_array_expr() {
693        let empty_parameters: HashMap<&str, Value> = HashMap::new();
694
695        let test_cases: Vec<TestCase> = vec![
696            TestCase {
697                expr: "1 in [1, 2]",
698                want: Ok(Value::from(true)),
699            },
700            TestCase {
701                expr: "3 in [1, 2]",
702                want: Ok(Value::from(false)),
703            },
704            TestCase {
705                expr: "'one' in ['one', 'two']",
706                want: Ok(Value::from(true)),
707            },
708            TestCase {
709                expr: "'three' in ['one', 'two']",
710                want: Ok(Value::from(false)),
711            },
712            TestCase {
713                expr: "true in [true, false]",
714                want: Ok(Value::from(true)),
715            },
716            TestCase {
717                expr: "true in [false]",
718                want: Ok(Value::from(false)),
719            },
720            TestCase {
721                expr: "1 in []",
722                want: Ok(Value::from(false)),
723            },
724        ];
725        test_cases.iter().for_each(|case| {
726            let expr = parser::parse_expr_from_str(case.expr).unwrap();
727            let output = super::evaluate(&expr, &empty_parameters);
728            assert_eq!(case.want, output, "expr: {}", case.expr);
729        });
730    }
731
732    #[test]
733    fn test_parameter_expr() {
734        let empty_parameters: HashMap<&str, Value> = HashMap::new();
735        let test_cases: Vec<TestCaseWithParameters> = vec![
736            TestCaseWithParameters {
737                expr: "{name} > 1",
738                parameters: HashMap::from([("name", Value::from(2))]),
739                want: Ok(Value::from(true)),
740            },
741            TestCaseWithParameters {
742                expr: "{name} == 1",
743                parameters: HashMap::from([("name", Value::from(1))]),
744                want: Ok(Value::from(true)),
745            },
746            TestCaseWithParameters {
747                expr: "{name} < 1",
748                parameters: HashMap::from([("name", Value::from(0))]),
749                want: Ok(Value::from(true)),
750            },
751            TestCaseWithParameters {
752                expr: "{name} > 1",
753                parameters: HashMap::from([("name", Value::from(0))]),
754                want: Ok(Value::from(false)),
755            },
756            TestCaseWithParameters {
757                expr: "{name} == 1",
758                parameters: HashMap::from([("name", Value::from(0))]),
759                want: Ok(Value::from(false)),
760            },
761            TestCaseWithParameters {
762                expr: "{name} < 1",
763                parameters: HashMap::from([("name", Value::from(2))]),
764                want: Ok(Value::from(false)),
765            },
766            TestCaseWithParameters {
767                expr: "{name} == 1",
768                parameters: empty_parameters,
769                want: Err(EvaluatorError::InvalidParameter("name".to_owned())),
770            },
771        ];
772
773        test_cases.iter().for_each(|case| {
774            let expr = parser::parse_expr_from_str(case.expr).unwrap();
775            let output = super::evaluate(&expr, &case.parameters);
776            assert_eq!(case.want, output, "expr: {}", case.expr);
777        });
778    }
779
780    #[test]
781    fn test_precedence_expr() {
782        let empty_parameters: HashMap<&str, Value> = HashMap::new();
783
784        let test_cases: Vec<TestCase> = vec![
785            TestCase {
786                expr: "(2 > 1) && (4 > 2)",
787                want: Ok(Value::from(true)),
788            },
789            TestCase {
790                expr: "2 > 1 && 4 > 2",
791                want: Ok(Value::from(true)),
792            },
793            TestCase {
794                expr: "1 + 2 * 3",
795                want: Ok(Value::from(7)),
796            },
797            TestCase {
798                expr: "(1 + 2) * 3",
799                want: Ok(Value::from(9)),
800            },
801        ];
802        test_cases.iter().for_each(|case| {
803            let expr = parser::parse_expr_from_str(case.expr).unwrap();
804            let output = super::evaluate(&expr, &empty_parameters);
805            assert_eq!(case.want, output, "expr: {}", case.expr);
806        });
807    }
808}