1use sup_xml_core::error::XmlError;
10
11#[derive(Debug)]
12pub enum XsltError {
13 InvalidStylesheet(String),
17
18 UnresolvedReference(String),
22
23 Xpath(XmlError),
25
26 Terminated(String),
29}
30
31impl std::fmt::Display for XsltError {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 match self {
34 XsltError::InvalidStylesheet(msg) => write!(f, "invalid stylesheet: {msg}"),
35 XsltError::UnresolvedReference(msg) => write!(f, "unresolved reference: {msg}"),
36 XsltError::Xpath(e) => match (&e.file, e.line, e.column) {
41 (Some(file), Some(line), Some(col)) => {
42 write!(f, "{file}:{line}:{col}: {}", e.message)?;
43 if let Some(ofs) = e.byte_offset {
44 write!(f, " @ byte {ofs}")?;
45 }
46 Ok(())
47 }
48 _ => write!(f, "xpath error: {}", e.message),
49 },
50 XsltError::Terminated(msg) => write!(f, "xsl:message terminate=yes: {msg}"),
51 }
52 }
53}
54
55impl std::error::Error for XsltError {}
56
57impl From<XmlError> for XsltError {
58 fn from(e: XmlError) -> Self { XsltError::Xpath(e) }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use sup_xml_core::error::{ErrorDomain, ErrorLevel};
65
66 #[test]
67 fn display_invalid_stylesheet() {
68 let e = XsltError::InvalidStylesheet("bad <foo>".into());
69 assert_eq!(format!("{e}"), "invalid stylesheet: bad <foo>");
70 }
71
72 #[test]
73 fn display_unresolved_reference() {
74 let e = XsltError::UnresolvedReference("template X".into());
75 assert_eq!(format!("{e}"), "unresolved reference: template X");
76 }
77
78 #[test]
79 fn display_xpath_wraps_inner_message() {
80 let inner = XmlError::new(ErrorDomain::XPath, ErrorLevel::Error, "syntax");
81 let e = XsltError::Xpath(inner);
82 assert_eq!(format!("{e}"), "xpath error: syntax");
83 }
84
85 #[test]
86 fn display_terminated() {
87 let e = XsltError::Terminated("user-requested halt".into());
88 assert_eq!(format!("{e}"), "xsl:message terminate=yes: user-requested halt");
89 }
90
91 #[test]
92 fn from_xml_error_wraps_as_xpath() {
93 let inner = XmlError::new(ErrorDomain::XPath, ErrorLevel::Error, "div by zero");
94 let e: XsltError = inner.into();
95 assert!(matches!(e, XsltError::Xpath(_)));
96 assert_eq!(format!("{e}"), "xpath error: div by zero");
97 }
98
99 #[test]
100 fn implements_std_error_trait() {
101 let e = XsltError::InvalidStylesheet("x".into());
103 let err: &dyn std::error::Error = &e;
104 assert!(err.to_string().contains("invalid stylesheet"));
105 }
106
107 #[test]
108 fn debug_format_works() {
109 let e = XsltError::Terminated("x".into());
112 let s = format!("{e:?}");
113 assert!(s.contains("Terminated"));
114 }
115}