oxidize_pdf/templates/
error.rs1use std::fmt;
2
3#[derive(Debug, Clone)]
5pub enum TemplateError {
6 VariableNotFound(String),
8 InvalidPlaceholder(String),
10 CircularReference(String),
12 InvalidVariableName(String),
14 ParseError(String),
16 RenderError(String),
18}
19
20impl fmt::Display for TemplateError {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 Self::VariableNotFound(var) => {
24 write!(f, "Variable '{}' not found in template context", var)
25 }
26 Self::InvalidPlaceholder(placeholder) => {
27 write!(f, "Invalid placeholder syntax: '{}'", placeholder)
28 }
29 Self::CircularReference(var) => {
30 write!(f, "Circular reference detected for variable '{}'", var)
31 }
32 Self::InvalidVariableName(name) => {
33 write!(f, "Invalid variable name: '{}' (must contain only alphanumeric characters, underscores, and dots)", name)
34 }
35 Self::ParseError(msg) => {
36 write!(f, "Template parsing error: {}", msg)
37 }
38 Self::RenderError(msg) => {
39 write!(f, "Template rendering error: {}", msg)
40 }
41 }
42 }
43}
44
45impl std::error::Error for TemplateError {}
46
47pub type TemplateResult<T> = std::result::Result<T, TemplateError>;
49
50impl From<regex::Error> for TemplateError {
51 fn from(err: regex::Error) -> Self {
52 TemplateError::ParseError(format!("Regex error: {}", err))
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_error_display() {
62 let err = TemplateError::VariableNotFound("name".to_string());
63 assert_eq!(
64 format!("{}", err),
65 "Variable 'name' not found in template context"
66 );
67
68 let err = TemplateError::InvalidPlaceholder("{{invalid}}".to_string());
69 assert!(format!("{}", err).contains("Invalid placeholder syntax"));
70 }
71
72 #[test]
73 fn test_error_debug() {
74 let err = TemplateError::CircularReference("var1".to_string());
75 assert!(format!("{:?}", err).contains("CircularReference"));
76 }
77
78 #[test]
79 fn test_variable_not_found_display() {
80 let err = TemplateError::VariableNotFound("username".to_string());
81 let msg = format!("{}", err);
82 assert!(msg.contains("username"));
83 assert!(msg.contains("not found"));
84 }
85
86 #[test]
87 fn test_invalid_placeholder_display() {
88 let err = TemplateError::InvalidPlaceholder("{{bad syntax".to_string());
89 let msg = format!("{}", err);
90 assert!(msg.contains("Invalid placeholder syntax"));
91 assert!(msg.contains("{{bad syntax"));
92 }
93
94 #[test]
95 fn test_circular_reference_display() {
96 let err = TemplateError::CircularReference("var_a".to_string());
97 let msg = format!("{}", err);
98 assert!(msg.contains("Circular reference"));
99 assert!(msg.contains("var_a"));
100 }
101
102 #[test]
103 fn test_invalid_variable_name_display() {
104 let err = TemplateError::InvalidVariableName("123invalid".to_string());
105 let msg = format!("{}", err);
106 assert!(msg.contains("Invalid variable name"));
107 assert!(msg.contains("123invalid"));
108 assert!(msg.contains("alphanumeric"));
109 }
110
111 #[test]
112 fn test_parse_error_display() {
113 let err = TemplateError::ParseError("Unexpected token".to_string());
114 let msg = format!("{}", err);
115 assert!(msg.contains("Template parsing error"));
116 assert!(msg.contains("Unexpected token"));
117 }
118
119 #[test]
120 fn test_render_error_display() {
121 let err = TemplateError::RenderError("Failed to render".to_string());
122 let msg = format!("{}", err);
123 assert!(msg.contains("Template rendering error"));
124 assert!(msg.contains("Failed to render"));
125 }
126
127 #[test]
128 fn test_error_clone() {
129 let err1 = TemplateError::VariableNotFound("test".to_string());
130 let err2 = err1.clone();
131 assert_eq!(format!("{}", err1), format!("{}", err2));
132 }
133
134 #[test]
135 fn test_from_regex_error() {
136 let regex_result = regex::Regex::new("[invalid(");
138 if let Err(regex_err) = regex_result {
139 let template_err: TemplateError = regex_err.into();
140 let msg = format!("{}", template_err);
141 assert!(msg.contains("Regex error"));
142 }
143 }
144
145 #[test]
146 fn test_template_result_ok() {
147 fn returns_ok() -> TemplateResult<i32> {
148 Ok(42)
149 }
150 assert_eq!(returns_ok().unwrap(), 42);
151 }
152
153 #[test]
154 fn test_template_result_err() {
155 fn returns_err() -> TemplateResult<i32> {
156 Err(TemplateError::ParseError("test".to_string()))
157 }
158 assert!(returns_err().is_err());
159 }
160
161 #[test]
162 fn test_error_is_std_error() {
163 fn assert_error<T: std::error::Error>(_: &T) {}
165 let err = TemplateError::ParseError("test".to_string());
166 assert_error(&err);
167 }
168
169 #[test]
170 fn test_all_variants_debug() {
171 let variants: Vec<TemplateError> = vec![
173 TemplateError::VariableNotFound("v".to_string()),
174 TemplateError::InvalidPlaceholder("p".to_string()),
175 TemplateError::CircularReference("c".to_string()),
176 TemplateError::InvalidVariableName("n".to_string()),
177 TemplateError::ParseError("pe".to_string()),
178 TemplateError::RenderError("re".to_string()),
179 ];
180
181 for err in variants {
182 let debug_str = format!("{:?}", err);
183 assert!(!debug_str.is_empty());
184 }
185 }
186
187 #[test]
188 fn test_empty_string_errors() {
189 let err = TemplateError::VariableNotFound(String::new());
191 assert!(format!("{}", err).contains("''"));
192
193 let err = TemplateError::ParseError(String::new());
194 assert!(format!("{}", err).contains("Template parsing error:"));
195 }
196
197 #[test]
198 fn test_unicode_in_errors() {
199 let err = TemplateError::VariableNotFound("变量名".to_string());
200 assert!(format!("{}", err).contains("变量名"));
201
202 let err = TemplateError::RenderError("🎯 Error".to_string());
203 assert!(format!("{}", err).contains("🎯"));
204 }
205}