use lopdf::{dictionary, Document, Object, ObjectStream};
#[test]
fn test_empty_trailer() {
let doc = Document::with_version("1.5");
let obj_id = (1, 0);
let obj = Object::Dictionary(dictionary! { "Test" => "Value" });
assert!(ObjectStream::can_be_compressed(obj_id, &obj, &doc),
"Object should be compressible with empty trailer");
}
#[test]
fn test_malformed_encrypt_reference() {
let mut doc = Document::with_version("1.5");
let obj_id = doc.add_object(dictionary! {
"Type" => "Catalog"
});
doc.trailer.set("Encrypt", Object::Reference((999, 99)));
assert!(ObjectStream::can_be_compressed(obj_id, doc.objects.get(&obj_id).unwrap(), &doc),
"Object should be compressible even with malformed Encrypt reference");
}
#[test]
fn test_self_referencing_object() {
let mut doc = Document::with_version("1.5");
let obj_id = (5, 0);
doc.objects.insert(obj_id, Object::Dictionary(dictionary! {
"Type" => "Test",
"Self" => Object::Reference(obj_id) }));
doc.trailer.set("Test", obj_id);
assert!(ObjectStream::can_be_compressed(obj_id, doc.objects.get(&obj_id).unwrap(), &doc),
"Self-referencing object should be compressible");
}
#[test]
fn test_circular_references() {
let mut doc = Document::with_version("1.5");
let obj1_id = (1, 0);
let obj2_id = (2, 0);
doc.objects.insert(obj1_id, Object::Dictionary(dictionary! {
"Next" => Object::Reference(obj2_id)
}));
doc.objects.insert(obj2_id, Object::Dictionary(dictionary! {
"Next" => Object::Reference(obj1_id) }));
doc.trailer.set("Start", obj1_id);
assert!(ObjectStream::can_be_compressed(obj1_id, doc.objects.get(&obj1_id).unwrap(), &doc),
"First object in circular reference should be compressible");
assert!(ObjectStream::can_be_compressed(obj2_id, doc.objects.get(&obj2_id).unwrap(), &doc),
"Second object in circular reference should be compressible");
}
#[test]
fn test_trailer_with_all_pdf_types() {
let mut doc = Document::with_version("1.5");
let obj_id = doc.add_object(dictionary! { "Type" => "Test" });
doc.trailer.set("Root", obj_id);
doc.trailer.set("Null", Object::Null);
doc.trailer.set("Bool", Object::Boolean(true));
doc.trailer.set("Int", Object::Integer(42));
doc.trailer.set("Real", Object::Real(3.14159));
doc.trailer.set("String", Object::String(b"test".to_vec(), lopdf::StringFormat::Literal));
doc.trailer.set("Name", Object::Name(b"Test".to_vec()));
doc.trailer.set("Array", Object::Array(vec![Object::Integer(1), Object::Integer(2)]));
doc.trailer.set("Dict", Object::Dictionary(dictionary! { "Key" => "Value" }));
assert!(ObjectStream::can_be_compressed(obj_id, doc.objects.get(&obj_id).unwrap(), &doc),
"Object should be compressible with diverse trailer entries");
}
#[test]
fn test_unicode_trailer_keys() {
let mut doc = Document::with_version("1.5");
let obj_id = doc.add_object(dictionary! { "Test" => "Value" });
doc.trailer.set("Root", obj_id);
doc.trailer.set("Ünïcödé", Object::String(b"test".to_vec(), lopdf::StringFormat::Literal));
doc.trailer.set("日本語", Object::Integer(42));
doc.trailer.set("🎯", Object::Boolean(true));
assert!(ObjectStream::can_be_compressed(obj_id, doc.objects.get(&obj_id).unwrap(), &doc),
"Object should be compressible with Unicode trailer keys");
}
#[test]
fn test_very_large_trailer() {
let mut doc = Document::with_version("1.5");
let obj_id = doc.add_object(dictionary! { "Type" => "Catalog" });
doc.trailer.set("Root", obj_id);
for i in 0..1000 {
doc.trailer.set(format!("Custom{:04}", i).as_bytes(), Object::Integer(i));
}
let start = std::time::Instant::now();
let compressible = ObjectStream::can_be_compressed(obj_id, doc.objects.get(&obj_id).unwrap(), &doc);
let duration = start.elapsed();
assert!(compressible, "Object should be compressible even with large trailer");
assert!(duration.as_micros() < 100, "Check should be fast even with large trailer");
}
#[test]
fn test_concurrent_modification_safety() {
let mut doc = Document::with_version("1.5");
let obj1_id = doc.add_object(dictionary! { "Type" => "Test1" });
let obj2_id = doc.add_object(dictionary! { "Type" => "Test2" });
doc.trailer.set("Ref1", obj1_id);
let result1 = ObjectStream::can_be_compressed(obj1_id, doc.objects.get(&obj1_id).unwrap(), &doc);
doc.trailer.set("Ref2", obj2_id);
doc.trailer.set("Encrypt", obj1_id);
let result2 = ObjectStream::can_be_compressed(obj1_id, doc.objects.get(&obj1_id).unwrap(), &doc);
assert!(result1, "Initially should be compressible");
assert!(!result2, "Should not be compressible after becoming encryption dict");
}