| 532 | |
| 533 | impl VerificationSummary { |
| 534 | pub fn from_reports(reports: &[VerificationReport]) -> Self { |
| 535 | let mut required_check_count = 0; |
| 536 | let mut pending_required_check_count = 0; |
| 537 | let mut failed_check_count = 0; |
| 538 | let mut residual_risk_count = 0; |
| 539 | let mut pending_subjects = Vec::new(); |
| 540 | let mut failed_subjects = Vec::new(); |
| 541 | |
| 542 | for report in reports { |
| 543 | if matches!(report.status, VerificationStatus::NeedsReview) { |
| 544 | pending_subjects.push(report.subject.clone()); |
| 545 | } |
| 546 | |
| 547 | if matches!(report.status, VerificationStatus::Failed) { |
| 548 | failed_subjects.push(report.subject.clone()); |
| 549 | } |
| 550 | |
| 551 | residual_risk_count += report.residual_risks.len(); |
| 552 | |
| 553 | for check in &report.checks { |
| 554 | if check.required { |
| 555 | required_check_count += 1; |
| 556 | if matches!( |
| 557 | check.status, |
| 558 | VerificationStatus::NeedsReview | VerificationStatus::Skipped |
| 559 | ) { |
| 560 | pending_required_check_count += 1; |
| 561 | pending_subjects.push(report.subject.clone()); |
| 562 | } |
| 563 | } |
| 564 | |
| 565 | if check.status == VerificationStatus::Failed { |
| 566 | failed_check_count += 1; |
| 567 | failed_subjects.push(report.subject.clone()); |
| 568 | } |
| 569 | |
| 570 | if check.residual_risk.is_some() { |
| 571 | residual_risk_count += 1; |
| 572 | pending_subjects.push(report.subject.clone()); |
| 573 | } |
| 574 | } |
| 575 | } |
| 576 | |
| 577 | pending_subjects.sort(); |
| 578 | pending_subjects.dedup(); |
| 579 | failed_subjects.sort(); |
| 580 | failed_subjects.dedup(); |
| 581 | |
| 582 | let status = if failed_check_count > 0 |
| 583 | || reports |
| 584 | .iter() |
| 585 | .any(|report| report.status == VerificationStatus::Failed) |
| 586 | { |
| 587 | VerificationStatus::Failed |
| 588 | } else if pending_required_check_count > 0 |
| 589 | || residual_risk_count > 0 |
| 590 | || reports |
| 591 | .iter() |