1use super::context::EvaluationContext;
4use super::evaluator::{ConditionEvaluator, ConditionResult};
5use crate::expr::{ConditionExpr, StatusKind};
6
7#[derive(Debug, Clone, PartialEq)]
10pub struct StatusResolution {
11 pub result: ConditionResult,
14 pub kind: Option<StatusKind>,
15 pub unknown_ids: Vec<u32>,
17}
18
19pub struct ConditionExprEvaluator<'a, E: ConditionEvaluator> {
27 evaluator: &'a E,
28}
29
30impl<'a, E: ConditionEvaluator> ConditionExprEvaluator<'a, E> {
31 pub fn new(evaluator: &'a E) -> Self {
33 Self { evaluator }
34 }
35
36 pub fn evaluator(&self) -> &'a E {
38 self.evaluator
39 }
40
41 pub fn evaluate(&self, expr: &ConditionExpr, ctx: &EvaluationContext) -> ConditionResult {
43 match expr {
44 ConditionExpr::Ref(id) => self.evaluator.evaluate(*id, ctx),
45
46 ConditionExpr::And(exprs) => self.evaluate_and(exprs, ctx),
47
48 ConditionExpr::Or(exprs) => self.evaluate_or(exprs, ctx),
49
50 ConditionExpr::Xor(left, right) => {
51 let l = self.evaluate(left, ctx);
52 let r = self.evaluate(right, ctx);
53 self.evaluate_xor(l, r)
54 }
55
56 ConditionExpr::Not(inner) => {
57 let result = self.evaluate(inner, ctx);
58 self.evaluate_not(result)
59 }
60
61 ConditionExpr::Package { .. } => {
62 ConditionResult::True
65 }
66 }
67 }
68
69 fn evaluate_and(&self, exprs: &[ConditionExpr], ctx: &EvaluationContext) -> ConditionResult {
71 let mut has_unknown = false;
72
73 for expr in exprs {
74 match self.evaluate(expr, ctx) {
75 ConditionResult::False => return ConditionResult::False,
76 ConditionResult::Unknown => has_unknown = true,
77 ConditionResult::True => {}
78 }
79 }
80
81 if has_unknown {
82 ConditionResult::Unknown
83 } else {
84 ConditionResult::True
85 }
86 }
87
88 fn evaluate_or(&self, exprs: &[ConditionExpr], ctx: &EvaluationContext) -> ConditionResult {
90 let mut has_unknown = false;
91
92 for expr in exprs {
93 match self.evaluate(expr, ctx) {
94 ConditionResult::True => return ConditionResult::True,
95 ConditionResult::Unknown => has_unknown = true,
96 ConditionResult::False => {}
97 }
98 }
99
100 if has_unknown {
101 ConditionResult::Unknown
102 } else {
103 ConditionResult::False
104 }
105 }
106
107 fn evaluate_xor(&self, left: ConditionResult, right: ConditionResult) -> ConditionResult {
109 match (left, right) {
110 (ConditionResult::True, ConditionResult::False)
111 | (ConditionResult::False, ConditionResult::True) => ConditionResult::True,
112 (ConditionResult::True, ConditionResult::True)
113 | (ConditionResult::False, ConditionResult::False) => ConditionResult::False,
114 _ => ConditionResult::Unknown,
115 }
116 }
117
118 fn evaluate_not(&self, result: ConditionResult) -> ConditionResult {
120 match result {
121 ConditionResult::True => ConditionResult::False,
122 ConditionResult::False => ConditionResult::True,
123 ConditionResult::Unknown => ConditionResult::Unknown,
124 }
125 }
126
127 pub fn evaluate_status(&self, ahb_status: &str, ctx: &EvaluationContext) -> ConditionResult {
131 use crate::expr::ConditionParser;
132
133 match ConditionParser::parse(ahb_status) {
134 Ok(Some(expr)) => self.evaluate(&expr, ctx),
135 Ok(None) => ConditionResult::True, Err(_) => ConditionResult::Unknown, }
138 }
139
140 pub fn evaluate_status_with_ub(
143 &self,
144 ahb_status: &str,
145 ctx: &EvaluationContext,
146 ub_definitions: &std::collections::BTreeMap<String, crate::expr::ConditionExpr>,
147 ) -> ConditionResult {
148 use crate::expr::ConditionParser;
149
150 match ConditionParser::parse_with_ub(ahb_status, ub_definitions) {
151 Ok(Some(expr)) => self.evaluate(&expr, ctx),
152 Ok(None) => ConditionResult::True,
153 Err(_) => ConditionResult::Unknown,
154 }
155 }
156
157 pub fn evaluate_status_detailed(
160 &self,
161 ahb_status: &str,
162 ctx: &EvaluationContext,
163 ) -> (ConditionResult, Vec<u32>) {
164 use crate::expr::ConditionParser;
165
166 match ConditionParser::parse(ahb_status) {
167 Ok(Some(expr)) => {
168 let result = self.evaluate(&expr, ctx);
169 if result.is_unknown() {
170 let unknown_ids = self.collect_unknown_ids(&expr, ctx);
171 (result, unknown_ids)
172 } else {
173 (result, Vec::new())
174 }
175 }
176 Ok(None) => (ConditionResult::True, Vec::new()),
177 Err(_) => (ConditionResult::Unknown, Vec::new()),
178 }
179 }
180
181 pub fn evaluate_status_detailed_with_ub(
184 &self,
185 ahb_status: &str,
186 ctx: &EvaluationContext,
187 ub_definitions: &std::collections::BTreeMap<String, crate::expr::ConditionExpr>,
188 ) -> (ConditionResult, Vec<u32>) {
189 use crate::expr::ConditionParser;
190
191 match ConditionParser::parse_with_ub(ahb_status, ub_definitions) {
192 Ok(Some(expr)) => {
193 let result = self.evaluate(&expr, ctx);
194 if result.is_unknown() {
195 let unknown_ids = self.collect_unknown_ids(&expr, ctx);
196 (result, unknown_ids)
197 } else {
198 (result, Vec::new())
199 }
200 }
201 Ok(None) => (ConditionResult::True, Vec::new()),
202 Err(_) => (ConditionResult::Unknown, Vec::new()),
203 }
204 }
205
206 pub fn resolve_status(
219 &self,
220 ahb_status: &str,
221 ctx: &EvaluationContext,
222 ub_definitions: &std::collections::BTreeMap<String, crate::expr::ConditionExpr>,
223 ) -> StatusResolution {
224 use crate::expr::ConditionParser;
225
226 let branches = match ConditionParser::parse_status_branches(ahb_status, ub_definitions) {
227 Ok(branches) => branches,
228 Err(_) => {
229 return StatusResolution {
230 result: ConditionResult::Unknown,
231 kind: StatusKind::of(ahb_status),
232 unknown_ids: Vec::new(),
233 }
234 }
235 };
236
237 let mut holding: Option<Option<StatusKind>> = None;
238 let mut unknown: Vec<(Option<StatusKind>, &ConditionExpr)> = Vec::new();
239 for branch in &branches {
240 let result = branch
241 .condition
242 .as_ref()
243 .map_or(ConditionResult::True, |c| self.evaluate(c, ctx));
244 match result {
245 ConditionResult::True => {
246 holding = Some(holding.map_or(branch.kind, |k| k.max(branch.kind)));
247 }
248 ConditionResult::Unknown => {
249 if let Some(condition) = &branch.condition {
251 unknown.push((branch.kind, condition));
252 }
253 }
254 ConditionResult::False => {}
255 }
256 }
257
258 let blocking: Vec<&ConditionExpr> = unknown
260 .iter()
261 .filter(|(kind, _)| match holding {
262 None => true,
263 Some(h) => *kind > h,
264 })
265 .map(|(_, condition)| *condition)
266 .collect();
267
268 if !blocking.is_empty() {
269 return StatusResolution {
270 result: ConditionResult::Unknown,
271 kind: None,
272 unknown_ids: blocking
273 .into_iter()
274 .flat_map(|c| self.collect_unknown_ids(c, ctx))
275 .collect(),
276 };
277 }
278 match holding {
279 Some(kind) => StatusResolution {
280 result: ConditionResult::True,
281 kind,
282 unknown_ids: Vec::new(),
283 },
284 None => StatusResolution {
285 result: if branches.is_empty() {
286 ConditionResult::True
287 } else {
288 ConditionResult::False
289 },
290 kind: branches.iter().map(|b| b.kind).max().flatten(),
291 unknown_ids: Vec::new(),
292 },
293 }
294 }
295
296 fn collect_unknown_ids(&self, expr: &ConditionExpr, ctx: &EvaluationContext) -> Vec<u32> {
298 let mut ids = Vec::new();
299 self.collect_unknown_ids_inner(expr, ctx, &mut ids);
300 ids
301 }
302
303 fn collect_unknown_ids_inner(
304 &self,
305 expr: &ConditionExpr,
306 ctx: &EvaluationContext,
307 ids: &mut Vec<u32>,
308 ) {
309 match expr {
310 ConditionExpr::Ref(id) => {
311 if self.evaluator.evaluate(*id, ctx).is_unknown() {
312 ids.push(*id);
313 }
314 }
315 ConditionExpr::And(exprs) | ConditionExpr::Or(exprs) => {
316 for e in exprs {
317 self.collect_unknown_ids_inner(e, ctx, ids);
318 }
319 }
320 ConditionExpr::Xor(left, right) => {
321 self.collect_unknown_ids_inner(left, ctx, ids);
322 self.collect_unknown_ids_inner(right, ctx, ids);
323 }
324 ConditionExpr::Not(inner) => {
325 self.collect_unknown_ids_inner(inner, ctx, ids);
326 }
327 ConditionExpr::Package { .. } => {
328 }
330 }
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use super::super::evaluator::{ConditionResult as CR, NoOpExternalProvider};
337 use super::*;
338 use mig_types::segment::OwnedSegment;
339 use std::collections::HashMap;
340
341 struct MockEvaluator {
343 results: HashMap<u32, ConditionResult>,
344 external_ids: Vec<u32>,
345 }
346
347 impl MockEvaluator {
348 fn new() -> Self {
349 Self {
350 results: HashMap::new(),
351 external_ids: Vec::new(),
352 }
353 }
354
355 fn with_condition(mut self, id: u32, result: ConditionResult) -> Self {
356 self.results.insert(id, result);
357 self
358 }
359 }
360
361 impl ConditionEvaluator for MockEvaluator {
362 fn evaluate(&self, condition: u32, _ctx: &EvaluationContext) -> ConditionResult {
363 self.results
364 .get(&condition)
365 .copied()
366 .unwrap_or(ConditionResult::Unknown)
367 }
368
369 fn is_external(&self, condition: u32) -> bool {
370 self.external_ids.contains(&condition)
371 }
372
373 fn message_type(&self) -> &str {
374 "TEST"
375 }
376
377 fn format_version(&self) -> &str {
378 "FV_TEST"
379 }
380 }
381
382 fn empty_context() -> (NoOpExternalProvider, Vec<OwnedSegment>) {
383 (NoOpExternalProvider, Vec::new())
384 }
385
386 fn make_ctx<'a>(
387 external: &'a NoOpExternalProvider,
388 segments: &'a [OwnedSegment],
389 ) -> EvaluationContext<'a> {
390 EvaluationContext::new("11001", external, segments)
391 }
392
393 #[test]
396 fn test_eval_single_true() {
397 let eval = MockEvaluator::new().with_condition(1, CR::True);
398 let (ext, segs) = empty_context();
399 let ctx = make_ctx(&ext, &segs);
400 let expr_eval = ConditionExprEvaluator::new(&eval);
401
402 assert_eq!(expr_eval.evaluate(&ConditionExpr::Ref(1), &ctx), CR::True);
403 }
404
405 #[test]
406 fn test_eval_single_false() {
407 let eval = MockEvaluator::new().with_condition(1, CR::False);
408 let (ext, segs) = empty_context();
409 let ctx = make_ctx(&ext, &segs);
410 let expr_eval = ConditionExprEvaluator::new(&eval);
411
412 assert_eq!(expr_eval.evaluate(&ConditionExpr::Ref(1), &ctx), CR::False);
413 }
414
415 #[test]
416 fn test_eval_single_unknown() {
417 let eval = MockEvaluator::new(); let (ext, segs) = empty_context();
419 let ctx = make_ctx(&ext, &segs);
420 let expr_eval = ConditionExprEvaluator::new(&eval);
421
422 assert_eq!(
423 expr_eval.evaluate(&ConditionExpr::Ref(999), &ctx),
424 CR::Unknown
425 );
426 }
427
428 #[test]
431 fn test_eval_and_both_true() {
432 let eval = MockEvaluator::new()
433 .with_condition(1, CR::True)
434 .with_condition(2, CR::True);
435 let (ext, segs) = empty_context();
436 let ctx = make_ctx(&ext, &segs);
437 let expr_eval = ConditionExprEvaluator::new(&eval);
438
439 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
440 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
441 }
442
443 #[test]
444 fn test_eval_and_one_false_short_circuits() {
445 let eval = MockEvaluator::new()
446 .with_condition(1, CR::False)
447 .with_condition(2, CR::True);
448 let (ext, segs) = empty_context();
449 let ctx = make_ctx(&ext, &segs);
450 let expr_eval = ConditionExprEvaluator::new(&eval);
451
452 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
453 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
454 }
455
456 #[test]
457 fn test_eval_and_one_unknown_true_gives_unknown() {
458 let eval = MockEvaluator::new()
459 .with_condition(1, CR::True)
460 .with_condition(2, CR::Unknown);
461 let (ext, segs) = empty_context();
462 let ctx = make_ctx(&ext, &segs);
463 let expr_eval = ConditionExprEvaluator::new(&eval);
464
465 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
466 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
467 }
468
469 #[test]
470 fn test_eval_and_false_beats_unknown() {
471 let eval = MockEvaluator::new()
473 .with_condition(1, CR::False)
474 .with_condition(2, CR::Unknown);
475 let (ext, segs) = empty_context();
476 let ctx = make_ctx(&ext, &segs);
477 let expr_eval = ConditionExprEvaluator::new(&eval);
478
479 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
480 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
481 }
482
483 #[test]
484 fn test_eval_and_three_way() {
485 let eval = MockEvaluator::new()
486 .with_condition(182, CR::True)
487 .with_condition(6, CR::True)
488 .with_condition(570, 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::And(vec![
494 ConditionExpr::Ref(182),
495 ConditionExpr::Ref(6),
496 ConditionExpr::Ref(570),
497 ]);
498 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
499 }
500
501 #[test]
502 fn test_eval_and_three_way_one_false() {
503 let eval = MockEvaluator::new()
504 .with_condition(182, CR::True)
505 .with_condition(6, CR::True)
506 .with_condition(570, CR::False);
507 let (ext, segs) = empty_context();
508 let ctx = make_ctx(&ext, &segs);
509 let expr_eval = ConditionExprEvaluator::new(&eval);
510
511 let expr = ConditionExpr::And(vec![
512 ConditionExpr::Ref(182),
513 ConditionExpr::Ref(6),
514 ConditionExpr::Ref(570),
515 ]);
516 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
517 }
518
519 #[test]
522 fn test_eval_or_both_false() {
523 let eval = MockEvaluator::new()
524 .with_condition(1, CR::False)
525 .with_condition(2, CR::False);
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::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
531 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
532 }
533
534 #[test]
535 fn test_eval_or_one_true_short_circuits() {
536 let eval = MockEvaluator::new()
537 .with_condition(1, CR::False)
538 .with_condition(2, CR::True);
539 let (ext, segs) = empty_context();
540 let ctx = make_ctx(&ext, &segs);
541 let expr_eval = ConditionExprEvaluator::new(&eval);
542
543 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
544 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
545 }
546
547 #[test]
548 fn test_eval_or_true_beats_unknown() {
549 let eval = MockEvaluator::new()
550 .with_condition(1, CR::Unknown)
551 .with_condition(2, CR::True);
552 let (ext, segs) = empty_context();
553 let ctx = make_ctx(&ext, &segs);
554 let expr_eval = ConditionExprEvaluator::new(&eval);
555
556 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
557 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
558 }
559
560 #[test]
561 fn test_eval_or_false_and_unknown_gives_unknown() {
562 let eval = MockEvaluator::new()
563 .with_condition(1, CR::False)
564 .with_condition(2, CR::Unknown);
565 let (ext, segs) = empty_context();
566 let ctx = make_ctx(&ext, &segs);
567 let expr_eval = ConditionExprEvaluator::new(&eval);
568
569 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
570 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
571 }
572
573 #[test]
576 fn test_eval_xor_true_false() {
577 let eval = MockEvaluator::new()
578 .with_condition(1, CR::True)
579 .with_condition(2, CR::False);
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::Xor(
585 Box::new(ConditionExpr::Ref(1)),
586 Box::new(ConditionExpr::Ref(2)),
587 );
588 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
589 }
590
591 #[test]
592 fn test_eval_xor_both_true() {
593 let eval = MockEvaluator::new()
594 .with_condition(1, CR::True)
595 .with_condition(2, CR::True);
596 let (ext, segs) = empty_context();
597 let ctx = make_ctx(&ext, &segs);
598 let expr_eval = ConditionExprEvaluator::new(&eval);
599
600 let expr = ConditionExpr::Xor(
601 Box::new(ConditionExpr::Ref(1)),
602 Box::new(ConditionExpr::Ref(2)),
603 );
604 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
605 }
606
607 #[test]
608 fn test_eval_xor_both_false() {
609 let eval = MockEvaluator::new()
610 .with_condition(1, CR::False)
611 .with_condition(2, CR::False);
612 let (ext, segs) = empty_context();
613 let ctx = make_ctx(&ext, &segs);
614 let expr_eval = ConditionExprEvaluator::new(&eval);
615
616 let expr = ConditionExpr::Xor(
617 Box::new(ConditionExpr::Ref(1)),
618 Box::new(ConditionExpr::Ref(2)),
619 );
620 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
621 }
622
623 #[test]
624 fn test_eval_xor_unknown_propagates() {
625 let eval = MockEvaluator::new()
626 .with_condition(1, CR::True)
627 .with_condition(2, CR::Unknown);
628 let (ext, segs) = empty_context();
629 let ctx = make_ctx(&ext, &segs);
630 let expr_eval = ConditionExprEvaluator::new(&eval);
631
632 let expr = ConditionExpr::Xor(
633 Box::new(ConditionExpr::Ref(1)),
634 Box::new(ConditionExpr::Ref(2)),
635 );
636 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
637 }
638
639 #[test]
642 fn test_eval_not_true() {
643 let eval = MockEvaluator::new().with_condition(1, CR::True);
644 let (ext, segs) = empty_context();
645 let ctx = make_ctx(&ext, &segs);
646 let expr_eval = ConditionExprEvaluator::new(&eval);
647
648 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(1)));
649 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
650 }
651
652 #[test]
653 fn test_eval_not_false() {
654 let eval = MockEvaluator::new().with_condition(1, CR::False);
655 let (ext, segs) = empty_context();
656 let ctx = make_ctx(&ext, &segs);
657 let expr_eval = ConditionExprEvaluator::new(&eval);
658
659 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(1)));
660 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
661 }
662
663 #[test]
664 fn test_eval_not_unknown() {
665 let eval = MockEvaluator::new(); let (ext, segs) = empty_context();
667 let ctx = make_ctx(&ext, &segs);
668 let expr_eval = ConditionExprEvaluator::new(&eval);
669
670 let expr = ConditionExpr::Not(Box::new(ConditionExpr::Ref(1)));
671 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
672 }
673
674 #[test]
677 fn test_eval_complex_nested() {
678 let eval = MockEvaluator::new()
682 .with_condition(1, CR::True)
683 .with_condition(2, CR::False)
684 .with_condition(3, CR::True)
685 .with_condition(4, CR::True)
686 .with_condition(5, 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::And(vec![
692 ConditionExpr::Or(vec![
693 ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]),
694 ConditionExpr::And(vec![ConditionExpr::Ref(3), ConditionExpr::Ref(4)]),
695 ]),
696 ConditionExpr::Ref(5),
697 ]);
698 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
699 }
700
701 #[test]
702 fn test_eval_xor_with_nested_and() {
703 let eval = MockEvaluator::new()
707 .with_condition(102, CR::True)
708 .with_condition(2006, CR::True)
709 .with_condition(103, CR::False)
710 .with_condition(2005, CR::False);
711 let (ext, segs) = empty_context();
712 let ctx = make_ctx(&ext, &segs);
713 let expr_eval = ConditionExprEvaluator::new(&eval);
714
715 let expr = ConditionExpr::Xor(
716 Box::new(ConditionExpr::And(vec![
717 ConditionExpr::Ref(102),
718 ConditionExpr::Ref(2006),
719 ])),
720 Box::new(ConditionExpr::And(vec![
721 ConditionExpr::Ref(103),
722 ConditionExpr::Ref(2005),
723 ])),
724 );
725 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
726 }
727
728 #[test]
731 fn test_evaluate_status_with_conditions() {
732 let eval = MockEvaluator::new()
733 .with_condition(182, CR::True)
734 .with_condition(152, CR::True);
735 let (ext, segs) = empty_context();
736 let ctx = make_ctx(&ext, &segs);
737 let expr_eval = ConditionExprEvaluator::new(&eval);
738
739 assert_eq!(
740 expr_eval.evaluate_status("Muss [182] ∧ [152]", &ctx),
741 CR::True
742 );
743 }
744
745 #[test]
746 fn test_evaluate_status_no_conditions() {
747 let eval = MockEvaluator::new();
748 let (ext, segs) = empty_context();
749 let ctx = make_ctx(&ext, &segs);
750 let expr_eval = ConditionExprEvaluator::new(&eval);
751
752 assert_eq!(expr_eval.evaluate_status("Muss", &ctx), CR::True);
753 }
754
755 #[test]
756 fn test_evaluate_status_empty() {
757 let eval = MockEvaluator::new();
758 let (ext, segs) = empty_context();
759 let ctx = make_ctx(&ext, &segs);
760 let expr_eval = ConditionExprEvaluator::new(&eval);
761
762 assert_eq!(expr_eval.evaluate_status("", &ctx), CR::True);
763 }
764
765 #[test]
768 fn test_unknown_propagation_and_or_mix() {
769 let eval = MockEvaluator::new().with_condition(2, CR::True);
773 let (ext, segs) = empty_context();
775 let ctx = make_ctx(&ext, &segs);
776 let expr_eval = ConditionExprEvaluator::new(&eval);
777
778 let expr = ConditionExpr::Or(vec![
779 ConditionExpr::Ref(1),
780 ConditionExpr::And(vec![ConditionExpr::Ref(2), ConditionExpr::Ref(3)]),
781 ]);
782 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::Unknown);
783 }
784
785 #[test]
786 fn test_or_short_circuits_past_unknown() {
787 let eval = MockEvaluator::new().with_condition(2, CR::True);
789 let (ext, segs) = empty_context();
790 let ctx = make_ctx(&ext, &segs);
791 let expr_eval = ConditionExprEvaluator::new(&eval);
792
793 let expr = ConditionExpr::Or(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
794 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::True);
795 }
796
797 #[test]
798 fn test_and_short_circuits_past_unknown() {
799 let eval = MockEvaluator::new().with_condition(2, CR::False);
801 let (ext, segs) = empty_context();
802 let ctx = make_ctx(&ext, &segs);
803 let expr_eval = ConditionExprEvaluator::new(&eval);
804
805 let expr = ConditionExpr::And(vec![ConditionExpr::Ref(1), ConditionExpr::Ref(2)]);
806 assert_eq!(expr_eval.evaluate(&expr, &ctx), CR::False);
807 }
808
809 #[test]
812 fn test_detailed_returns_unknown_ids() {
813 let eval = MockEvaluator::new().with_condition(182, CR::True);
815 let (ext, segs) = empty_context();
816 let ctx = make_ctx(&ext, &segs);
817 let expr_eval = ConditionExprEvaluator::new(&eval);
818
819 let (result, unknown_ids) = expr_eval.evaluate_status_detailed("Muss [182] ∧ [8]", &ctx);
820 assert_eq!(result, CR::Unknown);
821 assert_eq!(unknown_ids, vec![8]);
822 }
823
824 #[test]
825 fn test_detailed_multiple_unknown_ids() {
826 let eval = MockEvaluator::new().with_condition(2, CR::True);
828 let (ext, segs) = empty_context();
829 let ctx = make_ctx(&ext, &segs);
830 let expr_eval = ConditionExprEvaluator::new(&eval);
831
832 let (result, unknown_ids) =
833 expr_eval.evaluate_status_detailed("Muss [1] ∧ [2] ∧ [3]", &ctx);
834 assert_eq!(result, CR::Unknown);
835 assert_eq!(unknown_ids, vec![1, 3]);
836 }
837
838 #[test]
839 fn test_detailed_no_unknown_when_true() {
840 let eval = MockEvaluator::new()
841 .with_condition(182, CR::True)
842 .with_condition(152, CR::True);
843 let (ext, segs) = empty_context();
844 let ctx = make_ctx(&ext, &segs);
845 let expr_eval = ConditionExprEvaluator::new(&eval);
846
847 let (result, unknown_ids) = expr_eval.evaluate_status_detailed("Muss [182] ∧ [152]", &ctx);
848 assert_eq!(result, CR::True);
849 assert!(unknown_ids.is_empty());
850 }
851
852 #[test]
853 fn test_detailed_no_unknown_when_false() {
854 let eval = MockEvaluator::new().with_condition(182, CR::False);
855 let (ext, segs) = empty_context();
856 let ctx = make_ctx(&ext, &segs);
857 let expr_eval = ConditionExprEvaluator::new(&eval);
858
859 let (result, unknown_ids) = expr_eval.evaluate_status_detailed("Muss [182] ∧ [8]", &ctx);
860 assert_eq!(result, CR::False);
861 assert!(unknown_ids.is_empty());
862 }
863
864 fn resolve(eval: &MockEvaluator, status: &str) -> StatusResolution {
867 let (ext, segs) = empty_context();
868 let ctx = make_ctx(&ext, &segs);
869 ConditionExprEvaluator::new(eval).resolve_status(status, &ctx, &Default::default())
870 }
871
872 #[test]
873 fn test_resolve_single_line_keeps_its_status() {
874 let eval = MockEvaluator::new().with_condition(1, CR::True);
875 let r = resolve(&eval, "Soll [1]");
876 assert_eq!((r.result, r.kind), (CR::True, Some(StatusKind::Soll)));
877 }
878
879 #[test]
880 fn test_resolve_only_later_line_holds_gives_its_status() {
881 let eval = MockEvaluator::new()
883 .with_condition(2119, CR::False)
884 .with_condition(130, CR::True);
885 let r = resolve(&eval, "Muss [2119]\r\nSoll [130]");
886 assert_eq!((r.result, r.kind), (CR::True, Some(StatusKind::Soll)));
887 }
888
889 #[test]
890 fn test_resolve_several_lines_hold_strictest_wins() {
891 let eval = MockEvaluator::new()
892 .with_condition(47, CR::True)
893 .with_condition(46, CR::True);
894 let r = resolve(&eval, "Soll [47]\nMuss [46]");
895 assert_eq!((r.result, r.kind), (CR::True, Some(StatusKind::Muss)));
896 }
897
898 #[test]
899 fn test_resolve_unconditional_fallback_line() {
900 let eval = MockEvaluator::new().with_condition(48, CR::False);
901 let r = resolve(&eval, "Muss [48]\nKann");
902 assert_eq!((r.result, r.kind), (CR::True, Some(StatusKind::Kann)));
903 }
904
905 #[test]
906 fn test_resolve_weaker_unknown_line_does_not_block() {
907 let eval = MockEvaluator::new().with_condition(2119, CR::True);
909 let r = resolve(&eval, "Muss [2119]\nSoll [130]");
910 assert_eq!((r.result, r.kind), (CR::True, Some(StatusKind::Muss)));
911 assert!(r.unknown_ids.is_empty());
912 }
913
914 #[test]
915 fn test_resolve_stronger_unknown_line_is_unknown() {
916 let eval = MockEvaluator::new().with_condition(130, CR::True);
918 let r = resolve(&eval, "Muss [2119]\nSoll [130]");
919 assert_eq!(r.result, CR::Unknown);
920 assert_eq!(r.unknown_ids, vec![2119]);
921 }
922
923 #[test]
924 fn test_resolve_equally_strong_unknown_line_does_not_block() {
925 let eval = MockEvaluator::new().with_condition(2, CR::True);
926 let r = resolve(&eval, "Muss [1]\nMuss [2]");
927 assert_eq!((r.result, r.kind), (CR::True, Some(StatusKind::Muss)));
928 }
929
930 #[test]
931 fn test_resolve_nothing_holds_but_something_unknown() {
932 let eval = MockEvaluator::new().with_condition(1, CR::False);
933 let r = resolve(&eval, "Muss [1]\nSoll [2]");
934 assert_eq!(r.result, CR::Unknown);
935 assert_eq!(r.unknown_ids, vec![2]);
936 }
937
938 #[test]
939 fn test_resolve_no_line_holds_reports_strictest_status() {
940 let eval = MockEvaluator::new()
941 .with_condition(1, CR::False)
942 .with_condition(2, CR::False);
943 let r = resolve(&eval, "Soll [1]\nMuss [2]");
944 assert_eq!((r.result, r.kind), (CR::False, Some(StatusKind::Muss)));
945 }
946}