1use hwpforge_foundation::{
25 ApplyPageType, HwpUnit, NumberFormatType, PageNumberPosition, ShowMode, TextDirection,
26};
27use schemars::JsonSchema;
28use serde::{Deserialize, Serialize};
29
30use crate::column::ColumnSettings;
31use crate::page::PageSettings;
32use crate::paragraph::Paragraph;
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
43pub struct Visibility {
44 #[serde(default)]
46 pub hide_first_header: bool,
47 #[serde(default)]
49 pub hide_first_footer: bool,
50 #[serde(default)]
52 pub hide_first_master_page: bool,
53 #[serde(default)]
55 pub hide_first_page_num: bool,
56 #[serde(default)]
58 pub hide_first_empty_line: bool,
59 #[serde(default)]
61 pub show_line_number: bool,
62 #[serde(default)]
64 pub border: ShowMode,
65 #[serde(default)]
67 pub fill: ShowMode,
68}
69
70impl Default for Visibility {
71 fn default() -> Self {
72 Self {
73 hide_first_header: false,
74 hide_first_footer: false,
75 hide_first_master_page: false,
76 hide_first_page_num: false,
77 hide_first_empty_line: false,
78 show_line_number: false,
79 border: ShowMode::ShowAll,
80 fill: ShowMode::ShowAll,
81 }
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
93pub struct LineNumberShape {
94 #[serde(default)]
96 pub restart_type: u8,
97 #[serde(default)]
99 pub count_by: u16,
100 #[serde(default)]
102 pub distance: HwpUnit,
103 #[serde(default)]
105 pub start_number: u32,
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
117pub struct PageBorderFillEntry {
118 pub apply_type: String,
120 #[serde(default = "PageBorderFillEntry::default_border_fill_id")]
122 pub border_fill_id: u32,
123 #[serde(default = "PageBorderFillEntry::default_text_border")]
125 pub text_border: String,
126 #[serde(default)]
128 pub header_inside: bool,
129 #[serde(default)]
131 pub footer_inside: bool,
132 #[serde(default = "PageBorderFillEntry::default_fill_area")]
134 pub fill_area: String,
135 #[serde(default = "PageBorderFillEntry::default_offset")]
137 pub offset: [HwpUnit; 4],
138}
139
140impl PageBorderFillEntry {
141 fn default_border_fill_id() -> u32 {
142 1
143 }
144 fn default_text_border() -> String {
145 "PAPER".to_string()
146 }
147 fn default_fill_area() -> String {
148 "PAPER".to_string()
149 }
150 fn default_offset() -> [HwpUnit; 4] {
151 [
153 HwpUnit::new(1417).unwrap(),
154 HwpUnit::new(1417).unwrap(),
155 HwpUnit::new(1417).unwrap(),
156 HwpUnit::new(1417).unwrap(),
157 ]
158 }
159}
160
161impl Default for PageBorderFillEntry {
162 fn default() -> Self {
163 Self {
164 apply_type: "BOTH".to_string(),
165 border_fill_id: 1,
166 text_border: "PAPER".to_string(),
167 header_inside: false,
168 footer_inside: false,
169 fill_area: "PAPER".to_string(),
170 offset: Self::default_offset(),
171 }
172 }
173}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
183pub struct BeginNum {
184 #[serde(default = "BeginNum::one")]
186 pub page: u32,
187 #[serde(default = "BeginNum::one")]
189 pub footnote: u32,
190 #[serde(default = "BeginNum::one")]
192 pub endnote: u32,
193 #[serde(default = "BeginNum::one")]
195 pub pic: u32,
196 #[serde(default = "BeginNum::one")]
198 pub tbl: u32,
199 #[serde(default = "BeginNum::one")]
201 pub equation: u32,
202}
203
204impl BeginNum {
205 fn one() -> u32 {
206 1
207 }
208}
209
210impl Default for BeginNum {
211 fn default() -> Self {
212 Self { page: 1, footnote: 1, endnote: 1, pic: 1, tbl: 1, equation: 1 }
213 }
214}
215
216#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
228pub struct MasterPage {
229 pub apply_page_type: ApplyPageType,
231 pub paragraphs: Vec<Paragraph>,
233}
234
235impl MasterPage {
236 pub fn new(apply_page_type: ApplyPageType, paragraphs: Vec<Paragraph>) -> Self {
238 Self { apply_page_type, paragraphs }
239 }
240}
241
242impl std::fmt::Display for MasterPage {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 let n = self.paragraphs.len();
245 let word = if n == 1 { "paragraph" } else { "paragraphs" };
246 write!(f, "MasterPage({n} {word}, {:?})", self.apply_page_type)
247 }
248}
249
250#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
275pub struct HeaderFooter {
276 pub paragraphs: Vec<Paragraph>,
278 pub apply_page_type: ApplyPageType,
280}
281
282impl HeaderFooter {
283 pub fn new(paragraphs: Vec<Paragraph>, apply_page_type: ApplyPageType) -> Self {
285 Self { paragraphs, apply_page_type }
286 }
287
288 pub fn all_pages(paragraphs: Vec<Paragraph>) -> Self {
305 Self { paragraphs, apply_page_type: ApplyPageType::Both }
306 }
307
308 #[deprecated(since = "0.2.0", note = "Use `all_pages()` instead")]
310 pub fn both(paragraphs: Vec<Paragraph>) -> Self {
311 Self::all_pages(paragraphs)
312 }
313}
314
315impl std::fmt::Display for HeaderFooter {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 let n = self.paragraphs.len();
318 let word = if n == 1 { "paragraph" } else { "paragraphs" };
319 write!(f, "HeaderFooter({n} {word}, {:?})", self.apply_page_type)
320 }
321}
322
323#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
345pub struct PageNumber {
346 pub position: PageNumberPosition,
348 pub number_format: NumberFormatType,
350 pub decoration: String,
353}
354
355impl PageNumber {
356 pub fn new(position: PageNumberPosition, number_format: NumberFormatType) -> Self {
358 Self { position, number_format, decoration: String::new() }
359 }
360
361 pub fn bottom_center() -> Self {
379 Self {
380 position: PageNumberPosition::BottomCenter,
381 number_format: NumberFormatType::Digit,
382 decoration: String::new(),
383 }
384 }
385
386 pub fn with_decoration(
402 position: PageNumberPosition,
403 number_format: NumberFormatType,
404 decoration: impl Into<String>,
405 ) -> Self {
406 Self { position, number_format, decoration: decoration.into() }
407 }
408
409 #[deprecated(since = "0.2.0", note = "Use `with_decoration()` instead")]
411 pub fn with_side_char(
412 position: PageNumberPosition,
413 number_format: NumberFormatType,
414 side_char: impl Into<String>,
415 ) -> Self {
416 Self::with_decoration(position, number_format, side_char)
417 }
418}
419
420impl std::fmt::Display for PageNumber {
421 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422 write!(f, "PageNumber({:?}, {:?})", self.position, self.number_format)
423 }
424}
425
426#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
447pub struct Section {
448 pub paragraphs: Vec<Paragraph>,
450 pub page_settings: PageSettings,
452 #[serde(default, skip_serializing_if = "Vec::is_empty")]
461 pub headers: Vec<HeaderFooter>,
462 #[serde(default, skip_serializing_if = "Vec::is_empty")]
465 pub footers: Vec<HeaderFooter>,
466 #[serde(default, skip_serializing_if = "Option::is_none")]
468 pub page_number: Option<PageNumber>,
469 #[serde(default, skip_serializing_if = "Option::is_none")]
471 pub column_settings: Option<ColumnSettings>,
472 #[serde(default, skip_serializing_if = "Option::is_none")]
475 pub visibility: Option<Visibility>,
476 #[serde(default, skip_serializing_if = "Option::is_none")]
478 pub line_number_shape: Option<LineNumberShape>,
479 #[serde(default, skip_serializing_if = "Option::is_none")]
481 pub page_border_fills: Option<Vec<PageBorderFillEntry>>,
482 #[serde(default, skip_serializing_if = "Option::is_none")]
485 pub master_pages: Option<Vec<MasterPage>>,
486 #[serde(default, skip_serializing_if = "Option::is_none")]
489 pub begin_num: Option<BeginNum>,
490 #[serde(default)]
493 pub text_direction: TextDirection,
494}
495
496impl Section {
497 pub fn for_each_paragraph_mut<F: FnMut(&mut Paragraph)>(&mut self, mut f: F) {
500 self.walk_paragraphs_mut(&mut f);
501 }
502
503 pub(crate) fn walk_paragraphs_mut(&mut self, f: &mut dyn FnMut(&mut Paragraph)) {
505 for p in &mut self.paragraphs {
506 p.walk_paragraphs_mut(f);
507 }
508 for hf in self.headers.iter_mut().chain(self.footers.iter_mut()) {
509 for p in &mut hf.paragraphs {
510 p.walk_paragraphs_mut(f);
511 }
512 }
513 if let Some(master_pages) = &mut self.master_pages {
514 for mp in master_pages {
515 for p in &mut mp.paragraphs {
516 p.walk_paragraphs_mut(f);
517 }
518 }
519 }
520 }
521
522 pub fn new(page_settings: PageSettings) -> Self {
534 Self {
535 paragraphs: Vec::new(),
536 page_settings,
537 headers: Vec::new(),
538 footers: Vec::new(),
539 page_number: None,
540 column_settings: None,
541 visibility: None,
542 line_number_shape: None,
543 page_border_fills: None,
544 master_pages: None,
545 begin_num: None,
546 text_direction: TextDirection::Horizontal,
547 }
548 }
549
550 pub fn with_paragraphs(paragraphs: Vec<Paragraph>, page_settings: PageSettings) -> Self {
567 Self {
568 paragraphs,
569 page_settings,
570 headers: Vec::new(),
571 footers: Vec::new(),
572 page_number: None,
573 column_settings: None,
574 visibility: None,
575 line_number_shape: None,
576 page_border_fills: None,
577 master_pages: None,
578 begin_num: None,
579 text_direction: TextDirection::Horizontal,
580 }
581 }
582
583 pub fn with_text_direction(mut self, dir: TextDirection) -> Self {
597 self.text_direction = dir;
598 self
599 }
600
601 pub fn add_paragraph(&mut self, paragraph: Paragraph) {
603 self.paragraphs.push(paragraph);
604 }
605
606 pub fn paragraph_count(&self) -> usize {
608 self.paragraphs.len()
609 }
610
611 pub fn is_empty(&self) -> bool {
613 self.paragraphs.is_empty()
614 }
615
616 pub fn content_counts(&self) -> ContentCounts {
633 let mut tables: usize = 0;
634 let mut images: usize = 0;
635 let mut charts: usize = 0;
636
637 for para in &self.paragraphs {
638 for run in ¶.runs {
639 match &run.content {
640 crate::RunContent::Table(_) => tables += 1,
641 crate::RunContent::Image(_) => images += 1,
642 crate::RunContent::Control(c) => {
643 if matches!(**c, crate::control::Control::Chart { .. }) {
644 charts += 1;
645 }
646 }
647 _ => {}
648 }
649 }
650 }
651
652 ContentCounts { tables, images, charts }
653 }
654}
655
656#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
658pub struct ContentCounts {
659 pub tables: usize,
661 pub images: usize,
663 pub charts: usize,
665}
666
667impl std::fmt::Display for Section {
668 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
669 let n = self.paragraphs.len();
670 let word = if n == 1 { "paragraph" } else { "paragraphs" };
671 write!(f, "Section({n} {word})")
672 }
673}
674
675#[cfg(test)]
676mod tests {
677 use super::*;
678 use crate::run::Run;
679 use hwpforge_foundation::{
680 ApplyPageType, CharShapeIndex, NumberFormatType, PageNumberPosition, ParaShapeIndex,
681 };
682
683 fn simple_paragraph() -> Paragraph {
684 Paragraph::with_runs(
685 vec![Run::text("text", CharShapeIndex::new(0))],
686 ParaShapeIndex::new(0),
687 )
688 }
689
690 #[test]
691 fn new_is_empty() {
692 let section = Section::new(PageSettings::a4());
693 assert!(section.is_empty());
694 assert_eq!(section.paragraph_count(), 0);
695 }
696
697 #[test]
698 fn with_paragraphs() {
699 let section = Section::with_paragraphs(
700 vec![simple_paragraph(), simple_paragraph()],
701 PageSettings::a4(),
702 );
703 assert_eq!(section.paragraph_count(), 2);
704 assert!(!section.is_empty());
705 }
706
707 #[test]
708 fn add_paragraph() {
709 let mut section = Section::new(PageSettings::a4());
710 section.add_paragraph(simple_paragraph());
711 section.add_paragraph(simple_paragraph());
712 assert_eq!(section.paragraph_count(), 2);
713 }
714
715 #[test]
716 fn page_settings_preserved() {
717 let section = Section::new(PageSettings::letter());
718 assert_eq!(section.page_settings, PageSettings::letter());
719 }
720
721 #[test]
722 fn display_singular() {
723 let section = Section::with_paragraphs(vec![simple_paragraph()], PageSettings::a4());
724 assert_eq!(section.to_string(), "Section(1 paragraph)");
725 }
726
727 #[test]
728 fn display_plural() {
729 let section = Section::with_paragraphs(
730 vec![simple_paragraph(), simple_paragraph()],
731 PageSettings::a4(),
732 );
733 assert_eq!(section.to_string(), "Section(2 paragraphs)");
734 }
735
736 #[test]
737 fn equality() {
738 let a = Section::with_paragraphs(vec![simple_paragraph()], PageSettings::a4());
739 let b = Section::with_paragraphs(vec![simple_paragraph()], PageSettings::a4());
740 assert_eq!(a, b);
741 }
742
743 #[test]
744 fn inequality_different_page_settings() {
745 let a = Section::new(PageSettings::a4());
746 let b = Section::new(PageSettings::letter());
747 assert_ne!(a, b);
748 }
749
750 #[test]
751 fn clone_independence() {
752 let section = Section::with_paragraphs(vec![simple_paragraph()], PageSettings::a4());
753 let mut cloned = section.clone();
754 cloned.add_paragraph(simple_paragraph());
755 assert_eq!(section.paragraph_count(), 1);
756 assert_eq!(cloned.paragraph_count(), 2);
757 }
758
759 #[test]
760 fn serde_roundtrip() {
761 let section = Section::with_paragraphs(vec![simple_paragraph()], PageSettings::a4());
762 let json = serde_json::to_string(§ion).unwrap();
763 let back: Section = serde_json::from_str(&json).unwrap();
764 assert_eq!(section, back);
765 }
766
767 #[test]
768 fn serde_empty_section() {
769 let section = Section::new(PageSettings::a4());
770 let json = serde_json::to_string(§ion).unwrap();
771 let back: Section = serde_json::from_str(&json).unwrap();
772 assert_eq!(section, back);
773 }
774
775 #[test]
776 fn serde_letter_page() {
777 let section = Section::new(PageSettings::letter());
778 let json = serde_json::to_string(§ion).unwrap();
779 let back: Section = serde_json::from_str(&json).unwrap();
780 assert_eq!(section, back);
781 }
782
783 #[test]
788 fn header_footer_new() {
789 let hf =
790 HeaderFooter::new(vec![Paragraph::new(ParaShapeIndex::new(0))], ApplyPageType::Both);
791 assert_eq!(hf.paragraphs.len(), 1);
792 assert_eq!(hf.apply_page_type, ApplyPageType::Both);
793 }
794
795 #[test]
796 fn header_footer_even_odd() {
797 let even = HeaderFooter::new(vec![], ApplyPageType::Even);
798 let odd = HeaderFooter::new(vec![], ApplyPageType::Odd);
799 assert_eq!(even.apply_page_type, ApplyPageType::Even);
800 assert_eq!(odd.apply_page_type, ApplyPageType::Odd);
801 assert_ne!(even, odd);
802 }
803
804 #[test]
805 fn header_footer_display() {
806 let hf =
807 HeaderFooter::new(vec![Paragraph::new(ParaShapeIndex::new(0))], ApplyPageType::Both);
808 let s = hf.to_string();
809 assert!(s.contains("1 paragraph"), "display: {s}");
810 assert!(s.contains("Both"), "display: {s}");
811 }
812
813 #[test]
814 fn header_footer_serde_roundtrip() {
815 let hf = HeaderFooter::new(
816 vec![Paragraph::with_runs(
817 vec![Run::text("Header text", CharShapeIndex::new(0))],
818 ParaShapeIndex::new(0),
819 )],
820 ApplyPageType::Both,
821 );
822 let json = serde_json::to_string(&hf).unwrap();
823 let back: HeaderFooter = serde_json::from_str(&json).unwrap();
824 assert_eq!(hf, back);
825 }
826
827 #[test]
828 fn header_footer_clone_independence() {
829 let hf =
830 HeaderFooter::new(vec![Paragraph::new(ParaShapeIndex::new(0))], ApplyPageType::Both);
831 let mut cloned = hf.clone();
832 cloned.paragraphs.push(Paragraph::new(ParaShapeIndex::new(1)));
833 assert_eq!(hf.paragraphs.len(), 1);
834 assert_eq!(cloned.paragraphs.len(), 2);
835 }
836
837 #[test]
842 fn page_number_new() {
843 let pn = PageNumber::new(PageNumberPosition::BottomCenter, NumberFormatType::Digit);
844 assert_eq!(pn.position, PageNumberPosition::BottomCenter);
845 assert_eq!(pn.number_format, NumberFormatType::Digit);
846 assert!(pn.decoration.is_empty());
847 }
848
849 #[test]
850 fn page_number_with_decoration() {
851 let pn = PageNumber::with_decoration(
852 PageNumberPosition::BottomCenter,
853 NumberFormatType::RomanCapital,
854 "- ",
855 );
856 assert_eq!(pn.decoration, "- ");
857 assert_eq!(pn.number_format, NumberFormatType::RomanCapital);
858 }
859
860 #[test]
861 #[allow(deprecated)]
862 fn page_number_with_side_char_deprecated() {
863 let pn = PageNumber::with_side_char(
864 PageNumberPosition::BottomCenter,
865 NumberFormatType::Digit,
866 "- ",
867 );
868 assert_eq!(pn.decoration, "- ");
869 }
870
871 #[test]
872 fn page_number_display() {
873 let pn = PageNumber::new(PageNumberPosition::TopCenter, NumberFormatType::Digit);
874 let s = pn.to_string();
875 assert!(s.contains("TopCenter"), "display: {s}");
876 assert!(s.contains("Digit"), "display: {s}");
877 }
878
879 #[test]
880 fn page_number_serde_roundtrip() {
881 let pn = PageNumber::with_decoration(
882 PageNumberPosition::BottomCenter,
883 NumberFormatType::CircledDigit,
884 "< ",
885 );
886 let json = serde_json::to_string(&pn).unwrap();
887 let back: PageNumber = serde_json::from_str(&json).unwrap();
888 assert_eq!(pn, back);
889 }
890
891 #[test]
892 fn page_number_equality() {
893 let a = PageNumber::new(PageNumberPosition::BottomCenter, NumberFormatType::Digit);
894 let b = PageNumber::new(PageNumberPosition::BottomCenter, NumberFormatType::Digit);
895 assert_eq!(a, b);
896 }
897
898 #[test]
899 fn page_number_inequality() {
900 let a = PageNumber::new(PageNumberPosition::BottomCenter, NumberFormatType::Digit);
901 let b = PageNumber::new(PageNumberPosition::TopCenter, NumberFormatType::Digit);
902 assert_ne!(a, b);
903 }
904
905 #[test]
910 fn section_new_has_empty_header_footer_vecs() {
911 let section = Section::new(PageSettings::a4());
912 assert!(section.headers.is_empty());
913 assert!(section.footers.is_empty());
914 assert!(section.page_number.is_none());
915 assert!(section.column_settings.is_none());
916 }
917
918 #[test]
919 fn section_with_header_footer() {
920 let mut section = Section::new(PageSettings::a4());
921 section.headers.push(HeaderFooter::new(
922 vec![Paragraph::with_runs(
923 vec![Run::text("Header", CharShapeIndex::new(0))],
924 ParaShapeIndex::new(0),
925 )],
926 ApplyPageType::Both,
927 ));
928 section.footers.push(HeaderFooter::new(
929 vec![Paragraph::with_runs(
930 vec![Run::text("Footer", CharShapeIndex::new(0))],
931 ParaShapeIndex::new(0),
932 )],
933 ApplyPageType::Both,
934 ));
935 assert_eq!(section.headers.len(), 1);
936 assert_eq!(section.footers.len(), 1);
937 }
938
939 #[test]
940 fn section_with_page_number() {
941 let mut section = Section::new(PageSettings::a4());
942 section.page_number =
943 Some(PageNumber::new(PageNumberPosition::BottomCenter, NumberFormatType::Digit));
944 assert!(section.page_number.is_some());
945 }
946
947 #[test]
948 fn section_serde_with_optional_fields() {
949 let mut section = Section::new(PageSettings::a4());
950 section.headers.push(HeaderFooter::new(vec![], ApplyPageType::Both));
951 section.page_number =
952 Some(PageNumber::new(PageNumberPosition::BottomCenter, NumberFormatType::Digit));
953 let json = serde_json::to_string(§ion).unwrap();
954 let back: Section = serde_json::from_str(&json).unwrap();
955 assert_eq!(section, back);
956 }
957
958 #[test]
959 fn section_serde_none_fields_skipped() {
960 let section = Section::new(PageSettings::a4());
961 let json = serde_json::to_string(§ion).unwrap();
962 assert!(!json.contains("\"header\""));
965 assert!(!json.contains("\"footer\""));
966 assert!(!json.contains("\"page_number\""));
967 assert!(!json.contains("\"column_settings\""));
968 let back: Section = serde_json::from_str(&json).unwrap();
969 assert_eq!(section, back);
970 }
971
972 #[test]
977 fn header_footer_all_pages_apply_page_type() {
978 let hf = HeaderFooter::all_pages(vec![Paragraph::new(ParaShapeIndex::new(0))]);
979 assert_eq!(hf.apply_page_type, ApplyPageType::Both);
980 }
981
982 #[test]
983 fn header_footer_all_pages_preserves_paragraphs() {
984 let paras = vec![simple_paragraph(), simple_paragraph()];
985 let hf = HeaderFooter::all_pages(paras);
986 assert_eq!(hf.paragraphs.len(), 2);
987 }
988
989 #[test]
990 fn header_footer_all_pages_empty_paragraphs() {
991 let hf = HeaderFooter::all_pages(vec![]);
992 assert_eq!(hf.apply_page_type, ApplyPageType::Both);
993 assert!(hf.paragraphs.is_empty());
994 }
995
996 #[test]
997 #[allow(deprecated)]
998 fn header_footer_both_deprecated_alias() {
999 let hf = HeaderFooter::both(vec![Paragraph::new(ParaShapeIndex::new(0))]);
1000 assert_eq!(hf.apply_page_type, ApplyPageType::Both);
1001 }
1002
1003 #[test]
1008 fn page_number_bottom_center_position() {
1009 let pn = PageNumber::bottom_center();
1010 assert_eq!(pn.position, PageNumberPosition::BottomCenter);
1011 }
1012
1013 #[test]
1014 fn page_number_bottom_center_format() {
1015 let pn = PageNumber::bottom_center();
1016 assert_eq!(pn.number_format, NumberFormatType::Digit);
1017 }
1018
1019 #[test]
1020 fn page_number_bottom_center_no_decoration() {
1021 let pn = PageNumber::bottom_center();
1022 assert!(pn.decoration.is_empty());
1023 }
1024
1025 #[test]
1026 fn page_number_bottom_center_equals_explicit() {
1027 let shortcut = PageNumber::bottom_center();
1028 let explicit = PageNumber::new(PageNumberPosition::BottomCenter, NumberFormatType::Digit);
1029 assert_eq!(shortcut, explicit);
1030 }
1031
1032 #[test]
1033 fn section_backward_compat_deserialize() {
1034 let a4 = PageSettings::a4();
1036 let json = serde_json::to_string(&Section::with_paragraphs(vec![], a4)).unwrap();
1037 let section: Section = serde_json::from_str(&json).unwrap();
1038 assert!(section.headers.is_empty());
1039 assert!(section.footers.is_empty());
1040 assert!(section.page_number.is_none());
1041 }
1042
1043 #[test]
1044 fn all_pages_equals_new_with_both() {
1045 let paras = vec![simple_paragraph()];
1046 let from_all_pages = HeaderFooter::all_pages(paras.clone());
1047 let from_new = HeaderFooter::new(paras, ApplyPageType::Both);
1048 assert_eq!(from_all_pages, from_new);
1049 }
1050}