Skip to main content

ppt_rs/core/package_validation/
report.rs

1//! Structured validation report types.
2
3/// Severity of a package validation finding.
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
5pub enum ValidationSeverity {
6    Warning,
7    Error,
8}
9
10/// Category grouping for validation findings (used in tests and filtering).
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum ValidationCategory {
13    MissingPart,
14    Relationship,
15    ContentType,
16    Presentation,
17    SlideMaster,
18    Slide,
19    Chart,
20    Xml,
21    Theme,
22}
23
24/// A single structural issue found in a PPTX package.
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct PackageValidationIssue {
27    pub category: ValidationCategory,
28    pub severity: ValidationSeverity,
29    pub message: String,
30    /// Part path most relevant to the issue, when applicable.
31    pub path: Option<String>,
32}
33
34impl PackageValidationIssue {
35    pub fn error(
36        category: ValidationCategory,
37        message: impl Into<String>,
38        path: Option<&str>,
39    ) -> Self {
40        Self {
41            category,
42            severity: ValidationSeverity::Error,
43            message: message.into(),
44            path: path.map(str::to_string),
45        }
46    }
47
48    pub fn warning(
49        category: ValidationCategory,
50        message: impl Into<String>,
51        path: Option<&str>,
52    ) -> Self {
53        Self {
54            category,
55            severity: ValidationSeverity::Warning,
56            message: message.into(),
57            path: path.map(str::to_string),
58        }
59    }
60}
61
62/// Aggregated result of running all package validation rules.
63#[derive(Clone, Debug, Default, PartialEq, Eq)]
64pub struct PackageValidationReport {
65    pub issues: Vec<PackageValidationIssue>,
66}
67
68impl PackageValidationReport {
69    pub fn is_valid(&self) -> bool {
70        self.issues
71            .iter()
72            .all(|i| i.severity != ValidationSeverity::Error)
73    }
74
75    pub fn is_ok(&self) -> bool {
76        self.is_valid()
77    }
78
79    pub fn error_count(&self) -> usize {
80        self.issues
81            .iter()
82            .filter(|i| i.severity == ValidationSeverity::Error)
83            .count()
84    }
85
86    pub fn push(&mut self, issue: PackageValidationIssue) {
87        self.issues.push(issue);
88    }
89
90    pub fn extend(&mut self, issues: impl IntoIterator<Item = PackageValidationIssue>) {
91        self.issues.extend(issues);
92    }
93
94    /// Flat string list of error messages (compat with legacy `CompatReport`).
95    pub fn error_messages(&self) -> Vec<String> {
96        self.issues
97            .iter()
98            .filter(|i| i.severity == ValidationSeverity::Error)
99            .map(|i| i.message.clone())
100            .collect()
101    }
102
103    pub fn issues_in_category(
104        &self,
105        category: ValidationCategory,
106    ) -> impl Iterator<Item = &PackageValidationIssue> {
107        self.issues
108            .iter()
109            .filter(move |i| i.category == category)
110    }
111}