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