1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum PdfError {
5 #[error("IO error: {0}")]
6 Io(#[from] std::io::Error),
7
8 #[error("Invalid PDF structure: {0}")]
9 InvalidStructure(String),
10
11 #[error("Invalid object reference: {0}")]
12 InvalidReference(String),
13
14 #[error("Encoding error: {0}")]
15 EncodingError(String),
16
17 #[error("Font error: {0}")]
18 FontError(String),
19
20 #[error("Compression error: {0}")]
21 CompressionError(String),
22
23 #[error("Invalid image: {0}")]
24 InvalidImage(String),
25
26 #[error("Invalid object reference: {0} {1} R")]
27 InvalidObjectReference(u32, u16),
28
29 #[error("Parse error: {0}")]
30 ParseError(String),
31
32 #[error("Invalid page number: {0}")]
33 InvalidPageNumber(u32),
34
35 #[error("Invalid format: {0}")]
36 InvalidFormat(String),
37
38 #[error("Invalid header")]
39 InvalidHeader,
40
41 #[error("Content stream too large: {0} bytes")]
42 ContentStreamTooLarge(usize),
43
44 #[error("Operation cancelled")]
45 OperationCancelled,
46}
47
48pub type Result<T> = std::result::Result<T, PdfError>;
49
50#[derive(Error, Debug)]
52pub enum OxidizePdfError {
53 #[error("IO error: {0}")]
54 Io(#[from] std::io::Error),
55
56 #[error("Parse error: {0}")]
57 ParseError(String),
58
59 #[error("Invalid PDF structure: {0}")]
60 InvalidStructure(String),
61
62 #[error("Encoding error: {0}")]
63 EncodingError(String),
64
65 #[error("Other error: {0}")]
66 Other(String),
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use std::io::{Error as IoError, ErrorKind};
73
74 #[test]
75 fn test_pdf_error_display() {
76 let error = PdfError::InvalidStructure("test message".to_string());
77 assert_eq!(error.to_string(), "Invalid PDF structure: test message");
78 }
79
80 #[test]
81 fn test_pdf_error_debug() {
82 let error = PdfError::InvalidReference("object 1 0".to_string());
83 let debug_str = format!("{:?}", error);
84 assert!(debug_str.contains("InvalidReference"));
85 assert!(debug_str.contains("object 1 0"));
86 }
87
88 #[test]
89 fn test_pdf_error_from_io_error() {
90 let io_error = IoError::new(ErrorKind::NotFound, "file not found");
91 let pdf_error = PdfError::from(io_error);
92
93 match pdf_error {
94 PdfError::Io(ref err) => {
95 assert_eq!(err.kind(), ErrorKind::NotFound);
96 }
97 _ => panic!("Expected IO error variant"),
98 }
99 }
100
101 #[test]
102 fn test_all_pdf_error_variants() {
103 let errors = vec![
104 PdfError::InvalidStructure("structure error".to_string()),
105 PdfError::InvalidObjectReference(1, 0),
106 PdfError::EncodingError("encoding error".to_string()),
107 PdfError::FontError("font error".to_string()),
108 PdfError::CompressionError("compression error".to_string()),
109 PdfError::InvalidImage("image error".to_string()),
110 PdfError::ParseError("parse error".to_string()),
111 PdfError::InvalidPageNumber(999),
112 PdfError::InvalidFormat("format error".to_string()),
113 PdfError::InvalidHeader,
114 PdfError::ContentStreamTooLarge(1024 * 1024),
115 ];
116
117 for error in errors {
119 let error_string = error.to_string();
120 assert!(!error_string.is_empty());
121 }
122 }
123
124 #[test]
125 fn test_oxidize_pdf_error_display() {
126 let error = OxidizePdfError::ParseError("parsing failed".to_string());
127 assert_eq!(error.to_string(), "Parse error: parsing failed");
128 }
129
130 #[test]
131 fn test_oxidize_pdf_error_debug() {
132 let error = OxidizePdfError::InvalidStructure("malformed PDF".to_string());
133 let debug_str = format!("{:?}", error);
134 assert!(debug_str.contains("InvalidStructure"));
135 assert!(debug_str.contains("malformed PDF"));
136 }
137
138 #[test]
139 fn test_oxidize_pdf_error_from_io_error() {
140 let io_error = IoError::new(ErrorKind::PermissionDenied, "access denied");
141 let pdf_error = OxidizePdfError::from(io_error);
142
143 match pdf_error {
144 OxidizePdfError::Io(ref err) => {
145 assert_eq!(err.kind(), ErrorKind::PermissionDenied);
146 }
147 _ => panic!("Expected IO error variant"),
148 }
149 }
150
151 #[test]
152 fn test_all_oxidize_pdf_error_variants() {
153 let errors = vec![
154 OxidizePdfError::ParseError("parse error".to_string()),
155 OxidizePdfError::InvalidStructure("structure error".to_string()),
156 OxidizePdfError::EncodingError("encoding error".to_string()),
157 OxidizePdfError::Other("other error".to_string()),
158 ];
159
160 for error in errors {
162 let error_string = error.to_string();
163 assert!(!error_string.is_empty());
164 assert!(error_string.contains("error"));
165 }
166 }
167
168 #[test]
169 fn test_result_type_ok() {
170 let result: Result<i32> = Ok(42);
171 assert!(result.is_ok());
172 assert_eq!(result.unwrap(), 42);
173 }
174
175 #[test]
176 fn test_result_type_err() {
177 let result: Result<i32> = Err(PdfError::InvalidStructure("test".to_string()));
178 assert!(result.is_err());
179
180 let error = result.unwrap_err();
181 match error {
182 PdfError::InvalidStructure(msg) => assert_eq!(msg, "test"),
183 _ => panic!("Expected InvalidStructure variant"),
184 }
185 }
186
187 #[test]
188 fn test_error_chain_display() {
189 let errors = [
191 (
192 "Invalid PDF structure: corrupted header",
193 PdfError::InvalidStructure("corrupted header".to_string()),
194 ),
195 (
196 "Invalid object reference: 999 0 R",
197 PdfError::InvalidObjectReference(999, 0),
198 ),
199 (
200 "Encoding error: unsupported encoding",
201 PdfError::EncodingError("unsupported encoding".to_string()),
202 ),
203 (
204 "Font error: missing font",
205 PdfError::FontError("missing font".to_string()),
206 ),
207 (
208 "Compression error: deflate failed",
209 PdfError::CompressionError("deflate failed".to_string()),
210 ),
211 (
212 "Invalid image: corrupt JPEG",
213 PdfError::InvalidImage("corrupt JPEG".to_string()),
214 ),
215 ];
216
217 for (expected, error) in errors {
218 assert_eq!(error.to_string(), expected);
219 }
220 }
221
222 #[test]
223 fn test_oxidize_pdf_error_chain_display() {
224 let errors = [
226 (
227 "Parse error: unexpected token",
228 OxidizePdfError::ParseError("unexpected token".to_string()),
229 ),
230 (
231 "Invalid PDF structure: missing xref",
232 OxidizePdfError::InvalidStructure("missing xref".to_string()),
233 ),
234 (
235 "Encoding error: invalid UTF-8",
236 OxidizePdfError::EncodingError("invalid UTF-8".to_string()),
237 ),
238 (
239 "Other error: unknown issue",
240 OxidizePdfError::Other("unknown issue".to_string()),
241 ),
242 ];
243
244 for (expected, error) in errors {
245 assert_eq!(error.to_string(), expected);
246 }
247 }
248
249 #[test]
250 fn test_error_send_sync() {
251 fn assert_send_sync<T: Send + Sync>() {}
253 assert_send_sync::<PdfError>();
254 assert_send_sync::<OxidizePdfError>();
255 }
256
257 #[test]
258 fn test_error_struct_creation() {
259 let errors = vec![
261 PdfError::InvalidStructure("test".to_string()),
262 PdfError::InvalidObjectReference(1, 0),
263 PdfError::EncodingError("encoding".to_string()),
264 PdfError::FontError("font".to_string()),
265 PdfError::CompressionError("compression".to_string()),
266 PdfError::InvalidImage("image".to_string()),
267 PdfError::ParseError("parse".to_string()),
268 PdfError::InvalidPageNumber(1),
269 PdfError::InvalidFormat("format".to_string()),
270 PdfError::InvalidHeader,
271 PdfError::ContentStreamTooLarge(1024),
272 PdfError::OperationCancelled,
273 ];
274
275 for error in errors {
277 let msg = error.to_string();
278 assert!(!msg.is_empty(), "Error message should not be empty");
279
280 match &error {
282 PdfError::OperationCancelled => assert!(msg.contains("cancelled")),
283 PdfError::ContentStreamTooLarge(_) => assert!(msg.contains("too large")),
284 _ => assert!(msg.contains("error") || msg.contains("Invalid")),
285 }
286 }
287 }
288
289 #[test]
290 fn test_oxidize_pdf_error_struct_creation() {
291 let errors = vec![
293 OxidizePdfError::ParseError("test".to_string()),
294 OxidizePdfError::InvalidStructure("structure".to_string()),
295 OxidizePdfError::EncodingError("encoding".to_string()),
296 OxidizePdfError::Other("other".to_string()),
297 ];
298
299 for error in errors {
301 let msg = error.to_string();
302 assert!(msg.contains("error") || msg.contains("Invalid"));
303 }
304 }
305
306 #[test]
307 fn test_error_equality() {
308 let error1 = PdfError::InvalidStructure("test".to_string());
309 let error2 = PdfError::InvalidStructure("test".to_string());
310 let error3 = PdfError::InvalidStructure("different".to_string());
311
312 assert_eq!(error1.to_string(), error2.to_string());
314 assert_ne!(error1.to_string(), error3.to_string());
315 }
316
317 #[test]
318 fn test_io_error_preservation() {
319 let original_io_error = IoError::new(ErrorKind::UnexpectedEof, "sudden EOF");
321 let pdf_error = PdfError::from(original_io_error);
322
323 if let PdfError::Io(io_err) = pdf_error {
324 assert_eq!(io_err.kind(), ErrorKind::UnexpectedEof);
325 assert_eq!(io_err.to_string(), "sudden EOF");
326 } else {
327 panic!("IO error should be preserved as PdfError::Io");
328 }
329 }
330
331 #[test]
332 fn test_oxidize_pdf_error_io_error_preservation() {
333 let original_io_error = IoError::new(ErrorKind::InvalidData, "corrupted data");
335 let oxidize_error = OxidizePdfError::from(original_io_error);
336
337 if let OxidizePdfError::Io(io_err) = oxidize_error {
338 assert_eq!(io_err.kind(), ErrorKind::InvalidData);
339 assert_eq!(io_err.to_string(), "corrupted data");
340 } else {
341 panic!("IO error should be preserved as OxidizePdfError::Io");
342 }
343 }
344}