1use super::context::EvaluationContext;
4use super::evaluator::{ConditionEvaluator, ConditionResult};
5use crate::expr::ConditionExpr;
6
7pub struct ConditionExprEvaluator<'a, E: ConditionEvaluator> {
15 evaluator: &'a E,
16}
17
18impl<'a, E: ConditionEvaluator> ConditionExprEvaluator<'a, E> {
19 pub fn new(evaluator: &'a E) -> Self {
21 Self { evaluator }
22 }
23
24 pub fn evaluate(&self, expr: &ConditionExpr, ctx: &EvaluationContext) -> ConditionResult {
26 match expr {
27 ConditionExpr::Ref(id) => self.evaluator.evaluate(*id, ctx),
28
29 ConditionExpr::And(exprs) => self.evaluate_and(exprs, ctx),
30
31 ConditionExpr::Or(exprs) => self.evaluate_or(exprs, ctx),
32
33 ConditionExpr::Xor(left, right) => {
34 let l = self.evaluate(left, ctx);
35 let r = self.evaluate(right, ctx);
36 self.evaluate_xor(l, r)
37 }
38
39 ConditionExpr::Not(inner) => {
40 let result = self.evaluate(inner, ctx);
41 self.evaluate_not(result)
42 }
43
44 ConditionExpr::Package { .. } => {
45 ConditionResult::True
48 }
49 }
50 }
51
52 fn evaluate_and(&self, exprs: &[ConditionExpr], ctx: &EvaluationContext) -> ConditionResult {
54 let mut has_unknown = false;
55
56 for expr in exprs {
57 match self.evaluate(expr, ctx) {
58 ConditionResult::False => return ConditionResult::False,
59 ConditionResult::Unknown => has_unknown = true,
60 ConditionResult::True => {}
61 }
62 }
63
64 if has_unknown {
65 ConditionResult::Unknown
66 } else {
67 ConditionResult::True
68 }
69 }
70
71 fn evaluate_or(&self, exprs: &[ConditionExpr], ctx: &EvaluationContext) -> ConditionResult {
73 let mut has_unknown = false;
74
75 for expr in exprs {
76 match self.evaluate(expr, ctx) {
77 ConditionResult::True => return ConditionResult::True,
78 ConditionResult::Unknown => has_unknown = true,
79 ConditionResult::False => {}
80 }
81 }
82
83 if has_unknown {
84 ConditionResult::Unknown
85 } else {
86 ConditionResult::False
87 }
88 }
89
90 fn evaluate_xor(&self, left: ConditionResult, right: ConditionResult) -> ConditionResult {
92 match (left, right) {
93 (ConditionResult::True, ConditionResult::False)
94 | (ConditionResult::False, ConditionResult::True) => ConditionResult::True,
95 (ConditionResult::True, ConditionResult::True)
96 | (ConditionResult::False, ConditionResult::False) => ConditionResult::False,
97 _ => ConditionResult::Unknown,
98 }
99 }
100
101 fn evaluate_not(&self, result: ConditionResult) -> ConditionResult {
103 match result {
104 ConditionResult::True => ConditionResult::False,
105 ConditionResult::False => ConditionResult::True,
106 ConditionResult::Unknown => ConditionResult::Unknown,
107 }
108 }
109
110 pub fn evaluate_status(&self, ahb_status: &str, ctx: &EvaluationContext) -> ConditionResult {
114 use crate::expr::ConditionParser;
115
116 match ConditionParser::parse(ahb_status) {
117 Ok(Some(expr)) => self.evaluate(&expr, ctx),
118 Ok(None) => ConditionResult::True, Err(_) => ConditionResult::Unknown, }
121 }
122
123 pub fn evaluate_status_with_ub(
126 &self,
127 ahb_status: &str,
128 ctx: &EvaluationContext,
129 ub_definitions: &std::collections::HashMap<String, crate::expr::ConditionExpr>,
130 ) -> ConditionResult {
131 use crate::expr::ConditionParser;
132
133 match ConditionParser::parse_with_ub(ahb_status, ub_definitions) {
134 Ok(Some(expr)) => self.evaluate(&expr, ctx),
135 Ok(None) => ConditionResult::True,
136 Err(_) => ConditionResult::Unknown,
137 }
138 }
139
140 pub fn evaluate_status_detailed(
143 &self,
144 ahb_status: &str,
145 ctx: &EvaluationContext,
146 ) -> (ConditionResult, Vec<u32>) {
147 use crate::expr::ConditionParser;
148
149 match ConditionParser::parse(ahb_status) {
150 Ok(Some(expr)) => {
151 let result = self.evaluate(&expr, ctx);
152 if result.is_unknown() {
153 let unknown_ids = self.collect_unknown_ids(&expr, ctx);
154 (result, unknown_ids)
155 } else {
156 (result, Vec::new())
157 }
158 }
159 Ok(None) => (ConditionResult::True, Vec::new()),
160 Err(_) => (ConditionResult::Unknown, Vec::new()),
161 }
162 }
163
164 pub fn evaluate_status_detailed_with_ub(
167 &self,
168 ahb_status: &str,
169 ctx: &EvaluationContext,
170 ub_definitions: &std::collections::HashMap<String, crate::expr::ConditionExpr>,
171 ) -> (ConditionResult, Vec<u32>) {
172 use crate::expr::ConditionParser;
173
174 match ConditionParser::parse_with_ub(ahb_status, ub_definitions) {
175 Ok(Some(expr)) => {
176 let result = self.evaluate(&expr, ctx);
177 if result.is_unknown() {
178 let unknown_ids = self.collect_unknown_ids(&expr, ctx);
179 (result, unknown_ids)
180 } else {
181 (result, Vec::new())
182 }
183 }
184 Ok(None) => (ConditionResult::True, Vec::new()),
185 Err(_) => (ConditionResult::Unknown, Vec::new()),
186 }
187 }
188
189 fn collect_unknown_ids(&self, expr: &ConditionExpr, ctx: &EvaluationContext) -> Vec<u32> {
191 let mut ids = Vec::new();
192 self.collect_unknown_ids_inner(expr, ctx, &mut ids);
193 ids
194 }
195
196 fn collect_unknown_ids_inner(
197 &self,
198 expr: &ConditionExpr,
199 ctx: &EvaluationContext,
200 ids: &mut Vec<u32>,
201 ) {
202 match expr {
203 ConditionExpr::Ref(id) => {
204 if self.evaluator.evaluate(*id, ctx).is_unknown() {
205 ids.push(*id);
206 }
207 }
208 ConditionExpr::And(exprs) | ConditionExpr::Or(exprs) => {
209 for e in exprs {
210 self.collect_unknown_ids_inner(e, ctx, ids);
211 }
212 }
213 ConditionExpr::Xor(left, right) => {
214 self.collect_unknown_ids_inner(left, ctx, ids);
215 self.collect_unknown_ids_inner(right, ctx, ids);
216 }
217 ConditionExpr::Not(inner) => {
218 self.collect_unknown_ids_inner(inner, ctx, ids);
219 }
220 ConditionExpr::Package { .. } => {
221 }
223 }
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::super::evaluator::{ConditionResult as CR, NoOpExternalProvider};
230 use super::*;
231 use mig_types::segment::OwnedSegment;
232 use std::collections::HashMap;
233
234 struct MockEvaluator {
236 results: HashMap<u32, ConditionResult>,
237 external_ids: Vec<u32>,
238 }
239
240 impl MockEvaluator {
241 fn new() -> Self {
242 Self {
243 results: HashMap::new(),
244 external_ids: Vec::new(),
245 }
246 }
247
248 fn with_condition(mut self, id: u32, result: ConditionResult) -> Self {
249 self.results.insert(id, result);
250 self
251 }
252 }
253
254 impl ConditionEvaluator for MockEvaluator {
255 fn evaluate(&self, condition: u32, _ctx: &EvaluationContext) -> ConditionResult {
256 self.results
257 .get(&condition)
258 .copied()
259 .unwrap_or(ConditionResult::Unknown)
260 }
261
262 fn is_external(&self, condition: u32) -> bool {
263 self.external_ids.contains(&condition)
264 }
265
266 fn message_type(&self) -> &str {
267 "TEST"
268 }
269
270 fn format_version(&self) -> &str {
271 "FV_TEST"
272 }
273 }
274
275 fn empty_context() -> (NoOpExternalProvider, Vec<OwnedSegment>) {
276 (NoOpExternalProvider, Vec::new())
277 }
278
279 fn make_ctx<'a>(
280 external: &'a NoOpExternalProvider,
281 segments: &'a [OwnedSegment],
282 ) -> EvaluationContext<'a> {
283 EvaluationContext::new("11001", external, segments)
284 }
285
286 #[test]
289 fn test_eval_single_true() {
290 let eval = MockEvaluator::new().with_condition(1, CR::True);
291 let (ext, segs) = empty_context();
292 let ctx = make_ctx(&ext, &segs);
293 let expr_eval = ConditionExprEvaluator::new(&eval);
294
295 assert_eq!(expr_eval.evaluate(&ConditionExpr::Ref(1), &ctx), CR::True);
296 }
297
298 #[test]
299 fn test_eval_single_false() {
300 let eval = MockEvaluator::new().with_condition(1, CR::False);
301 let (ext, segs) = empty_context();
302 let ctx = make_ctx(&ext, &segs);
303 let expr_eval = ConditionExprEvaluator::new(&eval);
304
305 assert_eq!(expr_eval.evaluate(&ConditionExpr::Ref(1), &ctx), CR::False);
306 }
307
308 #[test]
309 fn test_eval_single_unknown() {
310 let eval = MockEvaluator::new(); let (ext, segs) = empty_context();
312 let ctx = make_ctx(&ext, &segs);
313 let expr_eval = ConditionExprEvaluator::new(&eval);
314
315 assert_eq!(
316 expr_eval.evaluate(&ConditionExpr::Ref(999), &ctx),
317 CR::Unknown
318 );
319 }
320
321 #[test]
324 fn test_eval_and_both_true() {
325 let eval = MockEvaluator::new()
326 .with_condition(1, CR::True)
327 .with_condition(2, CR::True);
328 let (ext, segs) = empty_context();
329 let ctx = make_ctx(&ext, &segs);
330 let expr_eval = ConditionExprEvaluator::new(&eval);
331
332 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
333 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
334 }
335
336 #[test]
337 fn test_eval_and_one_false_short_circuits() {
338 let eval = MockEvaluator::new()
339 .with_condition(1, CR::False)
340 .with_condition(2, CR::True);
341 let (ext, segs) = empty_context();
342 let ctx = make_ctx(&ext, &segs);
343 let expr_eval = ConditionExprEvaluator::new(&eval);
344
345 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
346 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
347 }
348
349 #[test]
350 fn test_eval_and_one_unknown_true_gives_unknown() {
351 let eval = MockEvaluator::new()
352 .with_condition(1, CR::True)
353 .with_condition(2, CR::Unknown);
354 let (ext, segs) = empty_context();
355 let ctx = make_ctx(&ext, &segs);
356 let expr_eval = ConditionExprEvaluator::new(&eval);
357
358 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
359 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
360 }
361
362 #[test]
363 fn test_eval_and_false_beats_unknown() {
364 let eval = MockEvaluator::new()
366 .with_condition(1, CR::False)
367 .with_condition(2, CR::Unknown);
368 let (ext, segs) = empty_context();
369 let ctx = make_ctx(&ext, &segs);
370 let expr_eval = ConditionExprEvaluator::new(&eval);
371
372 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
373 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
374 }
375
376 #[test]
377 fn test_eval_and_three_way() {
378 let eval = MockEvaluator::new()
379 .with_condition(182, CR::True)
380 .with_condition(6, CR::True)
381 .with_condition(570, CR::True);
382 let (ext, segs) = empty_context();
383 let ctx = make_ctx(&ext, &segs);
384 let expr_eval = ConditionExprEvaluator::new(&eval);
385
386 let expr = ConditionExpr::And(vec![
387 ConditionExpr::Ref(182),
388 ConditionExpr::Ref(6),
389 ConditionExpr::Ref(570),
390 ]);
391 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
392 }
393
394 #[test]
395 fn test_eval_and_three_way_one_false() {
396 let eval = MockEvaluator::new()
397 .with_condition(182, CR::True)
398 .with_condition(6, CR::True)
399 .with_condition(570, CR::False);
400 let (ext, segs) = empty_context();
401 let ctx = make_ctx(&ext, &segs);
402 let expr_eval = ConditionExprEvaluator::new(&eval);
403
404 let expr = ConditionExpr::And(vec![
405 ConditionExpr::Ref(182),
406 ConditionExpr::Ref(6),
407 ConditionExpr::Ref(570),
408 ]);
409 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
410 }
411
412 #[test]
415 fn test_eval_or_both_false() {
416 let eval = MockEvaluator::new()
417 .with_condition(1, CR::False)
418 .with_condition(2, CR::False);
419 let (ext, segs) = empty_context();
420 let ctx = make_ctx(&ext, &segs);
421 let expr_eval = ConditionExprEvaluator::new(&eval);
422
423 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
424 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
425 }
426
427 #[test]
428 fn test_eval_or_one_true_short_circuits() {
429 let eval = MockEvaluator::new()
430 .with_condition(1, CR::False)
431 .with_condition(2, CR::True);
432 let (ext, segs) = empty_context();
433 let ctx = make_ctx(&ext, &segs);
434 let expr_eval = ConditionExprEvaluator::new(&eval);
435
436 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
437 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
438 }
439
440 #[test]
441 fn test_eval_or_true_beats_unknown() {
442 let eval = MockEvaluator::new()
443 .with_condition(1, CR::Unknown)
444 .with_condition(2, CR::True);
445 let (ext, segs) = empty_context();
446 let ctx = make_ctx(&ext, &segs);
447 let expr_eval = ConditionExprEvaluator::new(&eval);
448
449 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
450 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
451 }
452
453 #[test]
454 fn test_eval_or_false_and_unknown_gives_unknown() {
455 let eval = MockEvaluator::new()
456 .with_condition(1, CR::False)
457 .with_condition(2, CR::Unknown);
458 let (ext, segs) = empty_context();
459 let ctx = make_ctx(&ext, &segs);
460 let expr_eval = ConditionExprEvaluator::new(&eval);
461
462 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
463 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
464 }
465
466 #[test]
469 fn test_eval_xor_true_false() {
470 let eval = MockEvaluator::new()
471 .with_condition(1, CR::True)
472 .with_condition(2, CR::False);
473 let (ext, segs) = empty_context();
474 let ctx = make_ctx(&ext, &segs);
475 let expr_eval = ConditionExprEvaluator::new(&eval);
476
477 let expr = ConditionExpr::Xor(
478 Box::new(ConditionExpr::Ref(1)),
479 Box::new(ConditionExpr::Ref(2)),
480 );
481 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
482 }
483
484 #[test]
485 fn test_eval_xor_both_true() {
486 let eval = MockEvaluator::new()
487 .with_condition(1, CR::True)
488 .with_condition(2, CR::True);
489 let (ext, segs) = empty_context();
490 let ctx = make_ctx(&ext, &segs);
491 let expr_eval = ConditionExprEvaluator::new(&eval);
492
493 let expr = ConditionExpr::Xor(
494 Box::new(ConditionExpr::Ref(1)),
495 Box::new(ConditionExpr::Ref(2)),
496 );
497 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
498 }
499
500 #[test]
501 fn test_eval_xor_both_false() {
502 let eval = MockEvaluator::new()
503 .with_condition(1, CR::False)
504 .with_condition(2, CR::False);
505 let (ext, segs) = empty_context();
506 let ctx = make_ctx(&ext, &segs);
507 let expr_eval = ConditionExprEvaluator::new(&eval);
508
509 let expr = ConditionExpr::Xor(
510 Box::new(ConditionExpr::Ref(1)),
511 Box::new(ConditionExpr::Ref(2)),
512 );
513 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
514 }
515
516 #[test]
517 fn test_eval_xor_unknown_propagates() {
518 let eval = MockEvaluator::new()
519 .with_condition(1, CR::True)
520 .with_condition(2, CR::Unknown);
521 let (ext, segs) = empty_context();
522 let ctx = make_ctx(&ext, &segs);
523 let expr_eval = ConditionExprEvaluator::new(&eval);
524
525 let expr = ConditionExpr::Xor(
526 Box::new(ConditionExpr::Ref(1)),
527 Box::new(ConditionExpr::Ref(2)),
528 );
529 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
530 }
531
532 #[test]
535 fn test_eval_not_true() {
536 let eval = MockEvaluator::new().with_condition(1, CR::True);
537 let (ext, segs) = empty_context();
538 let ctx = make_ctx(&ext, &segs);
539 let expr_eval = ConditionExprEvaluator::new(&eval);
540
541 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(1)));
542 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
543 }
544
545 #[test]
546 fn test_eval_not_false() {
547 let eval = MockEvaluator::new().with_condition(1, CR::False);
548 let (ext, segs) = empty_context();
549 let ctx = make_ctx(&ext, &segs);
550 let expr_eval = ConditionExprEvaluator::new(&eval);
551
552 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(1)));
553 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
554 }
555
556 #[test]
557 fn test_eval_not_unknown() {
558 let eval = MockEvaluator::new(); let (ext, segs) = empty_context();
560 let ctx = make_ctx(&ext, &segs);
561 let expr_eval = ConditionExprEvaluator::new(&eval);
562
563 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(1)));
564 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
565 }
566
567 #[test]
570 fn test_eval_complex_nested() {
571 let eval = MockEvaluator::new()
575 .with_condition(1, CR::True)
576 .with_condition(2, CR::False)
577 .with_condition(3, CR::True)
578 .with_condition(4, CR::True)
579 .with_condition(5, CR::True);
580 let (ext, segs) = empty_context();
581 let ctx = make_ctx(&ext, &segs);
582 let expr_eval = ConditionExprEvaluator::new(&eval);
583
584 let expr = ConditionExpr::And(vec![
585 ConditionExpr::Or(vec![
586 ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]),
587 ConditionExpr::And(vec![ConditionExpr::Ref(3), ConditionExpr::Ref(4)]),
588 ]),
589 ConditionExpr::Ref(5),
590 ]);
591 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
592 }
593
594 #[test]
595 fn test_eval_xor_with_nested_and() {
596 let eval = MockEvaluator::new()
600 .with_condition(102, CR::True)
601 .with_condition(2006, CR::True)
602 .with_condition(103, CR::False)
603 .with_condition(2005, CR::False);
604 let (ext, segs) = empty_context();
605 let ctx = make_ctx(&ext, &segs);
606 let expr_eval = ConditionExprEvaluator::new(&eval);
607
608 let expr = ConditionExpr::Xor(
609 Box::new(ConditionExpr::And(vec![
610 ConditionExpr::Ref(102),
611 ConditionExpr::Ref(2006),
612 ])),
613 Box::new(ConditionExpr::And(vec![
614 ConditionExpr::Ref(103),
615 ConditionExpr::Ref(2005),
616 ])),
617 );
618 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
619 }
620
621 #[test]
624 fn test_evaluate_status_with_conditions() {
625 let eval = MockEvaluator::new()
626 .with_condition(182, CR::True)
627 .with_condition(152, CR::True);
628 let (ext, segs) = empty_context();
629 let ctx = make_ctx(&ext, &segs);
630 let expr_eval = ConditionExprEvaluator::new(&eval);
631
632 assert_eq!(
633 expr_eval.evaluate_status("Muss [182] ∧ [152]", &ctx),
634 CR::True
635 );
636 }
637
638 #[test]
639 fn test_evaluate_status_no_conditions() {
640 let eval = MockEvaluator::new();
641 let (ext, segs) = empty_context();
642 let ctx = make_ctx(&ext, &segs);
643 let expr_eval = ConditionExprEvaluator::new(&eval);
644
645 assert_eq!(expr_eval.evaluate_status("Muss", &ctx), CR::True);
646 }
647
648 #[test]
649 fn test_evaluate_status_empty() {
650 let eval = MockEvaluator::new();
651 let (ext, segs) = empty_context();
652 let ctx = make_ctx(&ext, &segs);
653 let expr_eval = ConditionExprEvaluator::new(&eval);
654
655 assert_eq!(expr_eval.evaluate_status("", &ctx), CR::True);
656 }
657
658 #[test]
661 fn test_unknown_propagation_and_or_mix() {
662 let eval = MockEvaluator::new().with_condition(2, CR::True);
666 let (ext, segs) = empty_context();
668 let ctx = make_ctx(&ext, &segs);
669 let expr_eval = ConditionExprEvaluator::new(&eval);
670
671 let expr = ConditionExpr::Or(vec![
672 ConditionExpr::Ref(1),
673 ConditionExpr::And(vec![ConditionExpr::Ref(2), ConditionExpr::Ref(3)]),
674 ]);
675 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
676 }
677
678 #[test]
679 fn test_or_short_circuits_past_unknown() {
680 let eval = MockEvaluator::new().with_condition(2, CR::True);
682 let (ext, segs) = empty_context();
683 let ctx = make_ctx(&ext, &segs);
684 let expr_eval = ConditionExprEvaluator::new(&eval);
685
686 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
687 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
688 }
689
690 #[test]
691 fn test_and_short_circuits_past_unknown() {
692 let eval = MockEvaluator::new().with_condition(2, CR::False);
694 let (ext, segs) = empty_context();
695 let ctx = make_ctx(&ext, &segs);
696 let expr_eval = ConditionExprEvaluator::new(&eval);
697
698 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
699 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
700 }
701
702 #[test]
705 fn test_detailed_returns_unknown_ids() {
706 let eval = MockEvaluator::new().with_condition(182, CR::True);
708 let (ext, segs) = empty_context();
709 let ctx = make_ctx(&ext, &segs);
710 let expr_eval = ConditionExprEvaluator::new(&eval);
711
712 let (result, unknown_ids) = expr_eval.evaluate_status_detailed("Muss [182] ∧ [8]", &ctx);
713 assert_eq!(result, CR::Unknown);
714 assert_eq!(unknown_ids, vec![8]);
715 }
716
717 #[test]
718 fn test_detailed_multiple_unknown_ids() {
719 let eval = MockEvaluator::new().with_condition(2, CR::True);
721 let (ext, segs) = empty_context();
722 let ctx = make_ctx(&ext, &segs);
723 let expr_eval = ConditionExprEvaluator::new(&eval);
724
725 let (result, unknown_ids) =
726 expr_eval.evaluate_status_detailed("Muss [1] ∧ [2] ∧ [3]", &ctx);
727 assert_eq!(result, CR::Unknown);
728 assert_eq!(unknown_ids, vec![1, 3]);
729 }
730
731 #[test]
732 fn test_detailed_no_unknown_when_true() {
733 let eval = MockEvaluator::new()
734 .with_condition(182, CR::True)
735 .with_condition(152, CR::True);
736 let (ext, segs) = empty_context();
737 let ctx = make_ctx(&ext, &segs);
738 let expr_eval = ConditionExprEvaluator::new(&eval);
739
740 let (result, unknown_ids) = expr_eval.evaluate_status_detailed("Muss [182] ∧ [152]", &ctx);
741 assert_eq!(result, CR::True);
742 assert!(unknown_ids.is_empty());
743 }
744
745 #[test]
746 fn test_detailed_no_unknown_when_false() {
747 let eval = MockEvaluator::new().with_condition(182, CR::False);
748 let (ext, segs) = empty_context();
749 let ctx = make_ctx(&ext, &segs);
750 let expr_eval = ConditionExprEvaluator::new(&eval);
751
752 let (result, unknown_ids) = expr_eval.evaluate_status_detailed("Muss [182] ∧ [8]", &ctx);
753 assert_eq!(result, CR::False);
754 assert!(unknown_ids.is_empty());
755 }
756}