mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-30 04:58:34 -06:00
test: document the #3276 regression tests and helpers
This commit is contained in:
@@ -378,11 +378,13 @@ fn removing_an_inline_encrypt_dictionary_leaves_an_unencrypted_file() {
|
||||
// Undo can restore a snapshot whose output security differs from the last saved file (#3276).
|
||||
// Overlaying such a snapshot onto that file must be refused before anything changes.
|
||||
|
||||
/// Edit `/Title` in the document information dictionary: an unsaved change to compare.
|
||||
fn set_title(doc: &mut Document, title: &str) {
|
||||
let info = doc.trailer().reference(b"Info").unwrap();
|
||||
doc.update_dict(info, |d| d.set(b"Title".to_vec(), Object::String(PdfString { bytes: title.as_bytes().to_vec(), hex: false }))).unwrap();
|
||||
}
|
||||
|
||||
/// Protect again with the same passwords and no restrictions; `seed` picks the key and `/ID`.
|
||||
fn rekey(doc: &mut Document, alg: Algorithm, seed: u8) {
|
||||
doc.set_encryption(&NewEncryption {
|
||||
algorithm: alg,
|
||||
@@ -395,6 +397,7 @@ fn rekey(doc: &mut Document, alg: Algorithm, seed: u8) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Replace the first file identifier, which is part of the key, and keep the second.
|
||||
fn with_first_id(doc: &mut Document, id: &[u8]) {
|
||||
let Some(Object::Array(ids)) = doc.trailer().get(b"ID").cloned() else { panic!("no /ID") };
|
||||
let id = Object::String(PdfString { bytes: id.to_vec(), hex: true });
|
||||
@@ -407,6 +410,8 @@ fn state(doc: &Document) -> (Dict, Vec<u32>, Vec<u32>, bool, Vec<u8>) {
|
||||
(doc.trailer().clone(), doc.object_numbers(), doc.modified_objects(), doc.is_modified(), save)
|
||||
}
|
||||
|
||||
/// Every incompatible pairing is refused with `CosError::Security` and leaves the target exactly
|
||||
/// as it was; the same overlay with matching security does apply.
|
||||
#[test]
|
||||
fn an_overlay_with_different_output_security_is_refused_before_any_change() {
|
||||
let encrypted = Arc::new(protect(Algorithm::Aes256, "user", "owner", -1));
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
use super::*;
|
||||
use pdfcraft_cos::{Algorithm, Document as CosDocument, NewEncryption, Object};
|
||||
|
||||
/// A two-page file with a title and XMP metadata, protected with `user`/`owner` and no
|
||||
/// restrictions. `inline` moves `/Encrypt` into the trailer, as some writers store it.
|
||||
fn encrypted_fixture(algorithm: Algorithm, inline: bool) -> Arc<Vec<u8>> {
|
||||
let mut doc = CosDocument::open(Arc::new(fixture(2))).unwrap();
|
||||
pdfcraft_organize::set_info(&mut doc, "Title", "Security regression title").unwrap();
|
||||
@@ -59,6 +61,7 @@ fn assert_saved_content(s: &Session, id: DocId, bytes: Arc<Vec<u8>>, password: O
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove protection, save, undo, save: the file is encrypted again with its original passwords.
|
||||
#[test]
|
||||
fn undo_saved_security_removal_restores_encrypted_content() {
|
||||
let mut failures = Vec::new();
|
||||
@@ -94,6 +97,7 @@ fn undo_saved_security_removal_restores_encrypted_content() {
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
|
||||
/// Protect, save, undo, save: the file is plain again and readable without a password.
|
||||
#[test]
|
||||
fn undo_saved_protection_restores_plain_content() {
|
||||
let mut failures = Vec::new();
|
||||
@@ -121,6 +125,8 @@ fn undo_saved_protection_restores_plain_content() {
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
|
||||
/// Undoing a saved change of algorithm, permissions, metadata encryption or key restores the
|
||||
/// original security dictionary, even though the password strings never changed.
|
||||
#[test]
|
||||
fn undo_saved_rekey_with_the_same_passwords_restores_original_security() {
|
||||
let mut failures = Vec::new();
|
||||
@@ -155,6 +161,8 @@ fn undo_saved_rekey_with_the_same_passwords_restores_original_security() {
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
|
||||
/// A full save renumbers `/Encrypt`; undoing past it must not leave the restored dictionary
|
||||
/// encrypted as an ordinary object.
|
||||
#[test]
|
||||
fn undo_encrypted_compaction_restores_the_encrypt_dictionary_exemption() {
|
||||
let mut cos = CosDocument::open(Arc::new(fixture(3))).unwrap();
|
||||
@@ -220,6 +228,7 @@ fn undo_saved_removal_after_unlock_keeps_the_user_restrictions() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Undo across a save that kept the same security still appends to the last saved file.
|
||||
#[test]
|
||||
fn undo_ordinary_encrypted_edits_keeps_the_last_saved_revision() {
|
||||
let mut s = Session::new();
|
||||
@@ -237,6 +246,8 @@ fn undo_ordinary_encrypted_edits_keeps_the_last_saved_revision() {
|
||||
assert_saved_content(&s, id, rotated, Some("user"), true).unwrap();
|
||||
}
|
||||
|
||||
/// Undoing a saved password change restores the original passwords; the new ones no longer open
|
||||
/// the file.
|
||||
#[test]
|
||||
fn undo_saved_password_change_restores_original_passwords() {
|
||||
let mut s = Session::new();
|
||||
|
||||
Reference in New Issue
Block a user