use std::path::PathBuf;
use pdfluent::prelude::*;
use pdfluent::redact::RedactOptions;
fn mini(name: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../tests/corpus-mini")
.join(name)
}
fn pick_token(text: &str) -> Option<String> {
text.split(|c: char| !c.is_ascii_alphabetic())
.find(|w| w.len() >= 4)
.map(|w| w.to_string())
}
#[test]
fn qr15_redaction_removes_underlying_text() {
for name in ["multi-page.pdf", "simple.pdf", "acroform.pdf"] {
let Ok(bytes) = std::fs::read(mini(name)) else {
continue;
};
let Ok(doc) = PdfDocument::from_bytes(&bytes) else {
continue;
};
let Ok(text) = doc.extract_text() else {
continue;
};
let Some(token) = pick_token(&text) else {
continue; };
assert!(
text.to_lowercase().contains(&token.to_lowercase()),
"{name}: token '{token}' should be present pre-redaction"
);
let mut doc = PdfDocument::from_bytes(&bytes).expect("reopen for redact");
if doc.redact(&token, RedactOptions::new()).is_err() {
continue;
}
let out = doc.to_bytes().expect("persist redacted");
let reopened = PdfDocument::from_bytes(&out).expect("reopen redacted");
let after = reopened.extract_text().unwrap_or_default().to_lowercase();
assert!(
!after.contains(&token.to_lowercase()),
"{name}: redacted token '{token}' must NOT be extractable after redaction \
(content must be removed, not merely covered)"
);
return; }
eprintln!("QR-15: no fixture with extractable redactable text — skipped");
}