1use thiserror::Error;
8
9#[derive(Debug, Error)]
17pub enum DocError {
18 #[error("I/O error: {0}")]
22 Io(#[from] std::io::Error),
23
24 #[error("ZIP error: {0}")]
28 Zip(String),
29
30 #[error("Format error: {0}")]
34 Format(String),
35
36 #[error("Template error at placeholder '{placeholder}': {message}")]
40 Template {
41 placeholder: String,
43 message: String,
45 },
46
47 #[error("Conversion error: field '{field}', value '{value}': {message}")]
51 Conversion {
52 field: String,
54 value: String,
56 message: String,
58 },
59
60 #[error("Unsupported operation: {0}")]
64 Unsupported(String),
65
66 #[error("Document error: {0}")]
70 Document(String),
71}
72
73pub type Result<T> = std::result::Result<T, DocError>;
75
76impl From<zip::result::ZipError> for DocError {
77 fn from(e: zip::result::ZipError) -> Self {
78 Self::Zip(e.to_string())
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn error_display_io() {
88 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "missing");
89 let err = DocError::Io(io_err);
90 assert!(format!("{err}").contains("I/O error"));
91 }
92
93 #[test]
94 fn error_display_zip() {
95 let err = DocError::Zip("corrupt".into());
96 assert!(format!("{err}").contains("ZIP error"));
97 }
98
99 #[test]
100 fn error_display_format() {
101 let err = DocError::Format("bad xml".into());
102 assert!(format!("{err}").contains("Format error"));
103 }
104
105 #[test]
106 fn error_display_template() {
107 let err = DocError::Template {
108 placeholder: "name".into(),
109 message: "not found".into(),
110 };
111 let s = format!("{err}");
112 assert!(s.contains("name"));
113 assert!(s.contains("not found"));
114 }
115
116 #[test]
117 fn error_display_conversion() {
118 let err = DocError::Conversion {
119 field: "age".into(),
120 value: "abc".into(),
121 message: "not a number".into(),
122 };
123 let s = format!("{err}");
124 assert!(s.contains("age"));
125 assert!(s.contains("abc"));
126 }
127
128 #[test]
129 fn error_display_unsupported() {
130 let err = DocError::Unsupported("macro".into());
131 assert!(format!("{err}").contains("Unsupported operation"));
132 }
133
134 #[test]
135 fn error_display_document() {
136 let err = DocError::Document("corrupted".into());
137 assert!(format!("{err}").contains("Document error"));
138 }
139
140 #[test]
141 fn error_from_zip_error() {
142 let zip_err = zip::result::ZipError::FileNotFound;
143 let err: DocError = zip_err.into();
144 assert!(matches!(err, DocError::Zip(_)));
145 }
146
147 #[test]
148 fn error_from_io_error() {
149 let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "denied");
150 let err: DocError = io_err.into();
151 assert!(matches!(err, DocError::Io(_)));
152 }
153
154 #[test]
155 fn error_debug() {
156 let err = DocError::Document("test".into());
157 let dbg = format!("{err:?}");
158 assert!(dbg.contains("Document"));
159 }
160}