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
18pub 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}