1use crate::error::Result;
2use crate::objects::{Object, ObjectId};
3use crate::page::Page;
4use crate::writer::PdfWriter;
5use chrono::{DateTime, Local, Utc};
6use std::collections::HashMap;
7
8pub struct Document {
25 pub(crate) pages: Vec<Page>,
26 #[allow(dead_code)]
27 pub(crate) objects: HashMap<ObjectId, Object>,
28 #[allow(dead_code)]
29 pub(crate) next_object_id: u32,
30 pub(crate) metadata: DocumentMetadata,
31}
32
33#[derive(Debug, Clone)]
35pub struct DocumentMetadata {
36 pub title: Option<String>,
38 pub author: Option<String>,
40 pub subject: Option<String>,
42 pub keywords: Option<String>,
44 pub creator: Option<String>,
46 pub producer: Option<String>,
48 pub creation_date: Option<DateTime<Utc>>,
50 pub modification_date: Option<DateTime<Utc>>,
52}
53
54impl Default for DocumentMetadata {
55 fn default() -> Self {
56 let now = Utc::now();
57 Self {
58 title: None,
59 author: None,
60 subject: None,
61 keywords: None,
62 creator: Some("oxidize_pdf".to_string()),
63 producer: Some(format!("oxidize_pdf v{}", env!("CARGO_PKG_VERSION"))),
64 creation_date: Some(now),
65 modification_date: Some(now),
66 }
67 }
68}
69
70impl Document {
71 pub fn new() -> Self {
73 Self {
74 pages: Vec::new(),
75 objects: HashMap::new(),
76 next_object_id: 1,
77 metadata: DocumentMetadata::default(),
78 }
79 }
80
81 pub fn add_page(&mut self, page: Page) {
83 self.pages.push(page);
84 }
85
86 pub fn set_title(&mut self, title: impl Into<String>) {
88 self.metadata.title = Some(title.into());
89 }
90
91 pub fn set_author(&mut self, author: impl Into<String>) {
93 self.metadata.author = Some(author.into());
94 }
95
96 pub fn set_subject(&mut self, subject: impl Into<String>) {
98 self.metadata.subject = Some(subject.into());
99 }
100
101 pub fn set_keywords(&mut self, keywords: impl Into<String>) {
103 self.metadata.keywords = Some(keywords.into());
104 }
105
106 pub fn set_creator(&mut self, creator: impl Into<String>) {
108 self.metadata.creator = Some(creator.into());
109 }
110
111 pub fn set_producer(&mut self, producer: impl Into<String>) {
113 self.metadata.producer = Some(producer.into());
114 }
115
116 pub fn set_creation_date(&mut self, date: DateTime<Utc>) {
118 self.metadata.creation_date = Some(date);
119 }
120
121 pub fn set_creation_date_local(&mut self, date: DateTime<Local>) {
123 self.metadata.creation_date = Some(date.with_timezone(&Utc));
124 }
125
126 pub fn set_modification_date(&mut self, date: DateTime<Utc>) {
128 self.metadata.modification_date = Some(date);
129 }
130
131 pub fn set_modification_date_local(&mut self, date: DateTime<Local>) {
133 self.metadata.modification_date = Some(date.with_timezone(&Utc));
134 }
135
136 pub fn update_modification_date(&mut self) {
138 self.metadata.modification_date = Some(Utc::now());
139 }
140
141 pub fn page_count(&self) -> usize {
143 self.pages.len()
144 }
145
146 pub fn save(&mut self, path: impl AsRef<std::path::Path>) -> Result<()> {
152 self.update_modification_date();
154
155 let mut writer = PdfWriter::new(path)?;
156 writer.write_document(self)?;
157 Ok(())
158 }
159
160 pub fn write(&mut self, buffer: &mut Vec<u8>) -> Result<()> {
166 self.update_modification_date();
168
169 let mut writer = PdfWriter::new_with_writer(buffer);
170 writer.write_document(self)?;
171 Ok(())
172 }
173
174 #[allow(dead_code)]
175 pub(crate) fn allocate_object_id(&mut self) -> ObjectId {
176 let id = ObjectId::new(self.next_object_id, 0);
177 self.next_object_id += 1;
178 id
179 }
180
181 #[allow(dead_code)]
182 pub(crate) fn add_object(&mut self, obj: Object) -> ObjectId {
183 let id = self.allocate_object_id();
184 self.objects.insert(id, obj);
185 id
186 }
187}
188
189impl Default for Document {
190 fn default() -> Self {
191 Self::new()
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_document_new() {
201 let doc = Document::new();
202 assert!(doc.pages.is_empty());
203 assert!(doc.objects.is_empty());
204 assert_eq!(doc.next_object_id, 1);
205 assert!(doc.metadata.title.is_none());
206 assert!(doc.metadata.author.is_none());
207 assert!(doc.metadata.subject.is_none());
208 assert!(doc.metadata.keywords.is_none());
209 assert_eq!(doc.metadata.creator, Some("oxidize_pdf".to_string()));
210 assert!(doc
211 .metadata
212 .producer
213 .as_ref()
214 .unwrap()
215 .starts_with("oxidize_pdf"));
216 }
217
218 #[test]
219 fn test_document_default() {
220 let doc = Document::default();
221 assert!(doc.pages.is_empty());
222 assert_eq!(doc.next_object_id, 1);
223 }
224
225 #[test]
226 fn test_add_page() {
227 let mut doc = Document::new();
228 let page1 = Page::a4();
229 let page2 = Page::letter();
230
231 doc.add_page(page1);
232 assert_eq!(doc.pages.len(), 1);
233
234 doc.add_page(page2);
235 assert_eq!(doc.pages.len(), 2);
236 }
237
238 #[test]
239 fn test_set_title() {
240 let mut doc = Document::new();
241 assert!(doc.metadata.title.is_none());
242
243 doc.set_title("Test Document");
244 assert_eq!(doc.metadata.title, Some("Test Document".to_string()));
245
246 doc.set_title(String::from("Another Title"));
247 assert_eq!(doc.metadata.title, Some("Another Title".to_string()));
248 }
249
250 #[test]
251 fn test_set_author() {
252 let mut doc = Document::new();
253 assert!(doc.metadata.author.is_none());
254
255 doc.set_author("John Doe");
256 assert_eq!(doc.metadata.author, Some("John Doe".to_string()));
257 }
258
259 #[test]
260 fn test_set_subject() {
261 let mut doc = Document::new();
262 assert!(doc.metadata.subject.is_none());
263
264 doc.set_subject("Test Subject");
265 assert_eq!(doc.metadata.subject, Some("Test Subject".to_string()));
266 }
267
268 #[test]
269 fn test_set_keywords() {
270 let mut doc = Document::new();
271 assert!(doc.metadata.keywords.is_none());
272
273 doc.set_keywords("test, pdf, rust");
274 assert_eq!(doc.metadata.keywords, Some("test, pdf, rust".to_string()));
275 }
276
277 #[test]
278 fn test_metadata_default() {
279 let metadata = DocumentMetadata::default();
280 assert!(metadata.title.is_none());
281 assert!(metadata.author.is_none());
282 assert!(metadata.subject.is_none());
283 assert!(metadata.keywords.is_none());
284 assert_eq!(metadata.creator, Some("oxidize_pdf".to_string()));
285 assert!(metadata
286 .producer
287 .as_ref()
288 .unwrap()
289 .starts_with("oxidize_pdf"));
290 }
291
292 #[test]
293 fn test_allocate_object_id() {
294 let mut doc = Document::new();
295
296 let id1 = doc.allocate_object_id();
297 assert_eq!(id1.number(), 1);
298 assert_eq!(id1.generation(), 0);
299 assert_eq!(doc.next_object_id, 2);
300
301 let id2 = doc.allocate_object_id();
302 assert_eq!(id2.number(), 2);
303 assert_eq!(id2.generation(), 0);
304 assert_eq!(doc.next_object_id, 3);
305 }
306
307 #[test]
308 fn test_add_object() {
309 let mut doc = Document::new();
310 assert!(doc.objects.is_empty());
311
312 let obj = Object::Boolean(true);
313 let id = doc.add_object(obj.clone());
314
315 assert_eq!(id.number(), 1);
316 assert_eq!(doc.objects.len(), 1);
317 assert!(doc.objects.contains_key(&id));
318 }
319
320 #[test]
321 fn test_write_to_buffer() {
322 let mut doc = Document::new();
323 doc.set_title("Buffer Test");
324 doc.add_page(Page::a4());
325
326 let mut buffer = Vec::new();
327 let result = doc.write(&mut buffer);
328
329 assert!(result.is_ok());
330 assert!(!buffer.is_empty());
331 assert!(buffer.starts_with(b"%PDF-1.7"));
332 }
333
334 #[test]
335 fn test_document_with_multiple_pages() {
336 let mut doc = Document::new();
337 doc.set_title("Multi-page Document");
338 doc.set_author("Test Author");
339 doc.set_subject("Testing multiple pages");
340 doc.set_keywords("test, multiple, pages");
341
342 for _ in 0..5 {
343 doc.add_page(Page::a4());
344 }
345
346 assert_eq!(doc.pages.len(), 5);
347 assert_eq!(doc.metadata.title, Some("Multi-page Document".to_string()));
348 assert_eq!(doc.metadata.author, Some("Test Author".to_string()));
349 }
350
351 #[test]
352 fn test_empty_document_write() {
353 let mut doc = Document::new();
354 let mut buffer = Vec::new();
355
356 let result = doc.write(&mut buffer);
358 assert!(result.is_ok());
359 assert!(!buffer.is_empty());
360 assert!(buffer.starts_with(b"%PDF-1.7"));
361 }
362
363 mod integration_tests {
365 use super::*;
366 use crate::graphics::Color;
367 use crate::text::Font;
368 use std::fs;
369 use tempfile::TempDir;
370
371 #[test]
372 fn test_document_writer_roundtrip() {
373 let temp_dir = TempDir::new().unwrap();
374 let file_path = temp_dir.path().join("test.pdf");
375
376 let mut doc = Document::new();
378 doc.set_title("Integration Test");
379 doc.set_author("Test Author");
380 doc.set_subject("Writer Integration");
381 doc.set_keywords("test, writer, integration");
382
383 let mut page = Page::a4();
384 page.text()
385 .set_font(Font::Helvetica, 12.0)
386 .at(100.0, 700.0)
387 .write("Integration Test Content")
388 .unwrap();
389
390 doc.add_page(page);
391
392 let result = doc.save(&file_path);
394 assert!(result.is_ok());
395
396 assert!(file_path.exists());
398 let metadata = fs::metadata(&file_path).unwrap();
399 assert!(metadata.len() > 0);
400
401 let content = fs::read(&file_path).unwrap();
403 assert!(content.starts_with(b"%PDF-1.7"));
404 assert!(content.ends_with(b"%%EOF\n") || content.ends_with(b"%%EOF"));
406 }
407
408 #[test]
409 fn test_document_with_complex_content() {
410 let temp_dir = TempDir::new().unwrap();
411 let file_path = temp_dir.path().join("complex.pdf");
412
413 let mut doc = Document::new();
414 doc.set_title("Complex Content Test");
415
416 let mut page = Page::a4();
418
419 page.text()
421 .set_font(Font::Helvetica, 14.0)
422 .at(50.0, 750.0)
423 .write("Complex Content Test")
424 .unwrap();
425
426 page.graphics()
428 .set_fill_color(Color::rgb(0.8, 0.2, 0.2))
429 .rectangle(50.0, 500.0, 200.0, 100.0)
430 .fill();
431
432 page.graphics()
433 .set_stroke_color(Color::rgb(0.2, 0.2, 0.8))
434 .set_line_width(2.0)
435 .move_to(50.0, 400.0)
436 .line_to(250.0, 400.0)
437 .stroke();
438
439 doc.add_page(page);
440
441 let result = doc.save(&file_path);
443 assert!(result.is_ok());
444 assert!(file_path.exists());
445 }
446
447 #[test]
448 fn test_document_multiple_pages_integration() {
449 let temp_dir = TempDir::new().unwrap();
450 let file_path = temp_dir.path().join("multipage.pdf");
451
452 let mut doc = Document::new();
453 doc.set_title("Multi-page Integration Test");
454
455 for i in 1..=5 {
457 let mut page = Page::a4();
458
459 page.text()
460 .set_font(Font::Helvetica, 16.0)
461 .at(50.0, 750.0)
462 .write(&format!("Page {}", i))
463 .unwrap();
464
465 page.text()
466 .set_font(Font::Helvetica, 12.0)
467 .at(50.0, 700.0)
468 .write(&format!("This is the content for page {}", i))
469 .unwrap();
470
471 let color = match i % 3 {
473 0 => Color::rgb(1.0, 0.0, 0.0),
474 1 => Color::rgb(0.0, 1.0, 0.0),
475 _ => Color::rgb(0.0, 0.0, 1.0),
476 };
477
478 page.graphics()
479 .set_fill_color(color)
480 .rectangle(50.0, 600.0, 100.0, 50.0)
481 .fill();
482
483 doc.add_page(page);
484 }
485
486 let result = doc.save(&file_path);
488 assert!(result.is_ok());
489 assert!(file_path.exists());
490
491 let metadata = fs::metadata(&file_path).unwrap();
493 assert!(metadata.len() > 1000); }
495
496 #[test]
497 fn test_document_metadata_persistence() {
498 let temp_dir = TempDir::new().unwrap();
499 let file_path = temp_dir.path().join("metadata.pdf");
500
501 let mut doc = Document::new();
502 doc.set_title("Metadata Persistence Test");
503 doc.set_author("Test Author");
504 doc.set_subject("Testing metadata preservation");
505 doc.set_keywords("metadata, persistence, test");
506
507 doc.add_page(Page::a4());
508
509 let result = doc.save(&file_path);
511 assert!(result.is_ok());
512
513 let content = fs::read(&file_path).unwrap();
515 let content_str = String::from_utf8_lossy(&content);
516
517 assert!(content_str.contains("Metadata Persistence Test"));
519 assert!(content_str.contains("Test Author"));
520 }
521
522 #[test]
523 fn test_document_writer_error_handling() {
524 let mut doc = Document::new();
525 doc.add_page(Page::a4());
526
527 let result = doc.save("/invalid/path/test.pdf");
529 assert!(result.is_err());
530 }
531
532 #[test]
533 fn test_document_object_management() {
534 let mut doc = Document::new();
535
536 let obj1 = Object::Boolean(true);
538 let obj2 = Object::Integer(42);
539 let obj3 = Object::Real(3.14);
540
541 let id1 = doc.add_object(obj1.clone());
542 let id2 = doc.add_object(obj2.clone());
543 let id3 = doc.add_object(obj3.clone());
544
545 assert_eq!(id1.number(), 1);
546 assert_eq!(id2.number(), 2);
547 assert_eq!(id3.number(), 3);
548
549 assert_eq!(doc.objects.len(), 3);
550 assert!(doc.objects.contains_key(&id1));
551 assert!(doc.objects.contains_key(&id2));
552 assert!(doc.objects.contains_key(&id3));
553
554 assert_eq!(doc.objects.get(&id1), Some(&obj1));
556 assert_eq!(doc.objects.get(&id2), Some(&obj2));
557 assert_eq!(doc.objects.get(&id3), Some(&obj3));
558 }
559
560 #[test]
561 fn test_document_page_integration() {
562 let mut doc = Document::new();
563
564 let page1 = Page::a4();
566 let page2 = Page::letter();
567 let mut page3 = Page::new(500.0, 400.0);
568
569 page3
571 .text()
572 .set_font(Font::Helvetica, 10.0)
573 .at(25.0, 350.0)
574 .write("Custom size page")
575 .unwrap();
576
577 doc.add_page(page1);
578 doc.add_page(page2);
579 doc.add_page(page3);
580
581 assert_eq!(doc.pages.len(), 3);
582
583 assert!(doc.pages[0].width() > 500.0); assert!(doc.pages[0].height() > 700.0); assert!(doc.pages[1].width() > 500.0); assert!(doc.pages[1].height() > 700.0); assert_eq!(doc.pages[2].width(), 500.0); assert_eq!(doc.pages[2].height(), 400.0); }
591
592 #[test]
593 fn test_document_content_generation() {
594 let temp_dir = TempDir::new().unwrap();
595 let file_path = temp_dir.path().join("content.pdf");
596
597 let mut doc = Document::new();
598 doc.set_title("Content Generation Test");
599
600 let mut page = Page::a4();
601
602 for i in 0..10 {
604 let y_pos = 700.0 - (i as f64 * 30.0);
605 page.text()
606 .set_font(Font::Helvetica, 12.0)
607 .at(50.0, y_pos)
608 .write(&format!("Generated line {}", i + 1))
609 .unwrap();
610 }
611
612 doc.add_page(page);
613
614 let result = doc.save(&file_path);
616 assert!(result.is_ok());
617 assert!(file_path.exists());
618
619 let metadata = fs::metadata(&file_path).unwrap();
621 assert!(metadata.len() > 500); }
623
624 #[test]
625 fn test_document_buffer_vs_file_write() {
626 let temp_dir = TempDir::new().unwrap();
627 let file_path = temp_dir.path().join("buffer_vs_file.pdf");
628
629 let mut doc = Document::new();
630 doc.set_title("Buffer vs File Test");
631 doc.add_page(Page::a4());
632
633 let mut buffer = Vec::new();
635 let buffer_result = doc.write(&mut buffer);
636 assert!(buffer_result.is_ok());
637
638 let file_result = doc.save(&file_path);
640 assert!(file_result.is_ok());
641
642 let file_content = fs::read(&file_path).unwrap();
644
645 assert!(buffer.starts_with(b"%PDF-1.7"));
647 assert!(file_content.starts_with(b"%PDF-1.7"));
648 assert!(buffer.ends_with(b"%%EOF\n"));
649 assert!(file_content.ends_with(b"%%EOF\n"));
650
651 let buffer_str = String::from_utf8_lossy(&buffer);
653 let file_str = String::from_utf8_lossy(&file_content);
654 assert!(buffer_str.contains("Buffer vs File Test"));
655 assert!(file_str.contains("Buffer vs File Test"));
656 }
657
658 #[test]
659 fn test_document_large_content_handling() {
660 let temp_dir = TempDir::new().unwrap();
661 let file_path = temp_dir.path().join("large_content.pdf");
662
663 let mut doc = Document::new();
664 doc.set_title("Large Content Test");
665
666 let mut page = Page::a4();
667
668 let large_text =
670 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ".repeat(200);
671 page.text()
672 .set_font(Font::Helvetica, 10.0)
673 .at(50.0, 750.0)
674 .write(&large_text)
675 .unwrap();
676
677 doc.add_page(page);
678
679 let result = doc.save(&file_path);
681 assert!(result.is_ok());
682 assert!(file_path.exists());
683
684 let metadata = fs::metadata(&file_path).unwrap();
686 assert!(metadata.len() > 2000); }
688
689 #[test]
690 fn test_document_incremental_building() {
691 let temp_dir = TempDir::new().unwrap();
692 let file_path = temp_dir.path().join("incremental.pdf");
693
694 let mut doc = Document::new();
695
696 doc.set_title("Incremental Building Test");
698
699 let mut page1 = Page::a4();
701 page1
702 .text()
703 .set_font(Font::Helvetica, 12.0)
704 .at(50.0, 750.0)
705 .write("First page content")
706 .unwrap();
707 doc.add_page(page1);
708
709 doc.set_author("Incremental Author");
711 doc.set_subject("Incremental Subject");
712
713 let mut page2 = Page::a4();
715 page2
716 .text()
717 .set_font(Font::Helvetica, 12.0)
718 .at(50.0, 750.0)
719 .write("Second page content")
720 .unwrap();
721 doc.add_page(page2);
722
723 doc.set_keywords("incremental, building, test");
725
726 let result = doc.save(&file_path);
728 assert!(result.is_ok());
729 assert!(file_path.exists());
730
731 assert_eq!(doc.pages.len(), 2);
733 assert_eq!(
734 doc.metadata.title,
735 Some("Incremental Building Test".to_string())
736 );
737 assert_eq!(doc.metadata.author, Some("Incremental Author".to_string()));
738 assert_eq!(
739 doc.metadata.subject,
740 Some("Incremental Subject".to_string())
741 );
742 assert_eq!(
743 doc.metadata.keywords,
744 Some("incremental, building, test".to_string())
745 );
746 }
747
748 #[test]
749 fn test_document_concurrent_page_operations() {
750 let mut doc = Document::new();
751 doc.set_title("Concurrent Operations Test");
752
753 let mut pages = Vec::new();
755
756 for i in 0..5 {
758 let mut page = Page::a4();
759 page.text()
760 .set_font(Font::Helvetica, 12.0)
761 .at(50.0, 750.0)
762 .write(&format!("Concurrent page {}", i))
763 .unwrap();
764 pages.push(page);
765 }
766
767 for page in pages {
769 doc.add_page(page);
770 }
771
772 assert_eq!(doc.pages.len(), 5);
773
774 let temp_dir = TempDir::new().unwrap();
776 let file_path = temp_dir.path().join("concurrent.pdf");
777 let result = doc.save(&file_path);
778 assert!(result.is_ok());
779 }
780
781 #[test]
782 fn test_document_memory_efficiency() {
783 let mut doc = Document::new();
784 doc.set_title("Memory Efficiency Test");
785
786 for i in 0..10 {
788 let mut page = Page::a4();
789 page.text()
790 .set_font(Font::Helvetica, 12.0)
791 .at(50.0, 700.0)
792 .write(&format!("Memory test page {}", i))
793 .unwrap();
794 doc.add_page(page);
795 }
796
797 let mut buffer = Vec::new();
799 let result = doc.write(&mut buffer);
800 assert!(result.is_ok());
801 assert!(!buffer.is_empty());
802
803 assert!(buffer.len() < 1_000_000); }
806
807 #[test]
808 fn test_document_creator_producer() {
809 let mut doc = Document::new();
810
811 assert_eq!(doc.metadata.creator, Some("oxidize_pdf".to_string()));
813 assert!(doc
814 .metadata
815 .producer
816 .as_ref()
817 .unwrap()
818 .contains("oxidize_pdf"));
819
820 doc.set_creator("My Application");
822 doc.set_producer("My PDF Library v1.0");
823
824 assert_eq!(doc.metadata.creator, Some("My Application".to_string()));
825 assert_eq!(
826 doc.metadata.producer,
827 Some("My PDF Library v1.0".to_string())
828 );
829 }
830
831 #[test]
832 fn test_document_dates() {
833 use chrono::{TimeZone, Utc};
834
835 let mut doc = Document::new();
836
837 assert!(doc.metadata.creation_date.is_some());
839 assert!(doc.metadata.modification_date.is_some());
840
841 let creation_date = Utc.with_ymd_and_hms(2023, 1, 1, 12, 0, 0).unwrap();
843 let mod_date = Utc.with_ymd_and_hms(2023, 6, 15, 18, 30, 0).unwrap();
844
845 doc.set_creation_date(creation_date);
846 doc.set_modification_date(mod_date);
847
848 assert_eq!(doc.metadata.creation_date, Some(creation_date));
849 assert_eq!(doc.metadata.modification_date, Some(mod_date));
850 }
851
852 #[test]
853 fn test_document_dates_local() {
854 use chrono::{Local, TimeZone};
855
856 let mut doc = Document::new();
857
858 let local_date = Local.with_ymd_and_hms(2023, 12, 25, 10, 30, 0).unwrap();
860 doc.set_creation_date_local(local_date);
861
862 assert!(doc.metadata.creation_date.is_some());
864 assert!(doc.metadata.creation_date.is_some());
866 }
867
868 #[test]
869 fn test_update_modification_date() {
870 let mut doc = Document::new();
871
872 let initial_mod_date = doc.metadata.modification_date;
873 assert!(initial_mod_date.is_some());
874
875 std::thread::sleep(std::time::Duration::from_millis(10));
877
878 doc.update_modification_date();
879
880 let new_mod_date = doc.metadata.modification_date;
881 assert!(new_mod_date.is_some());
882 assert!(new_mod_date.unwrap() > initial_mod_date.unwrap());
883 }
884
885 #[test]
886 fn test_document_save_updates_modification_date() {
887 let temp_dir = TempDir::new().unwrap();
888 let file_path = temp_dir.path().join("mod_date_test.pdf");
889
890 let mut doc = Document::new();
891 doc.add_page(Page::a4());
892
893 let initial_mod_date = doc.metadata.modification_date;
894
895 std::thread::sleep(std::time::Duration::from_millis(10));
897
898 doc.save(&file_path).unwrap();
899
900 assert!(doc.metadata.modification_date.unwrap() > initial_mod_date.unwrap());
902 }
903
904 #[test]
905 fn test_document_metadata_complete() {
906 let mut doc = Document::new();
907
908 doc.set_title("Complete Metadata Test");
910 doc.set_author("Test Author");
911 doc.set_subject("Testing all metadata fields");
912 doc.set_keywords("test, metadata, complete");
913 doc.set_creator("Test Application v1.0");
914 doc.set_producer("oxidize_pdf Test Suite");
915
916 assert_eq!(
918 doc.metadata.title,
919 Some("Complete Metadata Test".to_string())
920 );
921 assert_eq!(doc.metadata.author, Some("Test Author".to_string()));
922 assert_eq!(
923 doc.metadata.subject,
924 Some("Testing all metadata fields".to_string())
925 );
926 assert_eq!(
927 doc.metadata.keywords,
928 Some("test, metadata, complete".to_string())
929 );
930 assert_eq!(
931 doc.metadata.creator,
932 Some("Test Application v1.0".to_string())
933 );
934 assert_eq!(
935 doc.metadata.producer,
936 Some("oxidize_pdf Test Suite".to_string())
937 );
938 assert!(doc.metadata.creation_date.is_some());
939 assert!(doc.metadata.modification_date.is_some());
940 }
941 }
942}