easyofd_core/attachment/
ct_attachment.rs1use std::fmt::Write;
4
5#[derive(Debug, Clone, PartialEq)]
10pub struct CTAttachment {
11 pub id: String,
13 pub name: String,
15 pub format: Option<String>,
17 pub creation_date: Option<String>,
19 pub size: Option<u64>,
21 pub visible: bool,
23 pub file: Option<String>,
25}
26
27impl CTAttachment {
28 #[must_use]
30 pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
31 Self {
32 id: id.into(),
33 name: name.into(),
34 format: None,
35 creation_date: None,
36 size: None,
37 visible: true,
38 file: None,
39 }
40 }
41
42 #[must_use]
44 pub fn format(mut self, format: impl Into<String>) -> Self {
45 self.format = Some(format.into());
46 self
47 }
48
49 #[must_use]
51 pub fn creation_date(mut self, date: impl Into<String>) -> Self {
52 self.creation_date = Some(date.into());
53 self
54 }
55
56 #[must_use]
58 pub fn size(mut self, size: u64) -> Self {
59 self.size = Some(size);
60 self
61 }
62
63 #[must_use]
65 pub fn visible(mut self, visible: bool) -> Self {
66 self.visible = visible;
67 self
68 }
69
70 #[must_use]
72 pub fn file(mut self, file: impl Into<String>) -> Self {
73 self.file = Some(file.into());
74 self
75 }
76
77 #[must_use]
79 pub fn to_xml_string(&self) -> String {
80 let mut xml = format!(r#"<ofd:Attachment ID="{}" Name="{}""#, self.id, self.name);
81
82 if let Some(ref fmt) = self.format {
83 let _ = write!(xml, r#" Format="{fmt}""#);
84 }
85 if let Some(ref date) = self.creation_date {
86 let _ = write!(xml, r#" CreationDate="{date}""#);
87 }
88 if let Some(sz) = self.size {
89 let _ = write!(xml, r#" Size="{sz}""#);
90 }
91 if !self.visible {
92 xml.push_str(r#" Visible="false""#);
93 }
94 if let Some(ref file) = self.file {
95 let _ = write!(xml, r#" File="{file}""#);
96 }
97
98 xml.push_str(" />");
99 xml
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_ct_attachment_new() {
109 let a = CTAttachment::new("att1", "readme.pdf");
110 assert_eq!(a.id, "att1");
111 assert_eq!(a.name, "readme.pdf");
112 assert!(a.format.is_none());
113 assert!(a.creation_date.is_none());
114 assert!(a.size.is_none());
115 assert!(a.visible);
116 assert!(a.file.is_none());
117 }
118
119 #[test]
120 fn test_ct_attachment_builder() {
121 let a = CTAttachment::new("att2", "data.xlsx")
122 .format("application/vnd.ms-excel")
123 .creation_date("2025-03-15")
124 .size(1024)
125 .visible(false)
126 .file("Attachments/data.xlsx");
127 assert_eq!(a.format.as_deref(), Some("application/vnd.ms-excel"));
128 assert_eq!(a.creation_date.as_deref(), Some("2025-03-15"));
129 assert_eq!(a.size, Some(1024));
130 assert!(!a.visible);
131 assert_eq!(a.file.as_deref(), Some("Attachments/data.xlsx"));
132 }
133
134 #[test]
135 fn test_ct_attachment_to_xml_string_basic() {
136 let a = CTAttachment::new("a1", "test.txt");
137 let xml = a.to_xml_string();
138 assert!(xml.contains(r#"ID="a1""#));
139 assert!(xml.contains(r#"Name="test.txt""#));
140 assert!(xml.contains(" />"));
141 }
142
143 #[test]
144 fn test_ct_attachment_to_xml_string_full() {
145 let a = CTAttachment::new("a2", "img.png")
146 .format("image/png")
147 .creation_date("2025-06-01")
148 .size(2048)
149 .visible(false)
150 .file("Attachments/img.png");
151 let xml = a.to_xml_string();
152 assert!(xml.contains(r#"Format="image/png""#));
153 assert!(xml.contains(r#"CreationDate="2025-06-01""#));
154 assert!(xml.contains(r#"Size="2048""#));
155 assert!(xml.contains(r#"Visible="false""#));
156 assert!(xml.contains(r#"File="Attachments/img.png""#));
157 }
158
159 #[test]
160 fn test_ct_attachment_visible_default_true() {
161 let a = CTAttachment::new("a1", "x.txt");
162 let xml = a.to_xml_string();
163 assert!(!xml.contains("Visible"));
164 }
165
166 #[test]
167 fn test_ct_attachment_clone_debug() {
168 let a = CTAttachment::new("x", "y.txt");
169 let a2 = a.clone();
170 assert_eq!(a2.id, "x");
171 assert!(format!("{a:?}").contains("CTAttachment"));
172 }
173}