use lopdf::{dictionary, Document, Object, ObjectStream, SaveOptions};
use std::time::Instant;
#[test]
fn test_can_be_compressed_performance() {
let mut doc = Document::with_version("1.5");
let mut object_ids = Vec::new();
for i in 0..1000 {
let obj_id = doc.add_object(dictionary! {
"Type" => format!("TestObject{}", i),
"Index" => i as i64,
"Data" => format!("This is test object number {}", i)
});
object_ids.push(obj_id);
}
doc.trailer.set("Root", object_ids[0]);
doc.trailer.set("Info", object_ids[1]);
doc.trailer.set("Custom1", object_ids[2]);
doc.trailer.set("Custom2", object_ids[3]);
let start = Instant::now();
let mut compressible_count = 0;
for &id in &object_ids {
if let Some(obj) = doc.objects.get(&id) {
if ObjectStream::can_be_compressed(id, obj, &doc) {
compressible_count += 1;
}
}
}
let duration = start.elapsed();
println!("Checked {} objects in {:?}", object_ids.len(), duration);
println!("Compressible objects: {}", compressible_count);
assert_eq!(compressible_count, object_ids.len(),
"All non-encryption objects should be compressible");
assert!(duration.as_millis() < 100,
"Performance check took too long: {:?}", duration);
}
#[test]
fn test_save_performance_with_trailer_objects() {
let mut doc = Document::with_version("1.5");
let pages_id = doc.new_object_id();
let mut page_ids = Vec::new();
for i in 0..100 {
let page_id = doc.add_object(dictionary! {
"Type" => "Page",
"Parent" => pages_id,
"MediaBox" => vec![0.into(), 0.into(), 612.into(), 792.into()],
"Contents" => Object::Reference((1000 + i, 0))
});
page_ids.push(page_id);
}
doc.objects.insert(pages_id, Object::Dictionary(dictionary! {
"Type" => "Pages",
"Kids" => page_ids.iter().map(|&id| Object::Reference(id)).collect::<Vec<_>>(),
"Count" => page_ids.len() as i64
}));
let catalog_id = doc.add_object(dictionary! {
"Type" => "Catalog",
"Pages" => pages_id
});
let info_id = doc.add_object(dictionary! {
"Title" => "Performance Test PDF",
"PageCount" => page_ids.len() as i64
});
doc.trailer.set("Root", catalog_id);
doc.trailer.set("Info", info_id);
for i in 0..10 {
doc.trailer.set(format!("Custom{}", i).as_bytes(), Object::Integer(i));
}
let options = SaveOptions::builder()
.use_object_streams(true)
.build();
let start = Instant::now();
let mut output = Vec::new();
doc.save_with_options(&mut output, options).unwrap();
let save_duration = start.elapsed();
println!("Saved {} page PDF in {:?}", page_ids.len(), save_duration);
println!("Output size: {} bytes", output.len());
assert!(save_duration.as_millis() < 500,
"Save took too long: {:?}", save_duration);
let content = String::from_utf8_lossy(&output);
assert!(content.contains("/ObjStm"), "Object streams should be created");
}
#[test]
fn test_encryption_check_performance() {
let mut doc = Document::with_version("1.5");
let encrypt_id = doc.add_object(dictionary! {
"Filter" => "Standard",
"V" => 2
});
doc.trailer.set("Encrypt", encrypt_id);
let mut other_ids = Vec::new();
for i in 0..1000 {
let id = doc.add_object(Object::Integer(i));
other_ids.push(id);
}
let start = Instant::now();
let encrypt_obj = doc.objects.get(&encrypt_id).unwrap();
let encrypt_compressible = ObjectStream::can_be_compressed(encrypt_id, encrypt_obj, &doc);
for &id in &other_ids[..100] { if let Some(obj) = doc.objects.get(&id) {
let _ = ObjectStream::can_be_compressed(id, obj, &doc);
}
}
let duration = start.elapsed();
println!("Encryption check performance: {:?} for 101 objects", duration);
assert!(!encrypt_compressible, "Encryption dict should not be compressible");
assert!(duration.as_micros() < 1000, "Check should be very fast");
}