1pub mod bookmark;
6pub mod bookmarks;
7mod content_object;
8pub mod creation_date;
9pub mod creator;
10pub mod custom_data;
11pub mod custom_datas;
12mod image_format;
13mod image_object;
14pub mod ofd_id;
15mod ofd_metadata;
16mod ofd_page;
17pub mod page_size;
18mod path_object;
19pub mod permissions;
20pub mod point;
21pub mod template_page;
22mod text_object;
23pub mod weight;
24
25pub use bookmark::Bookmark;
26pub use bookmarks::Bookmarks;
27pub use content_object::ContentObject;
28pub use creation_date::CreationDate;
29pub use creator::Creator;
30pub use custom_data::CustomData;
31pub use custom_datas::CustomDatas;
32pub use image_format::ImageFormat;
33pub use image_object::ImageObject;
34pub use ofd_id::OfdId;
35pub use ofd_metadata::OfdMetadata;
36pub use ofd_page::OfdPage;
37pub use path_object::PathObject;
38pub use permissions::Permissions;
39pub use point::Point;
40pub use template_page::TemplatePage;
41pub use text_object::TextObject;
42pub use weight::Weight;
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
51 fn test_ofd_metadata_default() {
52 let meta = OfdMetadata::default();
53 assert_eq!(meta.version, "1.0");
54 assert!(meta.title.is_none());
55 assert!(meta.author.is_none());
56 assert!(meta.creator.is_none());
57 assert!(meta.creation_date.is_none());
58 }
59
60 #[test]
61 fn test_ofd_metadata_clone_debug() {
62 let meta = OfdMetadata {
63 title: Some("t".into()),
64 ..Default::default()
65 };
66 let meta2 = meta.clone();
67 assert_eq!(meta2.title.unwrap(), "t");
68 let dbg = format!("{meta:?}");
69 assert!(dbg.contains("OfdMetadata"));
70 }
71
72 #[test]
75 fn test_ofd_page_new() {
76 let page = OfdPage::new(210.0, 297.0);
77 assert!((page.width - 210.0).abs() < f64::EPSILON);
78 assert!((page.height - 297.0).abs() < f64::EPSILON);
79 assert!(page.content.is_empty());
80 }
81
82 #[test]
83 fn test_ofd_page_add_text() {
84 let mut page = OfdPage::new(210.0, 297.0);
85 page.add_text(TextObject::new(10.0, 20.0, "hello"));
86 assert_eq!(page.content.len(), 1);
87 assert!(matches!(&page.content[0], ContentObject::Text(_)));
88 }
89
90 #[test]
91 fn test_ofd_page_add_image() {
92 let mut page = OfdPage::new(210.0, 297.0);
93 page.add_image(ImageObject::jpeg(0.0, 0.0, 10.0, 10.0, vec![0xFF]));
94 assert_eq!(page.content.len(), 1);
95 assert!(matches!(&page.content[0], ContentObject::Image(_)));
96 }
97
98 #[test]
99 fn test_ofd_page_add_path() {
100 let mut page = OfdPage::new(210.0, 297.0);
101 page.add_path(PathObject::hline(0.0, 10.0, 100.0));
102 assert_eq!(page.content.len(), 1);
103 assert!(matches!(&page.content[0], ContentObject::Path(_)));
104 }
105
106 #[test]
107 fn test_ofd_page_mixed_content() {
108 let mut page = OfdPage::new(210.0, 297.0);
109 page.add_text(TextObject::new(0.0, 0.0, "t"));
110 page.add_image(ImageObject::png(0.0, 0.0, 1.0, 1.0, vec![0x89]));
111 page.add_path(PathObject::vline(5.0, 0.0, 10.0));
112 assert_eq!(page.content.len(), 3);
113 }
114
115 #[test]
116 fn test_ofd_page_clone_debug() {
117 let page = OfdPage::new(100.0, 200.0);
118 let page2 = page.clone();
119 assert!((page2.width - 100.0).abs() < f64::EPSILON);
120 let dbg = format!("{page:?}");
121 assert!(dbg.contains("OfdPage"));
122 }
123
124 #[test]
127 fn test_page_size_a4() {
128 assert_eq!(page_size::A4, (210.0, 297.0));
129 }
130
131 #[test]
132 fn test_page_size_a4_landscape() {
133 assert_eq!(page_size::A4_LANDSCAPE, (297.0, 210.0));
134 }
135
136 #[test]
137 fn test_page_size_a3() {
138 assert_eq!(page_size::A3, (297.0, 420.0));
139 }
140
141 #[test]
142 fn test_page_size_letter() {
143 assert_eq!(page_size::LETTER, (215.9, 279.4));
144 }
145
146 #[test]
149 fn test_text_object_new() {
150 let t = TextObject::new(10.0, 20.0, "hello");
151 assert!((t.x - 10.0).abs() < f64::EPSILON);
152 assert!((t.y - 20.0).abs() < f64::EPSILON);
153 assert_eq!(t.text, "hello");
154 assert_eq!(t.font, "SimSun");
155 assert!((t.size - 12.0).abs() < f64::EPSILON);
156 assert_eq!(t.weight, 400);
157 assert!(!t.italic);
158 assert_eq!(t.color, 0);
159 assert!(t.width.is_none());
160 assert!(t.height.is_none());
161 }
162
163 #[test]
164 fn test_text_object_from_string() {
165 let s = String::from("owned");
166 let t = TextObject::new(0.0, 0.0, s);
167 assert_eq!(t.text, "owned");
168 }
169
170 #[test]
171 fn test_text_object_builder_font() {
172 let t = TextObject::new(0.0, 0.0, "x").font("SimHei");
173 assert_eq!(t.font, "SimHei");
174 }
175
176 #[test]
177 fn test_text_object_builder_size() {
178 let t = TextObject::new(0.0, 0.0, "x").size(24.0);
179 assert!((t.size - 24.0).abs() < f64::EPSILON);
180 }
181
182 #[test]
183 fn test_text_object_builder_bold() {
184 let t = TextObject::new(0.0, 0.0, "x").bold();
185 assert_eq!(t.weight, 700);
186 }
187
188 #[test]
189 fn test_text_object_builder_italic() {
190 let t = TextObject::new(0.0, 0.0, "x").italic();
191 assert!(t.italic);
192 }
193
194 #[test]
195 fn test_text_object_builder_color() {
196 let t = TextObject::new(0.0, 0.0, "x").color(0xFF_0000);
197 assert_eq!(t.color, 0xFF_0000);
198 }
199
200 #[test]
201 fn test_text_object_builder_chaining() {
202 let t = TextObject::new(1.0, 2.0, "x")
203 .font("Arial")
204 .size(16.0)
205 .bold()
206 .italic()
207 .color(0x00_FF00);
208 assert_eq!(t.font, "Arial");
209 assert!((t.size - 16.0).abs() < f64::EPSILON);
210 assert_eq!(t.weight, 700);
211 assert!(t.italic);
212 assert_eq!(t.color, 0x00_FF00);
213 }
214
215 #[test]
216 fn test_text_object_clone_debug() {
217 let t = TextObject::new(0.0, 0.0, "x");
218 let t2 = t.clone();
219 assert_eq!(t2.text, "x");
220 let dbg = format!("{t:?}");
221 assert!(dbg.contains("TextObject"));
222 }
223
224 #[test]
227 fn test_image_format_variants() {
228 assert_ne!(ImageFormat::Jpeg, ImageFormat::Png);
229 assert_ne!(ImageFormat::Bmp, ImageFormat::Tiff);
230 assert_eq!(ImageFormat::Jpeg, ImageFormat::Jpeg);
231 }
232
233 #[test]
234 fn test_image_format_clone_copy_debug() {
235 let f = ImageFormat::Png;
236 let f2 = f;
237 assert_eq!(f2, ImageFormat::Png);
238 let dbg = format!("{f:?}");
239 assert!(dbg.contains("Png"));
240 }
241
242 #[test]
245 fn test_image_object_new() {
246 let img = ImageObject::new(10.0, 20.0, 30.0, 40.0, vec![1, 2], ImageFormat::Png);
247 assert!((img.x - 10.0).abs() < f64::EPSILON);
248 assert!((img.y - 20.0).abs() < f64::EPSILON);
249 assert!((img.width - 30.0).abs() < f64::EPSILON);
250 assert!((img.height - 40.0).abs() < f64::EPSILON);
251 assert_eq!(img.data, vec![1, 2]);
252 assert_eq!(img.format, ImageFormat::Png);
253 }
254
255 #[test]
256 fn test_image_object_jpeg() {
257 let img = ImageObject::jpeg(0.0, 0.0, 10.0, 10.0, vec![0xFF]);
258 assert_eq!(img.format, ImageFormat::Jpeg);
259 }
260
261 #[test]
262 fn test_image_object_png() {
263 let img = ImageObject::png(0.0, 0.0, 10.0, 10.0, vec![0x89]);
264 assert_eq!(img.format, ImageFormat::Png);
265 }
266
267 #[test]
268 fn test_image_object_clone_debug() {
269 let img = ImageObject::jpeg(0.0, 0.0, 1.0, 1.0, vec![0]);
270 let img2 = img.clone();
271 assert_eq!(img2.data, vec![0]);
272 let dbg = format!("{img:?}");
273 assert!(dbg.contains("ImageObject"));
274 }
275
276 #[test]
279 fn test_path_object_new() {
280 let p = PathObject::new(5.0, 10.0, "M0 0L10 10");
281 assert!((p.x - 5.0).abs() < f64::EPSILON);
282 assert!((p.y - 10.0).abs() < f64::EPSILON);
283 assert_eq!(p.path_data, "M0 0L10 10");
284 assert_eq!(p.stroke_color, 0);
285 assert!((p.stroke_width - 0.35).abs() < f64::EPSILON);
286 assert!(p.fill_color.is_none());
287 }
288
289 #[test]
290 fn test_path_object_hline() {
291 let p = PathObject::hline(10.0, 20.0, 100.0);
292 assert!((p.x - 10.0).abs() < f64::EPSILON);
293 assert!((p.y - 20.0).abs() < f64::EPSILON);
294 assert!(p.path_data.contains("M10"));
295 assert!(p.path_data.contains("L100"));
296 }
297
298 #[test]
299 fn test_path_object_vline() {
300 let p = PathObject::vline(5.0, 0.0, 50.0);
301 assert!((p.x - 5.0).abs() < f64::EPSILON);
302 assert!(p.path_data.contains("M5"));
303 }
304
305 #[test]
306 fn test_path_object_rect() {
307 let p = PathObject::rect(0.0, 0.0, 100.0, 50.0);
308 assert!(p.path_data.starts_with('M'));
309 assert!(p.path_data.ends_with('Z'));
310 assert!(p.path_data.contains("L100"));
311 }
312
313 #[test]
314 fn test_path_object_builder_stroke_color() {
315 let p = PathObject::new(0.0, 0.0, "M0 0").stroke_color(0xFF_0000);
316 assert_eq!(p.stroke_color, 0xFF_0000);
317 }
318
319 #[test]
320 fn test_path_object_builder_stroke_width() {
321 let p = PathObject::new(0.0, 0.0, "M0 0").stroke_width(1.5);
322 assert!((p.stroke_width - 1.5).abs() < f64::EPSILON);
323 }
324
325 #[test]
326 fn test_path_object_builder_fill_color() {
327 let p = PathObject::new(0.0, 0.0, "M0 0").fill_color(0x00_FF00);
328 assert_eq!(p.fill_color, Some(0x00_FF00));
329 }
330
331 #[test]
332 fn test_path_object_builder_chaining() {
333 let p = PathObject::new(0.0, 0.0, "M0 0")
334 .stroke_color(0xFF)
335 .stroke_width(2.0)
336 .fill_color(0xFF_FF00);
337 assert_eq!(p.stroke_color, 0xFF);
338 assert!((p.stroke_width - 2.0).abs() < f64::EPSILON);
339 assert_eq!(p.fill_color, Some(0xFF_FF00));
340 }
341
342 #[test]
343 fn test_path_object_clone_debug() {
344 let p = PathObject::new(0.0, 0.0, "M0 0");
345 let p2 = p.clone();
346 assert_eq!(p2.path_data, "M0 0");
347 let dbg = format!("{p:?}");
348 assert!(dbg.contains("PathObject"));
349 }
350
351 #[test]
354 fn test_content_object_variants_debug() {
355 let text = ContentObject::Text(TextObject::new(0.0, 0.0, "x"));
356 let img = ContentObject::Image(ImageObject::jpeg(0.0, 0.0, 1.0, 1.0, vec![0]));
357 let path = ContentObject::Path(PathObject::new(0.0, 0.0, "M0 0"));
358 assert!(format!("{text:?}").contains("Text"));
359 assert!(format!("{img:?}").contains("Image"));
360 assert!(format!("{path:?}").contains("Path"));
361 }
362
363 #[test]
366 fn test_image_from_file_png() {
367 let dir = std::env::temp_dir().join("easyofd_img_test");
368 std::fs::create_dir_all(&dir).unwrap();
369 let path = dir.join("test.png");
370 let png: Vec<u8> = vec![0x89, b'P', b'N', b'G', 0x0D, 0x0A, 0x1A, 0x0A];
371 std::fs::write(&path, &png).unwrap();
372
373 let img = ImageObject::from_file(0.0, 0.0, 10.0, 10.0, &path).unwrap();
374 assert_eq!(img.format, ImageFormat::Png);
375 assert!(!img.data.is_empty());
376 let _ = std::fs::remove_file(&path);
377 }
378
379 #[test]
380 fn test_image_from_file_jpg_by_ext() {
381 let dir = std::env::temp_dir().join("easyofd_img_test2");
382 std::fs::create_dir_all(&dir).unwrap();
383 let path = dir.join("test.jpg");
384 std::fs::write(&path, b"not-real-jpg").unwrap();
385
386 let img = ImageObject::from_file(0.0, 0.0, 10.0, 10.0, &path).unwrap();
387 assert_eq!(img.format, ImageFormat::Jpeg);
388 let _ = std::fs::remove_file(&path);
389 }
390}