use std::fmt;
pub const CHECK_NO_ENCRYPTION: &str = "no-encryption";
pub const CHECK_FONTS_EMBEDDED: &str = "fonts-embedded";
pub const CHECK_XMP_METADATA: &str = "xmp-metadata";
pub const CHECK_NO_LZW: &str = "no-lzw-filters";
pub const CHECK_NO_JAVASCRIPT: &str = "no-javascript";
pub const CHECK_METADATA_CONSISTENCY: &str = "metadata-consistency";
pub const CHECK_COLOR_SPACES: &str = "color-spaces";
pub const CHECK_NO_TRANSPARENCY: &str = "no-transparency";
pub const CHECK_OUTPUT_INTENT_PDFX: &str = "output-intent-pdfx";
pub const CHECK_TRIM_OR_ART_BOX: &str = "trim-or-art-box";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StandardsCheck {
pub id: &'static str,
pub description: &'static str,
pub passed: bool,
pub details: Vec<String>,
}
impl StandardsCheck {
pub fn pass(id: &'static str, description: &'static str) -> Self {
Self {
id,
description,
passed: true,
details: vec![],
}
}
pub fn fail(id: &'static str, description: &'static str, detail: impl Into<String>) -> Self {
Self {
id,
description,
passed: false,
details: vec![detail.into()],
}
}
pub fn from_details(id: &'static str, description: &'static str, details: Vec<String>) -> Self {
Self {
id,
description,
passed: details.is_empty(),
details,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StandardsReport {
pub standard: String,
pub checks: Vec<StandardsCheck>,
}
impl StandardsReport {
pub fn is_compliant(&self) -> bool {
self.checks.iter().all(|c| c.passed)
}
pub fn failures(&self) -> Vec<&StandardsCheck> {
self.checks.iter().filter(|c| !c.passed).collect()
}
pub fn total_checks(&self) -> usize {
self.checks.len()
}
pub fn passed_count(&self) -> usize {
self.checks.iter().filter(|c| c.passed).count()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PdfALevel {
A1b,
A2b,
A3b,
}
impl fmt::Display for PdfALevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PdfALevel::A1b => write!(f, "PDF/A-1b"),
PdfALevel::A2b => write!(f, "PDF/A-2b"),
PdfALevel::A3b => write!(f, "PDF/A-3b"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PdfXLevel {
X1a,
X3,
X4,
}
impl fmt::Display for PdfXLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PdfXLevel::X1a => write!(f, "PDF/X-1a:2001"),
PdfXLevel::X3 => write!(f, "PDF/X-3:2002"),
PdfXLevel::X4 => write!(f, "PDF/X-4"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn standards_check_creation() {
let check = StandardsCheck {
id: "test-check",
description: "A test check",
passed: true,
details: vec![],
};
assert!(check.passed);
assert_eq!(check.id, "test-check");
assert!(check.details.is_empty());
}
#[test]
fn standards_check_failing() {
let check = StandardsCheck {
id: "fail-check",
description: "A failing check",
passed: false,
details: vec!["Missing required field".into()],
};
assert!(!check.passed);
assert_eq!(check.details.len(), 1);
}
#[test]
fn standards_report_all_pass() {
let report = StandardsReport {
standard: "PDF/A-1b".into(),
checks: vec![
StandardsCheck {
id: "c1",
description: "Check 1",
passed: true,
details: vec![],
},
StandardsCheck {
id: "c2",
description: "Check 2",
passed: true,
details: vec![],
},
],
};
assert!(report.is_compliant());
assert!(report.failures().is_empty());
}
#[test]
fn standards_report_with_failures() {
let report = StandardsReport {
standard: "PDF/A-1b".into(),
checks: vec![
StandardsCheck {
id: "pass",
description: "Passes",
passed: true,
details: vec![],
},
StandardsCheck {
id: "fail",
description: "Fails",
passed: false,
details: vec!["bad".into()],
},
],
};
assert!(!report.is_compliant());
let failures = report.failures();
assert_eq!(failures.len(), 1);
assert_eq!(failures[0].id, "fail");
}
#[test]
fn standards_report_counts() {
let report = StandardsReport {
standard: "PDF/X-4".into(),
checks: vec![
StandardsCheck {
id: "a",
description: "A",
passed: true,
details: vec![],
},
StandardsCheck {
id: "b",
description: "B",
passed: false,
details: vec!["err".into()],
},
StandardsCheck {
id: "c",
description: "C",
passed: true,
details: vec![],
},
],
};
assert_eq!(report.total_checks(), 3);
assert_eq!(report.passed_count(), 2);
}
#[test]
fn pdfa_level_display() {
assert_eq!(format!("{}", PdfALevel::A1b), "PDF/A-1b");
assert_eq!(format!("{}", PdfALevel::A2b), "PDF/A-2b");
assert_eq!(format!("{}", PdfALevel::A3b), "PDF/A-3b");
}
#[test]
fn pdfx_level_display() {
assert_eq!(format!("{}", PdfXLevel::X1a), "PDF/X-1a:2001");
assert_eq!(format!("{}", PdfXLevel::X3), "PDF/X-3:2002");
assert_eq!(format!("{}", PdfXLevel::X4), "PDF/X-4");
}
#[test]
fn standards_report_empty() {
let report = StandardsReport {
standard: "Test".into(),
checks: vec![],
};
assert!(report.is_compliant());
assert_eq!(report.total_checks(), 0);
assert_eq!(report.passed_count(), 0);
}
}